以==理解java内存

引言

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public static void main(String[] args) {
    String str1 = new String("hello");
    String str2 = "hello";
    String str3 = new String("hello");
    String str4 = "hello";
    System.out.println(str1 == str2);
    System.out.println(str2 == str3);
    System.out.println(str3 == str4);
    String str5;// (str5 = str?)可以用==输出true?
}

来一段java代码,如果上面变量都是int之类基本类型,也许结果显然全部相等。但是:

  • 如果现在是字?
  • 再换为随意创建的对象呢?
  • 再把==换为equals()呢?

分析

也许上面代码直接copy到Eclipse下瞬间便知答案,但是为什么?

首先定义了两组变量(str1,str2与str3,str4),方式一模一样,然后用==计算互相之间差异。
那么我们就要知道==在java中比较的是地址。好吧,貌似知道了也不能直接解题。似乎还必须了解它们存放地址在哪,这样才知道是否地址相等。那便一个一个分析变量存储内存(java内存介绍便不啰嗦了,可以看这儿)。

1
String str1 = new String("hello");

这段代码执行时,用了new关键字,于是在堆中创建了String对象,保存的值便是"hello"(任何对象创建都是类似)。然后在堆栈(栈)中保存一个引用类型(str1)[4个字节,保存地址]。而str1存放的是"hello"这个对象在堆中的地址(可以想象C中指针指向一个实际值,但是java中不存在指针这一说法)。于是每new一个对象,必然在堆中新分配了空间。对于String类型这是绝对的,而且只会在堆中保存对象。但是一个类存在的静态变量,会放在静态变量区,方法体等其他仍在堆中。

1
String str2 = "hello";

而执行这段代码时,str2仍然是栈中引用类型,但是java会先在常量池中寻找有没有"hello"这个字符串,如果有,那么str2就初始化为找到的"hello"的引用(不会在任何地方创建新对象)。如果没找到,会在常量池中创建,不同于new,堆中不创建对象。至此,在常量池中和堆中各有一个"hello"。继续:

1
2
String str3 = new String("hello");
String str4 = "hello";

接下来继续创建"hello"。str3时,又是new,想都不用想,前面str1分析中说了每次new都在堆中新创建对象。ok,现在堆中两个对象了,接着str4呢?继续在常量池创建?当然不,直接等号初始化是在常量池创建,但是前提是没有这个,而str2已经存在于常量池中,那么str4也就引用此处"hello"好了。至此所有创建的对象包括引用状态如下图: ![内存状态][2] 现在回到代码输出,比较地址?显然只有str2和str4引用同一个"hello" 地址,再其他任意两个地址都不相等。好吧,开始程序输出三个false.

然后根据自己想法创建一个str5,想等于str1?可以这样String str5 = str1,str3同理。如果想等于str2,或者str4呢,也可以这样?当然,而且还可以这样:

1
String str5 = "hello";//为什么?

思考

如果输出用equals()而不用==呢?

运行程序,或者直接得出:所有的str都相等。那么么么。。。为什么O(∩_∩)O~?

看来又要去了解[equals()的比较方式] [3]

[2]: {{ site.url }}/assets/images/2015/20150423.png [3]: http://www.nonefly.com

updatedupdated2022-04-292022-04-29
Load Comments?