以前就知道JAVA对象分对象引用和值引用,并且还知道8种基础数据类型,即引用时是值引用的数据类型,比如int,short,long,byte,float,double,char,boolean,其它都是对象引用。可是其它的对象引用我一直都以为跟c里面是一样的指针传递,直到今天才发现原来JAVA里面还是别有一番天地的。
1. 方法调用的时候,并不是类似c的指针传递,而是引用的复制
比如代码:
voidfunc1(Lists){s.add(“dfdsa”);}voidtest(){List<String>list=newArrayList<String>();list.add(“abc”);func1(list);System.out.println(list.size());//此处结果为2 }
以前一直以为在func1里面的s跟外面的list变量是同一个引用(暂且理解为指针好了)即在栈(stack)里面是同一个东东,这个结论无可厚非,可是看代码:
voidfunc(Strings){s+=”tail”;}voidtest(){Stringa=”abc”;func(a);System.out.println(a);//此处结果为abc }
经过讨论才发现,原来在stack里面a和func里面的s是完全不同的两个引用,虽然它们指向同一个堆(heap)里面的对象,之所以跟上面的代码结果看起来不一样,只是因为String是一个非可变类(immutable),简单的说就是实例是不可被修改的。在func里面执行s += “tail”;操作的时候,s这个引用已经变成指向heap里面另外一个值为”abctail”的对象了,老的s引用已经被废了,随时可以被gc回收了
2. String对象在内存中的位置
既然String是一个immutable的类,那么对于同样值的String实例,我们是可以不必重复创建的,于是就有了JVM中的String Pool的概念。简单的说,String Pool里面放着heap里面String对象的引用。看代码:
Strings=”abc”;
当程序执行该代码的时候,JVM会在String Pool里面通过equal(“abc”)方法查找有没有现成的String对象引用,如果没有,则在heap里面创建一个String对象并将该对象的引用保存到String Pool里面;如果有了,那么就直接返回该对象的引用。
再看一段非常类似的代码:
Strings=newString(“abc”);
当程序执行该代码的时候,JVM会像普通对象一样生成这个String对象,在heap里面保存,直接返回引用,并不会与String Pool交互,这样一来,String Pool的优势就没有被发挥了,怎么办呢?难道我们就不去使用new的方法创建String了吗?答案是JVM还提供了一个方法:String.intern();来让String Pool管理这种String对象。
intern方法的工作原理是这样的:首先在heap里面创建一个完全一样的String对象,并且将该对象的引用放入String Pool中,最后返回给调用方,看代码: