文章目录

  • 一、==与equals()区别
  • 二、hashcode与equals
  • 三、为什么重写equals时必须重写hashCode方法
  • 四、链表与数组区别
  • 五、抽象类与接口区别
  • 六、String、StringBuffer、StringBuilder



一、==与equals()区别

  • 1、定义不同
    equals()是Java中的一个方法;==在Java中只是运算符号
  • 2、比较对象不同
    equals():对于引用数据类型的判断,两个数据内容是否相等,比如两个字符串,两个具体的对象; == 判断基本数据类型是否相等,相比较的是数值是否相等,相等返回true,不相等返回false。如果比较的是引用类型来, 则比较的是对象地址值是否相等。
  • 3、运行速度不同
    == 运行速度比equals()快,因为==只是比较引用。

二、hashcode与equals

  • hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。(hashmap底层对应的是一个数组)
  • 散列算法按照hashcode把记录放在合适的位置。在查找一个记录,首先通过hashcode快速定位位置,然后通过equals进行比较是否相等,如果hashcode没找到则不equals,元素不存于哈希表;即便找到hashcode也要进行equals判断。

三、为什么重写equals时必须重写hashCode方法

  • 一旦重写了equals方法,就一定要重写hashCode方法。如果一个类没有重写equals(Object obj)方法,则等价于通过==比较两个对象,即比较的是对象在内存中的空间地址是否相等;如果重写了equals(Object obj)方法,则根据重写的方法内容去比较相等,返回true则相等,false则不相等。
  • equals方法注释中的大致意思是:当我们将equals方法重写后有必要将hashCode方法也重写,这样做才能保证不违背hashCode方法中“相同对象必须有相同哈希值”的约定。
  • hashCode方法注释中列了个列表,列表中有三条注释,当前需要理解的大致意思如下:
    一个对象多次调用它的hashCode方法,应当返回相同的integer(哈希值);
    两个对象如果通过equals方法判定为相等,那么就应当返回相同integer。
    两个地址值不相等的对象调用hashCode方法不要求返回不相等的integer,但是要求拥有两个不相等integer的对象必须是不同对象。

    图中存在两种独立的情况:
  • 相同的对象必然导致相同的哈希值;
  • 不同的哈希值必然是由不同对象导致的;

因此, equals方法与hashCode方法根本就是配套使用的。对于任何一个对象,不论是使用继承自Object的equals方法还是重写equals方法。hashCode方法实际上必须要完成的一件事情就是,为该equals方法认定为相同的对象返回相同的哈希值。如果只重写equals方法没有重写hashCode方法,就会导致``equals`认定相同的对象却拥有不同的哈希值。

四、链表与数组区别

  • 插入、删除、访问

Java equals和hashcode java equals和hashcode区别_散列表


Java equals和hashcode java equals和hashcode区别_哈希算法_02

五、抽象类与接口区别

除了在语法上的区别(在上一篇文章大概讲过一些),还有在语义上的区别。

  • 抽象类描述的是抽象的概念,比如动物,哺乳动物,植物,食物,这些在我们脑子里都有了一个概念。那么面对这种抽象的对象,而我们人类已经有了概念的,就用抽象类。加入要用接口实现,你定义一个动物接口,哈哈,着实有点别扭。
  • 接口描述的是某些事物之间共同具有的某些特征,比如flyable(会飞的),描述这一类东西都会飞,飞机会飞,鸟会飞等,描述的是这些事物的特征。

六、String、StringBuffer、StringBuilder

1、String

  • String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。我们来看一下这张对String操作时内存变化的图:
  • 我们可以看到,初始String值为“hello”,然后在这个字符串后面加上新的字符串“world”,这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了“hello world”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。为了应对经常性的字符串相关的操作,就需要使用Java提供的其他两个操作字符串的类——StringBuffer类和StringBuild类来对此种变化字符串进行处理。
    2、StringBuilder 与 StringBuffer 原理
  • 当声明一个StringBuilder变量的时候,sb会指向堆中的一块空间,这里面有两个属性,一个是Value,底层对应的是一个数组,Count指的是数组里面有多少长度被占用,比如图片中数组长度是19,但是它占用的就是一部分。
    我们此时可以发现一个问题,当数组中存放数据存满了的时候,该怎么办??其实这时数据就会扩容,开辟一个新的,长度更长的数组,然后将Value从指向老的中断变为指向新的value,把原先老的内容拷贝到新的数组中
    以上是StringBuilder 和 StringBuffer 的底层原理。

3、StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类

Java equals和hashcode java equals和hashcode区别_数组_03

  • StringBuilder前面修饰都没有Synchronized
  • StringBuffer前面修饰都有Synchronized(Synchronized前面文章介绍过,翻一下,还有Lock)