-
2020-04-13 14:30:40
立即学习:https://edu.csdn.net/course/play/27126/360149?utm_source=blogtoedu
简历上写一句:理解Java虚拟机结构,并有内存调优的经验,别拘泥于体系结构,大致描述即可,但应立即深入到内存话题
- 在回答好集合方面的问题再说一句,用好集合后,我们要及时clear掉,从而提升内存性能
- 在回答好IO和数据库JDBC方面的问题后再说一句,用好以后,我们会在finally从句里释放对象,从而提升内存性能
更多相关内容 -
高考作文引出话题:我们为什么称赞儿子怀疑邻居.doc
2022-03-07 21:14:19高考作文引出话题:我们为什么称赞儿子怀疑邻居.doc -
由一桩盗窃案引出的话题.docx
2021-11-22 16:08:44由一桩盗窃案引出的话题.docx -
高考话题引出多个两难困境作文.doc
2022-03-07 19:10:44高考话题引出多个两难困境作文.doc -
学习笔记(21):Java面试Offer直通车-通过String,引出内存管理的话题
2020-08-26 13:03:04【Java面试宝典】 1、68讲视频课,500道大厂Java常见面试题+100个Java面试技巧与答题公式+10万字核心知识解析+授课老师1对1面试指导+无限次回放 2、这门课程基于胡书敏老师8年Java面试经验,调研近百家互联网公司...立即学习:https://edu.csdn.net/course/play/27126/357995?utm_source=blogtoedu
equal 比较值, ==比较地址
new 出来的是变量
常量可以共享内存,变量不会
常量连接还是常量,变量参与是变量
常量和变量存储的位置不同
- new出来的变量放在堆里
- 常量放在常量池,相同的值可以共享内存
- 用final定义的是常量,放常量池
- JVM内存优化,是针对堆区
String 是不可变类
- String 引用指向的内存值是不可变的
- 并不是更改内存中的值,而是指向新的内存空间
- 由此会产生大量的内存空间
String角度可以引出虚拟就调优说辞
- 值相同的常量会共享内存,尽量用常量
- new的对象放堆区
- 尽量避免对String以及其它不可变类的频繁操作
- 如要频繁对String操作,可用 StringBuilder或StringBuffer
-
<div id="app"></div> <script> window.onload = function () { let startTime = +new Date(); let oApp = document.getElementById('app'...
-
五、英语六级高级句型使用技巧精选.doc
2020-04-01 20:40:06英语六级高级句型使用技巧精选 -
心得体会:编程是一种新的学习方式.pdf
2020-12-23 00:30:31心得体会编程是一种新的学习方式 从 2020 年开始日本小学阶段将把编程纳入必修课...我们经常看到一些小孩在 Ipad 上触触画画但要具体看他在玩什么是一个 怎样的过程 这里引出一个话题 我们希望孩子被电脑程序左右 还是 -
心得体会:编程是一种新的学习方式.docx
2020-11-24 05:52:02心得体会编程是一种新的学习方式 从2020年开始日本小学阶段将把...我们经常看到一些小孩在Ipad上触触画画但要具体看他在玩什么是一个 怎样的过程这里引出一个话题我们希望孩子被电脑程序左右 还是由孩子自己左 右电脑程 -
深入研究ReentrantLock(重入锁)之引出话题篇
2013-10-15 10:30:51一直以来都想好好研究下ReentrantLock,她的独到魅力令我屡试不爽,无奈网上实在是没有太多的资料可以参考,于是自己开始深入研究它的内部实现机制,经过数天的研究,终于有点心得体会升华了,记录之…… ...一直以来都想好好研究下ReentrantLock,她的独到魅力令我屡试不爽,无奈网上实在是没有太多的资料可以参考,于是自己开始深入研究它的内部实现机制,经过数天的研究,终于有点心得体会升华了,记录之……
synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。
1.某个线程在等待一个锁的控制权的这段时间需要中断
2.需要分开处理一些wait-notify,ReentrantLock里面的Condition应用,能够控制notify哪个线程
3.具有公平锁功能,每个到来的线程都将排队等候
下面细细道来……
先说第一种情况,ReentrantLock的lock机制有2种,忽略中断锁和响应中断锁,这给我们带来了很大的灵活性。比如:如果A、B2个 线程去竞争锁,A线程得到了锁,B线程等待,但是A线程这个时候实在有太多事情要处理,就是一直不返回,B线程可能就会等不及了,想中断自己,不再等待这 个锁了,转而处理其他事情。这个时候ReentrantLock就提供了2种机制,第一,B线程中断自己(或者别的线程中断它),但是 ReentrantLock不去响应,继续让B线程等待,你再怎么中断,我全当耳边风(synchronized原语就是如此);第二,B线程中断自己 (或者别的线程中断它),ReentrantLock处理了这个中断,并且不再等待这个锁的到来,完全放弃。(如果你没有了解java的中断机制,请参考 下相关资料,再回头看这篇文章,80%的人根本没有真正理解什么是java的中断,呵呵)
下面的Buffer类,就是synchronized实现
public class Buffer implements IBuffer { private Object lock; public Buffer() { this.lock = this; } @Override public void write() { // TODO Auto-generated method stub synchronized(lock){ long startTime = System.currentTimeMillis(); System.out.println("开始往这个buff写入数据....."); for(;;){ if(System.currentTimeMillis()-startTime>=Integer.MAX_VALUE){ break; } } System.out.println("终于写完了"); } } @Override public void read() throws InterruptedException { // TODO Auto-generated method stub synchronized(lock){ System.out.println("从这个buff读取数据"); } } }
我们定义一个读程序、定义一个写程序
public class Writer extends Thread { private IBuffer buff; public Writer(IBuffer buff){ this.buff = buff; } public void run(){ buff.write(); } } class Reader extends Thread{ private IBuffer buff; public Reader(IBuffer buff){ this.buff = buff; } public void run(){ try { buff.read();//可以收到中断的异常,从而有效退出 } catch (InterruptedException e) { System.out.println("我不读了" ); } System.out.println("读结束" ); } }
下面是测试main方法
public class TestRenntrantLock { public static boolean useSynchronized = true; public static void main(String [] args){ IBuffer buff = null; if(useSynchronized){ buff =new Buffer(); } else{ buff = new BufferInterruptibly(); } final Writer write = new Writer(buff); final Reader reader =new Reader(buff); write.start(); reader.start(); new Thread (new Runnable() { public void run(){ long startTime =System.currentTimeMillis(); for(;;){ if(System.currentTimeMillis()-startTime>9000){ System.out.println("不等了,尝试中断"); reader.interrupt(); break; } } } } ).start(); } }
测试发现,执行后显示
开始往这个buff写入数据..... 不等了,尝试中断
发现尝试中断的时候,并没有中断,因为线程得不到锁,就一直等待,因为写线程耗时非常长,几乎是无穷尽的,肯定超过一个小时(暂且,粗估),ReentrantLock给了一种机制让我们来响应中断,让“读”能伸能屈,勇敢放弃 对这个锁的等待。我们来改写Buffer这个类,就叫BufferInterruptibly吧,可中断缓存。
import java.util.concurrent.locks.ReentrantLock; public class BufferInterruptibly implements IBuffer { private ReentrantLock lock = new ReentrantLock();//参数默认false,不公平锁 @Override public void write() { // TODO Auto-generated method stub lock.lock(); try { long startTime = System.currentTimeMillis(); System.out.println("开始往这个buff写入数据"); for(;;){ if(System.currentTimeMillis()-startTime > Integer.MAX_VALUE){ break; } } System.out.println("终于写完了"); } finally{ lock.unlock(); } } @Override public void read() throws InterruptedException { // TODO Auto-generated method stub lock.lockInterruptibly(); //可以响应中断 try { System.out.println("从这个buffer读取数据"); }finally { lock.unlock(); } } }
ReentrantLock实现了,reader类中断自己,然后用户可以根据自己的需要进行异常操作。
-
面试热点话题:聊聊MySQL索引“B+Tree”的前世今生,
2021-05-30 18:41:59这里就引出了数据库索引的最左前缀原理。 在我们开发中经常会遇到明明这个字段建了联合索引,但是SQL查询该字段时却不会使用索引的问题。比如索引abc_index:(a,b,c)是a,b,c三个字段的联合索引,下列sql执行时都...小伙伴想精准查找自己想看的MySQL文章?喏 → MySQL江湖路 | 专栏目录
面试一说起MySQL,我们总会提到B+Tree索引,你对B+Tree索引了解么,它有哪些特性,优势在哪里,和B树有什么不同?
外行看热闹,内行看门道。对于这类热门知识和问题,希望同学们都能做到心中有数。
好了,今天我们一起来复习复习MySQL索引的前世今生。一起聊聊索引的那些事儿。
目录
一、什么是索引?
在关系数据库中,索引是一种单独的、物理的对数据库表中一列或多列的值进行排序的一种存储结构,它是某个表中一列或若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单。索引的作用相当于图书的目录,可以根据目录中的页码快速找到所需的内容。
当表中有大量记录时,若要对表进行查询,第一种搜索信息方式是全表搜索,是将所有记录一一取出,和查询条件进行一一对比,然后返回满足条件的记录,这样做会消耗大量数据库系统时间,并造成大量磁盘I/O操作;第二种就是在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索引中的ROWID(相当于页码)快速找到表中对应的记录。
MySQL5.5以后InnoDB储引擎使用的索引数据结构主要用:
B+Tree
;本篇文章带大家以B+Tree前世今生为主线来聊一聊;Mark:
B+Tree可以对<,<=,=,>,>=,BETWEEN,IN,以及不以通配符开始的LIKE使用索引。(MySQL5.5后)
这些事实或许会颠覆你的一些认知,比如在你读过的其他文章或书中。以上这些都属于“范围查询”,都是不走索引的!
没错,早先5.5以前优化器是不会选择通过索引搜索的,优化器认为这样取出的行多与全表扫描的行,因为还要回表查一次嘛,可能会涉及I/O的行数更多,被优化器放弃。
经过算法(B+Tree)优化后,支持对部分范围类型的扫描(得利与B+Tree数据结构的有序性)。该做法同时也违反了最左前缀原则,导致范围查询后的条件无法用到联合索引,我们在后面详细说明。
二、索引的优缺点
1、优点
- 索引大大减小了服务器需要扫描的数据量
- 索引可以帮助服务器避免排序和临时表
- 索引可以将随机I/O变成顺序I/O
2、缺点
- 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存索引文件。
- 建立索引会占用磁盘空间的索引文件。一般情况这个问题不算严重,但如果你在一个大表上创建了多种组合索引,且伴随大量数据量插入,索引文件大小也会快速膨胀。
- 如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
- 对于非常小的表,大部分情况下简单的全表扫描更高效;
因此应该只为最经常查询和最经常排序的数据列建立索引。(MySQL里同一个数据表里的索引总数限制为16个)
数据库存在的意义之一就是是解决数据存储和快速查找的。那么数据库的数据存在哪?没错,是磁盘,磁盘的优点是啥?便宜!缺点呢?相比内存访问速度慢。
那么你知道MySQL索引主要使用的数据结构么?
B+树!你脱口而出。
那 B+树 是什么样的数据结构?MySQL索引又是为什么选择了B+树呢?
其实最终选用 B+树 是经历了漫长的演化:
二叉排序树 → 二叉平衡树 → B-Tree(B树) → B+Tree(B+树)
有小伙伴问我“B树 跟 B-树有什么区别”?这里普及一下,MySQL数据结构只有B-Tree(B树)和B+Tree(B+树),多只是读法不同罢了,“B-Tree” 一般统称为B树,你叫他B-树也行~~
还有小伙伴提到的红黑树,是编程语言中的存储结构,不是MySQL的;如Java的HashMap就是用的链表加红黑树。
好了,今天就带着大家一起看一下演化成 B+树 的过程吧。
三、B+Tree索引的前世今生
1、二叉排序树
理解B+树之前,简单说一下二叉排序树,对于一个节点,它的左子树的孩子节点值都要小于它本身,它的右子树的孩子节点值都要大于它本身,如果所有节点都满足这个条件,那么它就是二叉排序树。(此处可以串一下二分查找的知识点)
上图是一颗二叉排序树,你可以尝试利用它的特点,体验查找9的过程:
- 9比10小,去它的左子树(节点3)查找
- 9比3大,去节点3的右子树(节点4)查找
- 9比4大,去节点4的右子树(节点9)查找
- 节点9与9相等,查找成功
一共比较了4次,那你有没有想过上述结构的优化方式?
2、AVL树 (自平衡二叉查找树)
上图是AVL树,节点个数和值均和二叉排序树一摸一样
再来看一下查找9的过程:
- 9比4大,去它的右子树查找
- 9比10小,去它的左子树查找
- 节点9与9相等,查找成功
一共比较了3次,同样的数据量比二叉排序树少了一次,为什么呢?因为AVL树高度要比二叉排序树小,高度越高意味着比较的次数越多;不要小看优化的这一次,假如是200w条数据,比较次数会明显地不同。
你可以想象一下一棵 100 万节点的平衡二叉树,树高 20。一次查询可能需要访问 20 个数据块。在机械硬盘时代,从磁盘随机读一个数据块需要 10 ms 左右的寻址时间。也就是说,对于一个 100 万行的表,如果使用二叉树来存储,单独访问一个行可能需要 20 个 10 ms 的时间,这个查询可真够慢的!
3、B树(Balanced Tree)多路平衡查找树 多叉的
B树是一种多路自平衡搜索树,它类似普通的二叉树,但是B书允许每个节点有更多的子节点。B树示意图如下:
值得注意的是,B树的非叶子节点和叶子结点的data数据都是分开存储的,那么针对范围查询、排序等常用特性就很不友好了。
B树的特点:
- 所有键值分布在整个树中
- 任何关键字出现且只出现在一个节点中
- 搜索有可能在非叶子节点结束
- 在关键字全集内做一次查找,性能逼近二分查找算法
为了提升效率,要尽量减少磁盘I/O的次数。实际过程中,磁盘并不是每次严格按需读取,而是每次都会预读。
磁盘读取完需要的数据后,会按顺序再多读一部分数据到内存中,这样做的理论依据是计算机科学中注明的局部性原理:
- 由于磁盘顺序读取的效率很高(不需要寻址时间,只需很少的旋转时间),因此对于具有局部性的程序来说,预读可以提高I/O效率.预读的长度一般为页(page)的整倍数。
- MySQL(默认使用InnoDB引擎),将记录按照页的方式进行管理,每页大小默认为16K(可以修改)。
B-Tree借助计算机磁盘预读机制:
每次新建节点的时候,都是申请一个页的空间,所以每查找一个节点只需要一次I/O;因为实际应用当中,节点深度会很少,所以查找效率很高.
那么最终版的 B+树 是如何做的呢?
4、B+ Tree (B+树是B树的变体,也是一种多路搜索树)
从图中也可以看到,B+树与B树的不同在于:
- 所有关键字存储在叶子节点,非叶子节点不存储真正的data,从而可以快速定位到叶子结点。
- 为所有叶子节点增加了一个链指针,
意味着所有的值都是按顺序存储的,并且每一个叶子页到根的距离相同,很适合查找范围数据。说明支持范围查询和天然排序。
因此,B+Tree可以对<,<=,=,>,>=,BETWEEN,IN,以及不以通配符开始的LIKE使用索引。且如果用到了该索引,排序功能的消耗大大减少。
B+树的优点:
比较的次数均衡,减少了I/O次数,提高了查找速度,查找也更稳定。
- B+树的磁盘读写代价更低
- B+树的查询效率更加稳定
要知道的是,你每次创建表,系统会为你自动创建一个基于ID的聚集索引(上述B+树),存储全部数据;你每次增加索引,数据库就会为你创建一个附加索引(上述B+树),索引选取的字段个数就是每个节点存储数据索引的个数,注意该索引并不存储全部数据。
四、为什么MySQL索引选择了 B+树 而不是 B树?
- B+树更适合外部存储(一般指磁盘存储),由于内节点(非叶子节点)不存储data,所以一个节点可以存储更多的内节点,每个节点能索引的范围更大更精确。也就是说使用B+树单次磁盘I/O的信息量相比较B树更大,I/O效率更高。
- mysql是关系型数据库,经常会按照区间来访问某个索引列,B+树的叶子节点间按顺序建立了链指针,加强了区间访问性,所以B+树对索引列上的区间范围查询很友好。而B树每个节点的key和data在一起,无法进行区间查找。
五、你应该知道的索引相关知识点
1、回表查询
比如你创建了name, age索引 name_age_index,查询数据时使用了
select * from table where name ='陈哈哈' and age = 26;
由于附加索引中只有name 和 age,因此命中索引后,数据库还必须回去聚集索引中查找其他数据,这就是回表,这也是你背的那条:少用select * 的原因。
2、索引覆盖
结合回表会更好理解,比如上述name_age_index索引,有查询
select name, age from table where name ='陈哈哈' and age = 26;
此时select的字段name,age在索引name_age_index中都能获取到,所以不需要回表,满足索引覆盖,直接返回索引中的数据,效率高。是DBA同学优化时的首选优化方式。
3、最左前缀原则
B+树的节点存储索引顺序是从左向右存储,在匹配的时候自然也要满足从左向右匹配;通常我们在建立联合索引的时候,也就是对多个字段建立索引,相信建立过索引的同学们会发现,无论是Oracle还是 MySQL 都会让我们选择索引的顺序,比如我们想在a,b,c三个字段上建立一个联合索引,我们可以选择自己想要的优先级,a、b、c,或者是b、a、c 或者是c、a、b等顺序。 为什么数据库会让我们选择字段的顺序呢?不都是三个字段的联合索引么?这里就引出了数据库索引的最左前缀原理。
在我们开发中经常会遇到明明这个字段建了联合索引,但是SQL查询该字段时却不会使用索引的问题。比如索引abc_index:(a,b,c)是a,b,c三个字段的联合索引,下列sql执行时都无法命中索引abc_index的;
select * from table where c = '1'; select * from table where b ='1' and c ='2';
以下三种情况却会走索引:
select * from table where a = '1'; select * from table where a = '1' and b = '2'; select * from table where a = '1' and b = '2' and c='3';
从上面两个例子大家是否阔以看出点眉目?
是的,索引abc_index:(a,b,c),只会在(a)、(a,b)、(a,b,c) 三种类型的查询中使用。其实这里说的有一点歧义,其实(a,c)也会走,但是只走a字段索引,不会走c字段。
另外还有一个特殊情况说明下,下面这种类型的也只会有 a与b 走索引,c不会走。
select * from table where a = '1' and b > '2' and c='3';
像上面这种类型的sql语句,在a、b走完索引后,c已经是无序了,所以c就没法走索引,优化器会认为还不如全表扫描c字段来的快。
最左前缀:顾名思义,就是最左优先,上例中我们创建了a_b_c多列索引,相当于创建了(a)单列索引,(a,b)组合索引以及(a,b,c)组合索引。
因此,在创建多列索引时,要根据业务需求,where子句中使用最频繁的一列放在最左边。
4、索引下推优化
还是索引name_age_index,有如下sql
select * from table where name like '陈%' and age > 26;
该语句有两种执行可能:
- 命中name_age_index联合索引,查询所有满足name以"陈"开头的数据, 然后回表查询所有满足的行。
- 命中name_age_index联合索引,查询所有满足name以"陈"开头的数据,然后顺便筛出age>20的索引,再回表查询全行数据。
显然第2种方式回表查询的行数较少,I/O次数也会减少,这就是索引下推。所以不是所有like都不会命中索引。
好了,多了就不说了,我劝你耗子尾汁,但推荐你关注我,因为我会让你在快乐中学会很多东西!
MySQL系列文章汇总与《MySQL江湖路 | 专栏目录》
往期热门MySQL系列文章
: -
(转)深入研究ReentrantLock(重入锁)之引出话题篇
2011-10-27 16:44:36synchronized原语和ReentrantLock在一般情况下没有什么区别,但是在非常复杂的同步应用中,请考虑使用ReentrantLock,特别是遇到下面2种需求的时候。 1.某个线程在等待一个锁的控制权的这段时间需要中断 ... -
面试话题讨论题_十大非常非常重要的话题需要讨论
2020-05-15 09:55:52面试话题讨论题 有些事情非常非常非常非常重要。 例如John Cleese 。 对于空白也是如此: 空格脱落 是。 仅23小时即可获得1080点Reddit Karma积分(非常需要!)。 这比我们曾经错误地想到的关于Java和SQL... -
Android系统篇之—-Android中的run-as命令引出升降权限的安全问题(Linux中的setuid和setgid)
2020-02-29 19:33:50今天继续开始我们今天的话题:run-as命令,在上周的开发中,遇到一个问题,就是在使用run-as命令的时候出现了一个错误,不过当时因为工作进度的问题,这问题就搁浅没有解决,用了其他一个曲线救国的方式去解决的。... -
《让你少奋斗10年的工作经验》引出的思考
2016-06-21 15:55:56这篇文章是单纯的在阅读了《让你少奋斗10年的工作经验》一文后,引出一个思考:技术工程师除了技术,我们是否还需要分配更多的精力在对自身的综合能力的提升上,或者说对自身理想的追求上(追求理想的人会追求自身的... -
[团队管理]结对编程引出的话题——企业管理与程序员规划的对话(修改总结稿)
2006-12-12 21:54:00要知道,悠悠之口,甚于防川,如果不防,对于任何企业和团队的管理者来说都是不可能的,怎么样才是最好的解决方式,大禹治水,疏通代替其父亲一直采用的堵,反而达到了真正解决问题的效果。 我一直采用得都是疏导... -
对《让测试团队慢慢死去!》的辩论
2021-03-23 11:44:10让我们先由2个问题引出今天的话题,第一,为什么选择做测试?第二,做测试的发展又如何? 哈哈,n久前就有人跟我说这个文章了,说实话,一直懒得看,今天有时间,咱也搞个辩论,直接copy过来,红色的是个人意见。 ... -
聊天,如何制造话题
2013-01-09 22:09:08晓晴的聪明之处就在于,她想到了一本书总会引出许多与书相关的话题。即使阿意拿着书只是做做样子,对书或对某一个话题不感兴趣,那么围绕书所引发的许多社会生活方面的话题,他总有感兴趣的吧,因此他们的初次谈话... -
详细版需求分析课程.ppt
2020-04-17 07:49:09了解顾客需要 最新文档 * 了解顾客需要 什么是客户的需要 如何了解客户的需要 询问 聆听 最新文档 * 寒喧与提问 主动与客户寒喧 通过寒喧的方式,创造... 最新文档 * 提问的目的 获取信息 引出话题给出谈话方向 建立起 -
关于我不聪明的证据,以及由此引出的话题(草稿)
2010-04-19 02:28:00(一) 我办事没谱,常遭人非议。没办法,这是事实,我只得低头承认。是是是,您说得对,我考虑不周,我笨。 猫拉完屎之后,第一件事就是找沙子将大便掩盖起来。所以我多次承认自己笨拙之后,也会找借口辩解辩解。... -
大数据下的机器学习算法综述
2021-03-10 21:50:27本文主要对当前用于处理大数据的机器学习算法的研究现状进行了分析和总结,此外,并行是处理大数据的主流方法,因此还单独对一些并行算法进行了介绍,并引出了大数据环境下机器学习研究所面临的问题,最后指出了... -
APT对传统反病毒技术的威胁和我们的应对尝试
2021-03-02 10:20:26APT(AdvancedPersistentThreat,高级持续性威胁)是我们目前非常感兴趣...像一切其他事物一样,安全事件的要素必然也包括:时间、地点、“人物”等等,这就引出了我们今天要讨论的话题:试想在APT时代的时间、地点和人 -
由项目需求中引出的思考,Promise链式调用如何防抖
2019-03-17 22:26:01由此引出今天讨论的话题,如何实现当Promise链未获取最终结果前,只有最后一次点击能够操作DOM改变页面。 P.S.由于实际工程比较复杂,http请求被封装在其他的模块中,所以在这里不考虑通过abort来终止请求以达到更... -
ApacheSpark内存管理详解
2021-03-01 18:22:30本文旨在梳理出Spark内存管理的脉络,抛砖引玉,引出读者对这个话题的深入探讨。本文中阐述的原理基于Spark2.1版本,阅读本文需要读者有一定的Spark和Java基础,了解RDD、Shuffle、JVM等相关概念。 在执行Spark的... -
详解python 内存优化
2020-12-17 02:32:43围绕类的话题,说是说不完的,仅在特殊方法,除了我们在前面遇到过的 __init__(),__new__(),__str__() 等之外还有很多。虽然它们只是在某些特殊的场景中才会用到,但是学会它们却可以成为你熟悉这门语言路上的铺路...