Java中的==和equals
1.如果比较对象是值变量:只用==
2.如果比较对象是引用型变量:
==:比较两个引用是不是指向同一个对象实例。
equals:
首先Object类中equals的实现是直接调用了==操作。
一个自定义类继承自Object且没有重写equals方法,那么其equals操作也是与Object类一样,仅仅是直接调用==操作。
如果一个类重写过equals方法(或者继承自一个重写过equals方法的类),那么效果与==操作不同
检查两个引用型变量是否属于同一个Class:instanceof
System.out.println((obj1 instanceof Student) && (obj2 instanceof Student))
API里的类大部分都重写了equals方法。例如String类
1>String类型的比较:
==:比较两个str是否是指向同一个对象实例。
equals:比较两个str中的内容是否相同
对String的比较来说,还存在public String intern()方法。
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。
它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
1 String a = new String( " ab " );
2 String b = new String( " ab " ); 3 String c = " ab " ; 4 String d = " a " + " b " ; 5 String e = " b " ; 6 String f = " a " + e; 8 System.out.println(b.intern() == a); 9 System.out.println(b.intern() == c); 10 System.out.println(b.intern() == d); 11 System.out.println(b.intern() == f); 12 System.out.println(b.intern() == a.intern());
运行结果:false true true false true
由运行结果可以看出来,b.intern() == a和b.intern() == c可知 采用new 创建的字符串对象不进入字符串池, 字符串相加的时候,都是静态字符串的结果会添加到字符串池,如果其中含有变量(如f中的e)则不会进入字符串池中。 在定义变量的时候赋值,如果赋值的是静态的字符串,就会执行进入字符串缓冲池的操作,如果池中含有该字符串,则返回引用。
2>数据类型封装类的比较
Java为每一个简单数据类型提供了一个封装类,每个基本数据类型可以封装成对象类型。 除int(Integer)和char(Character),其余类型首字母大写即成封装类类型名。double (Double), float(Float),long(Long), short(Short),byte(Byte),boolean(Boolean). 以int和Integer为例说明 Java中int和Integer区别如下: 1.int是基本的数据类型,默认值可以为0;Integer是int的封装类,默认值为null; 2.int和Integer都可以表示某一个数值,但int和Integer不能够互用,因为他们两种不同的数据类型; int a1=1; int a2=1; Integer b1 =new Integer (1); Integer b2 =new Integer (1); Answer: a1==a2 这个是成立的,很简单,都知道 a1==b1 这个是不成立的.表达式的值为 false ,它们是不同的数据类型(在jdk1.5以上版本中为true) b1==b2 这个也是不成立的.表达式的值为 false,虽然是相同的数据类型,但是它们是两个对象,==比较的是2个对象的地址,它们的地址是不相等的,内容相等都是1; b1.equals(b2)==true 这个是成立的,表达式的值为 true. 相同数据类型,两个对象,地址不同,内容相同, quals比较的是2个对象的内容,所以成立。 (a.equals(b),因为equals比较的是两个对象,所以a,b都不能为基本数据类型,否则会出编译错误。)(在jdk1.5以上版本中,b可以为基本数据类型,a不可以) 同理,其它的封装类和基本类型也是这样 在jdk1.5以上的版本中,基本类型和封装类能自动转化,与String类型的对象和字符串常量类似。 Integer i1 = 123; Integer i2 = 123; int i = 123; Integer i3 = new Integer(123); Integer i4 = new Integer(123); System.out.println("i1 == i2 = "+(i1 == i2)); System.out.println("i1.equals(i2) = "+(i1.equals(i2))); System.out.println(); System.out.println("i3 == i4 = "+(i3 == i4)); System.out.println("i3.equals(i4) = "+(i3.equals(i4))); System.out.println(); System.out.println("i2 == i4 = "+(i2 == i4)); System.out.println("i2.equals(i4) = "+(i2.equals(i4))); System.out.println(); System.out.println("i == i2 = "+(i == i2)); System.out.println("i1.equals(i) = "+(i1.equals(i))); System.out.println(); System.out.println("i == i4 = "+(i == i4)); System.out.println("i4.equals(i) = "+(i4.equals(i))); Answer: i1 == i2 = true i1.equals(i2) = true i3 == i4 = false i3.equals(i4) = true i2 == i4 = false i2.equals(i4) = true i == i2 = true i1.equals(i) = true i == i4 = true i4.equals(i) = true
3>对象的hashcode和equals
1)理解hashcode的作用
以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去。下次做Object的比较或者取这个对象的时候,它会根据对象的hashcode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。具体过程是这样: 1.new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashcode的对象放到这个单链表上去。 2.比较两个对象的时候,首先根据他们的hashcode去hash表中找他的对象,当两个对象的hashcode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashcode不同的话,肯定他们不能equal. 两个相等对象的equals方法一定为true, 但两个hashcode相等的对象不一定是相等的对象。
2) 覆盖equals的时候总是要覆盖hashcode
如果不覆盖hashcode的时候,可能会出现这样的情况,两个对象覆盖之后的equals方法返回为true,但其hashcode方法返回为false,而执行中的优化过程是,调用equals方法之前会先比较两个对象的hash值,如果不同,就不会进行equals比较了。所以覆盖equals方法而不覆盖hashcode方法存在上述风险,比较本应该放回equals的true但是在预执行hash值比较时就返回了false。