本文转载自微信公众号《粥下雪》,作者帅小凡凡。转载本文请联系粥夏雪公众号。还是那句话,不管你是初级、中级、高级,甚至是高级,不开玩笑,面试前一定要写八股文,因为你不能保证你遇到的面试官就是因为你位置。而跟你谈项目、架构、源码,我们能做的就是做好准备。反正我觉得object的八字散文应该就是这些了,有兴趣就去看看。对象八面体目录,看你哪里漏了,什么都看!equals和==有什么区别?说说你对hashCode和equals方法的理解?说说hashCode的作用?告诉我哈希冲突或冲突?clone方法什么是浅拷贝?如何实现浅拷贝?什么是深拷贝?为什么要在同步代码块中使用wait?为什么waitnotifynotifyAll定义在Object类中,而sleep定义在Thread类中?wait属于Object对象,调用Thread.wait会怎样?说说notify和notifyAll的区别?notifyAll之后,所有线程都会重新抢占锁。抢占失败怎么办?说说finalize()的作用?Java类加载过程是怎样的?Class.forName()和ClassLoader.loadClass有什么区别?equals之间没有区别。test1会直接报空指针异常。如果你仔细想想,null.equals看起来不像是不是很奇怪?空指针怎么会有方法呢?已知字面量放在equals中,未知参数放在equals后面,避免出现空指针。编程新手很容易出现这种异常。我看过的代码就是这样实现的。说实话,做过很多次了,不止是编程新人,有两三年工作经验的都会做这个。equlas和==的区别?equals方法比较的是字符串内容是否相等,而==比较的是对象地址。首先,Java中的数据类型可以分为两种,一种是基本数据类型,也称为原始数据类型,如byte、short、char、int、long、float、double、boolean、它们之间比较,应用double等号(==),比较它们的值。另一种是复合数据类型,包括类。他们用(==)比较的时候,比较的是他们在内存中的存储地址。因此,除非它们是同一个新对象,它们比较的结果为真,否则比较的结果为假。JAVA中的所有类都是继承自基类Object,在Object的基类中定义了一个equals方法。这个方法的初始行为是比较对象的内存地址,但是在一些类库中,这个方法被覆盖了,比如String、Integer、Date。在这些类中,equals有自己的实现,不再是比较类在堆内存中的存储地址。《在日常开发中的意义:》如果我没记错的话,我经常思考在Java中是用equals还是==来进行比较。谈谈对hashCode和equals方法的理解?如果两个对象的equals方法相等,则它们的hashCode必须相同;如果两个对象的hashCode相同,则它们的equals()方法不一定相等。如果两个对象的hashCode()返回值相等,则不能判断两个对象相等,但是如果两个对象的hashCode()返回值不相等,则可以判断为这两个对象不能相等。因为判断两个对象是否相等,会先判断hashCode,如果hashCode相等,再判断equals,保证对象一定是相同的。说说hashCode的作用?hashCode的作用其实就是在hash结构存储中提高查找效率。equals的实现会对对象的所有成员一一进行判断,从效率上来说是比较慢的。hashCode不同。hashCode是根据所有成员生成一个值,然后比较两个值,所以效率更高。等到hashCode相同,再调用equals判断,因为两个对象的hashCode相同,并不一定说明这两个对象是相同的,仍然存在hash冲突。谈论哈希冲突或碰撞?对象Hash的前提是实现了equals()和hashCode()方法,那么HashCode()的作用就是保证对象返回一个唯一的hash值,但是当两个对象的计算值都一样,这次发生了碰撞。那么如何解决hash冲突呢?开放式寻址法其实就是从上一个hash开始取值冲突,再hash,线性检测再hash:当发生冲突时,依次检查表中的下一个单元,直到找到一个空单元格或翻遍整张桌子。二次检测再哈希:当发生冲突时,对表的左右进行跳转检测,更加灵活。伪随机检测和re-hashing:具体实现是建立一个伪随机数生成器(如i=(i+p)%m),给出一个随机数作为起点。Rehashing方法当hash地址Hi=RH1(key)发生冲突时,重新计算Hi=RH2(key)...,直到冲突不再发生。这种方法不太容易聚类,但会增加计算时间。该方法的基本思想是将散列地址为i的所有元素组成一个称为同义词链的单链表,将单链表的头指针存放在散列的第i个单元中表,因此查找、插入和删除大多是在同义词链中完成的。链地址法适用于频繁的插入和删除。好像HashMap用的是链地址法。插入时会根据key的hash值计算出对应的数组下标。计算方式为index=hashcode%table.length,当下标上已经有元素时,则形成链表,将插入的元素放在末尾。如果下标上面没有元素,那么元素会直接放在这个位置。查询时会先根据key的hash值计算出对应的下标,然后在对应的位置查找。如果下标上的元素很多,那么就会在这个链表上查找,直到找到对应的Elements。普通溢出区的建立将哈希表分为基本表和溢出表两部分。所有与基本表冲突的元素都将填充到溢出表中。《在日常开发中的意义:》容器在日常开发中用的比较多,有时候需要重写equals和hashCode,了解一下很有用。另外,有时候两个对象明明是不同的,但是同样的问题却被误判了,最后找到了lombok注解@Data的原因。不懂equals和hashCode的原理,真的是找不着凶手。别着急,自然要知道@Data其实包括重写hashCode和euqals。clone方法每次问这个问题,大部分人回答2,小部分人回答1。全错,正确答案直接报错。为什么?因为clone方法是Object的protect方法,需要子类显式重写clone方法,实现Cloneable接口。这是一个规则。什么是浅拷贝?对于数据类型为基本数据类型的成员变量,浅拷贝会直接传值,即将属性值拷贝到一个新的对象中。因为是两份不同的数据,修改一个对象的成员变量值不会影响另一个对象复制的数据。对于数据类型为引用数据类型的成员变量,例如成员变量为数组、某个类的对象等,那么浅拷贝会进行引用传递,即只复制引用值(内存address)的成员变量一份给新主题。因为实际上两个对象的成员变量都指向同一个实例。在这种情况下,修改一个对象中的成员变量会影响另一个对象中成员变量的值。如何实现浅拷贝?通过copy构造方法实现浅拷贝没什么好说的;浅拷贝是通过重写clone()方法来实现的:Object类是类结构的根类,其中一个方法是protectedObject“clone”()这个方法就是浅拷贝。有了这个浅拷贝模板,我们就可以通过调用clone()方法来实现一个对象的浅拷贝。但是需要注意:1、Object类虽然有这个方法,但是这个方法是protected的(protected修饰的),所以我们不能直接使用。2、使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException。针对这两点,我们的解决方案是重写类中的clone()方法,使用clone方法,通过super.clone()调用Object类中原有的clone方法。什么是深拷贝?对于深拷贝,不仅需要复制对象所有基本数据类型的成员变量值,还需要为引用数据类型的所有成员变量申请存储空间,并复制被引用数据类型对象的每个成员变量引用,直到该对象可访问的所有对象;也就是说对象的深拷贝需要拷贝整个对象图;简单来说,深拷贝是为引用数据类型的成员变量的对象图中的所有对象开辟内存空间进行分配;而浅拷贝只传递地址点,新对象不为引用数据类型创建内存空间。如何实现深拷贝?通过重写clone方法实现深拷贝和重写clone方法实现浅拷贝是一样的。只需要在对象图的每一层为每个对象实现Cloneable接口并重写clone方法,最后在重写的最顶层类的clone方法中调用所有的clone方法即可实现深拷贝。通过对象序列化实现深拷贝。一个对象序列化成字节序列后,默认会序列化该对象的整个对象图,然后再通过反序列化完美实现深拷贝。》在日常开发中的意义:复制这个知识点还是很重要的。在企业开发中,克隆对象如果不考虑对象的深度,分分钟要命。sleep,wait,notify,notifyAll使用wait,notify实现生产者和消费者模式publicclassConsumeAndProviderDesign{privatestaticintsize=10000;publicstaticvoidmain(String[]args){ConsumeAndProviderDesigndesign=newConsumeAndProviderDesign();design.init();}privatevoidinit(){Containercontainer=newContainer();//productionnewThread(()->{try{for(inti=1;i<=size;i++){container.add();}}catch(InterruptedExceptione){e.printStackTrace();}}).start();//消费newThread(()->{try{for(inti=1;i<=size;i++){container.remove();}}catch(InterruptedExceptione){e.printStackTrace();}}).start();}classContainer{privateList
