主要区别
对于基本类型而言,== 比较的是二者值是否相等,对于应用类型而言,比较的是二者所引用的对象的地址是否相等,即比较二者是否指向同一个对象;
equals()是一个方法,只能比较引用数据类型(基本数据类型没有方法)。重写前比较的是地址值,重写后比一般是比较对象的属性。
Integer 的equals与==
Integer 重写了equals方法,实现源码如下
/**
* Compares this object to the specified object. The result is
* {@code true} if and only if the argument is not
* {@code null} and is an {@code Integer} object that
* contains the same {@code int} value as this object.
*
* @param obj the object to compare with.
* @return {@code true} if the objects are the same;
* {@code false} otherwise.
*/
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
改方法先判断equals的入参obj的类型是否为Integer,如果不是则直接返回false,如果是,则判断值是否相等。
如果obj参入的是一个基本类型,编译器会给改参数自动装箱成对应的包装类型;
在equals方法里打上断点,可以发现,但执行
a.equals(1L);
基本类型被装箱成Double类型
执行如下代码
public static void main(String[] args) {
Integer a = 1;
boolean result = a.equals(1L);
System.out.println("reuslt " + result);
result = a.equals(1);
System.out.println("reuslt " + result);
}
返回如下结果:
Integer与基本类型 == 的比较时,编译器会先将Integer拆箱成基本类型再比较,
public static void main(String[] args) {
Integer a = 1;
boolean result = a == 1.0;
System.out.println("reuslt " + result);
}
Integer与Integer比较时,判断的是两个地址是否同一个地址;
注意:当某个Integer是通过Integer.valueOf()获得的,需要判断这个值得大小,当Integer超出某个范围内才会,new一个新的对象
Integer.valueOf()源码如下
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache 缓存
JAVA的Integer有IntegerCache会缓存-128~127之间的对象。
如:Integer x = 100,会调用Integer的valueOf()方法,这个方法就是返回一个Integer对象,但是在返回前,作了一个判断,判断要赋给对象的值是否在[-128,127]区间中,且IntegerCache(是Integer类的内部类,里面有一个Integer对象数组,用于存放已经存在的且范围在[-128,127]中的对象)中是否存在此对象,如果存在,则直接返回引用,否则,创建一个新对象返回。
public static void main(String[] args) {
// Integer 与 基本类型equals比较时,基本类型会被编译成对应的装箱成对应的包装类型
Integer a = 1;
System.out.println(a.equals(1L));// 为false
// Integer 与 基本类型== 比较时, 包装类型会被拆箱成对应的基本类型
System.out.println(a == 1.0);// 为true
//Integer 与 new出来的 Integer 比较时,无论如何都是false,因为始终不指向同一个对象
System.out.println(a == new Integer(1));// 为false
//Integer 与 Integer.valueOf 出来的 Integer 比较时
System.out.println(a == Integer.valueOf(1));// 为true
Integer b = 1200;
System.out.println(b == Integer.valueOf(200));// 为false, 超出IntegerCache范围,
}
String 的equals 与 ==
String equals方法源码
/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
先判断类型是否为String, 在判断两个String类型的char[]数组长度是否一致,最后遍历char数组中每一个元素是否相等;
与 Integer 类似,String 有两种创建方式,new和字面量”赋值。对于使用字面量赋值方式。JVM为了节省空间,会首先查找JVM中是否有对应的字符串常量。如果已经存在,则直接返回该常量或字符串实例对象的地址引用,而无需重新创建对象。对象new创建方式,JVM将添加字面量常量和创建字符串实例并返回实例引用。
System.out.println("a" == "a");// 返回true
System.out.println( "a" == String.valueOf("a"));// 为true
System.out.println("a" == new String("a"));//为false
只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,
String s1 = "a";
String s2 = "b";
String s3 = "a";
String s4 = new String("b");
String s5 = "ab";
String s6 = "a" + "b";
String s7 = "a" + s2;
String s8 = s1 + "bc";
String s9 = "abc";
// 只有使用引号包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。对于所有包含new方式新建对象(包括null)的“+”连接表达式,它所产生的新对象都不会被加入字符串池中,
System.out.println(s1 == s3);// true
System.out.println(s2 == s4);// false
System.out.println(s5 == s6);// true
System.out.println(s5 == s7);// false
System.out.println(s8 == s9);// false
对于 String.valueOf(), 该方法源码如下
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
String 类的toString方法
public String toString() {
return this;
}
final修饰String
final修饰类的时候表示类不可被继承
final修饰方法的时候表示方法不能被重写
final修饰变量的时候,表示变量不可变
所以,final String c = “hello”;仅仅表示c不可变,不可再被重新赋值。(注意:这个String类是final的无关,那个是修饰String类的)
final修饰的String在相加的时候等同于字符串直接相加(注意这里相加的两个String 必须都被final修饰的):
final a = “a”,
final b = “b”;
a+b == “a”+“b” == “ab”
因为+号两边都是常量,其值在编译期就可以确定,由于编译器优化,在编译期就将+两边拼接合并了,直接合并成是一个常量"ab",这也解释了为什么 相加的两个String 必须都被final修饰的;
但是如果把final去掉,a+b == “a” + “b” 就是false了,因为不用final修饰,a和b都是对象,在编译期无法确定其值,所以要等到运行期再进行处理,处理方法:先new一个StringBuilder,然后append a和 b,最后相加的结果是一个堆中new出来的一个对象