java中==的含义
==的基本解释
==是二元运算符,其最终的结果返回的是基本数据类型中的boolean型。它是比较基本数据类型和引用数据类型,它的作用是比较两个变量是否相等,但对相等的定义我们应该达成一致。
情况一,基本数据类型之间比较
byte,short,char,int,long,float,double,boolean 他们之间的比较,比较的是他们的值。在比较它们值时,可能存在变量类型不同,在两个基本数据类型变量一致时,比较的是值。在比较两个基本数据类型不同是,会进行自动类型转换,小类型会转换成大类型,此时比较的也是值,当无法进行自动类型转换,便会报语法错误。
从本质来讲,基本数据类型比较的是内存地址,因为有jvm的常量池,所以我们赋值的是常量的内存地址。我们仅仅可以假想它们比较的是"值",但实质上是因为它们指向了同样的内存地址
情况二,引用数据类型之间比较
引用数据类型是指对象、数组、字符串等之间的比较,比较的是它们的内存地址。
字符串比较
String s1 = "abs";
String s2 = "abs"; //
String s3 = new String("abs");
System.out.println(s1 == s2);//s1与s2 内存地址相同
System.out.println(s2 == s3);//s2与s3 内存地址不相同
在编译时s1和s2的字符串"abs"会被放入jvm的常量池中。所以s1和s2在赋值的时候都是一样指向常量池中"abs"的内存地址。而s3不同,s3新new String对象,其字符串内容被放在heap中,s3在stack中指向heap地址。因此s2和s3内存地址不同。
情况三、基本数据类型与包装器类型的比较
包装器类型是指基本数据类型对应的类(int、Integer)。在比较时,会进行自动拆箱、装箱的操作。
自动拆箱、装箱
//自动装箱
Integer a = 127; //实际上是 Integer.valueOf(127)
//自动拆箱
int b = a;//实际上是 a.intValue()
装箱就是包装成对象;拆箱就是拆为基本数据类型。这些操作就是调用预先设计好的方法。
Integer比较细节
Integer i1 = 1;//装箱
Integer i2 = 1;//装箱
Integer i3 = new Integer(1);
Integer i4 = 128;
Integer i5 = 128;
System.out.println(i1 == i2);//true
System.out.println(i4 == i5);//false
System.out.println(i2 == i3);//false
System.out.println(1 == i1);//true,拆箱
i1、i2变量都进行了装箱操作,即调用了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);
}
...chche关键代码
cache[k] = new Integer(j++);
其中使用了IntegerCahce进行了缓存。预先初始化了256个数组。这意味着当值在-128到127闭区间的时候,使用的是相同内存地址的Integer对象。但是这样注意,这里尽管是缓存,但它还是对象!
因此由于缓存的关系,i1与i2内存地址相同。
i4与i5由于超过了缓存,所以内存地址不同。
i2和i3,因为一个是缓存中产生,一个是新new的对象,所以内存地址不同。
1和i1,从结果来看,i1拆箱了,即i1与1比较是,比较的不在是i1对象的内存地址,而是现将i1拆箱i1.intValue(),返回了i1对应的jvm中常量池的地址。所以i1和1的内存地址在==比较时是相等的。
同理的Short、Long类也有类似的操作。我们只需要正确理解内存地址、拆装箱的操作即可。
java中obj.equals()含义
==其实是java给我们定义的两个变量相等的含义,即内存地址是否相等。但这显然无法满足我们的需求。因此有了equals方法的定义。
equals方法是所有对象都拥有的默认方法。使用时我们必须明确的了解对应对象的equals具体实现。当然常用的String、Integer已经实现好了。
Integer equals解释
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
这个相等很简单,类型是否相同,其次对应的数字值是否相同。
关于 i4.equals(128),这将返回true,因为128会被装箱为Integer类型。但是i4.equals(new Long(128)),这将放回false,因为类型不同。
String equals解释
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;
}
先比较地址,其次比较字符串值。
java中Objects.equals()含义
这是工具类。
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
先比较内存地址,其次用equals比较,这里方便地方就是防止NPE(NullPointerException)的发生。
这里我说一下一个细节,关于是否使用Objects.equals方法来判断相等它有个很方便的功能就是永远不会发生NPE,但是在某种情况下代码吞掉NLP可能会引发致命的问题.
关于如何思考NPE问题及解决办法将在其他文章中总结