关于‘==’的种种比较你知道吗

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_40321672/article/details/84923229

上篇文章谈了equals与==的区别,其实对于引用类型,如果equals没有重写,二者比较的都是内存地址,重写了就变成比较内容的了,也没什么好说的。那其实‘==’在包装类和String里那真是变化莫测啊,必须得详细谈一下的。

1.Integer与int

直接上代码分析最清楚了。参考此文:https://www.cnblogs.com/liuling/archive/2013/05/05/intAndInteger.html

public class TestInteger {

	public static void main(String[] args) {
		int i = 128;
		Integer i2 = 128;
		Integer i3 = new Integer(128);
		// Integer会自动拆箱为int,所以为true
		System.out.println(i == i2);
		System.out.println(i == i3);
		
		Integer i5 = 127;// java在编译的时候,被翻译成-> Integer i5 = Integer.valueOf(127);
		Integer i6 = 127;
		System.out.println(i5 == i6);// true
		/*
		  Integer i5 = 128; 
		  Integer i6 = 128;
		  System.out.println(i5 == i6);//false
		*/
		
		Integer ii5 = new Integer(127);
		System.out.println(i5 == ii5); // false
		
		Integer i7 = new Integer(128);
		Integer i8 = new Integer(123);
		System.out.println(i7 == i8); // false
	}

}

首先,Integer和int比都会自动拆箱,所以第一个和第二个输出都是true。

我们先来分析第五个输出吧,Integer i5 = 127,指向专门存放它的内存(常量池);Integer ii5 = new Integer(127),指向堆。内存地址不一样,肯定是false的。 

再分析第六个输出,无论值相等不,new出来的对象是不一样的,所以指向不一样,所以输出为false。

最后,第三个输出为true,而第四个注释的为false,这儿很多人都不懂。其实java在编译Integer i5 = 127的时候,被翻译成-> Integer i5 = Integer.valueOf(127);所以关键就是看valueOf()函数了。只要看看valueOf()函数的源码就会明白了。JDK源码的valueOf函数式这样的:

public static Integer valueOf(int i) {
       assert IntegerCache.high >= 127;
       if (i >= IntegerCache.low && i <= IntegerCache.high)
           return IntegerCache.cache[i + (-IntegerCache.low)];
       return new Integer(i);
}

如果以(Integer i = ~ )这样去初始化时,对于-128到127之间的数,会进行缓存,也就是放到常量池中。Integer i5 = 127时,会将127进行缓存,当Integer i6 = 127时,就会直接从缓存中取。所以i5,i6指向的都是常量池的同一个对象。

但是,一旦超过了127是128呢,相当于new Integer了,注释的i5,i6相当于在堆里new了俩对象啦,肯定地址不一样的啊。

那么关于Integer的总结如下:

①int和integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比。

②Integer和new Integer不可能相等的。在-128到127之间的数,前者指向池子,后者指向堆;在这区间之外的数,前者相当于new Integer,new出来的对象指向都会不一样。

③两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false

④两个都是new出来的,都为false

2、String

除了没有自动拆箱机制,觉得跟Integer多多少少还是差不多的。还是贴代码分析吧。

 
    private static void testStringPool() {  
        String a = "abc";//字面量形式  
        String b = "abc";//字面量形式  
        String c = new String("abc");//使用new标准的构造对象  

        String d = "ab" + "c";//字面量形式  
        System.out.println("a == b " + (a == b));//true  
        System.out.println("a == c " + (a == c));//false  
        System.out.println("a == d " + (a == d));//true  
        System.out.println("b == c " + (b == c));//false  
        System.out.println("b == d " + (b == d));//true  
        System.out.println("c == d " + (c == d));//false  
        System.out.println("-----------------");  
        System.out.println("abc" == ("ab" + "c"));//true  
        System.out.println("-----------------");  
        String e = c.intern();//将new出来的字符串对象加入字符串常量池  
        System.out.println(a == e);//true  
    }  
 

java创建字符串对象有两种方式:字面量形式(常量池形式)、标准的new方法

一般来说,我们采取字面量形式创建比较多,原因是JVM为了减少字符串对象的重复创建,维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池。

工作原理:  https://blog.csdn.net/qq_36381855/article/details/79686812

当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查。
如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回。
否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。

那上面的结果就好解释了,a b d的指向都是指向常量池的"abc",故相互比较都是true。然后c是new出来的,它指向的是堆里的地址,所以跟字面量形式创建的对象比都是false。但是最后手动把new出来的字符串对象加入字符串常量池,返回该引用,跟a指向比较,又是true了。

盗张图:

ff是字符串直接拼接出来的,还是相当于指向常量池中的“hello2”,所以与aa比较为true;而ee是经过了dd中间变量创建的对象,dd+2 通过StringBuilder的最后一步toString()方法还原一个新的String对象”hello2”,因此堆中开辟一块空间存放此对象,那么引用ee指向堆中(dd+2)所还原的新String对象,aa指向的是常量池中的"hello2",显然结果是false。那么aa与cc比较咋又是true了呢?

这就是final的作用了,由于变量bb被final修饰,因此会被当做编译器常量,所以在使用到bb的地方会直接将变量bb替换为它的值。这是不是跟C语言中的宏定义有异曲同工之妙呢?

最后,这个链接的东东也可以看看:

https://blog.csdn.net/qq_27657429/article/details/77882191

猜你喜欢

转载自blog.csdn.net/weixin_40321672/article/details/84923229