我们首先来看一段代码: Java代码$ w q3 N8 P! n& p, Y+ E2 x. o
String str=new String("abc");3 i; [+ Z; L7 e# F
紧接着这段代码之后的往往是这个问题,那就是这行代码事实建树了几个String对象呢?相信巨匠对这道题并不目生,谜底也是众所周知的,2个。接下来我们就年夜这道题睁开,一路回首回头回忆一下与建树String对象相关的一些JAVA常识。
- E6 f- {2 X' w& L0 \2 e0 {6 i: _/ e 我们可以把膳缦沔这行代码分成String str、=、"abc"和new String()四部门来看待。String str只是界说了一个名为str的String类型的变量,是以它并没有建树对象;=是对变量str进行初始化,将某个对象的引用(或者叫句柄)赋值给它,显然也没有建树对象;此刻只剩下new String("abc")了。那么,new String("abc")为什媚暌怪能被算作"abc"和new String()呢?我们来看一下被我们挪用了的String的机关器:2 a! t$ Y& E2 D; P$ C
Java代码
& r+ P/ `3 O4 q, t1 R public String(String original) {# |9 o. h, O3 s+ Y0 E
//other code ...
5 m$ K2 k+ v. ], X! c; _ }- J- ^9 s2 b5 d: {0 [" c. P, d8 k
巨匠都知道,我们常用的建树一个类的实例(对象)的体例有以下两种:
) B) A: l! }" E$ j. H6 ] 使用new建树对象。! M [% w$ J: c, P
挪用Class类的newInstance体例,操作反射机制建树对象。 a9 r6 P- Q) c
我们恰是使用new挪用了String类的膳缦沔阿谁机关器体例建树了一个对象,并将它的引用赋值给了str变量。同时我们注重到,被挪用的机关器体例接管的参数也是一个String对象,这个对象恰是"abc"。由此我们又要惹人此外一种建树String对象的体例的谈判——引号内包含文本。
8 }% X V, x2 Q! L) w4 @* O2 F 这种体例是String特有的,而且它与new的体例存在很年夜区别。
0 l! |0 R" ]6 {" x Java代码
+ e% c6 m- Q+ m, P String str="abc";0 W# W3 e1 Z' l) _/ E
毫无疑问,这行代码建树了一个String对象。
- E O5 z1 h5 J# { Java代码
0 v' O2 p" M; j( Q; O String a="abc";
: F# O! e- ~' @ String b="abc";- O7 i6 X4 Q0 x+ ~5 N) v* r
那这里呢?谜底仍是一个。% k7 Z N$ r/ ?1 O+ s' J
Java代码
" o: b, H) x: M String a="ab"+"cd"; _/ }- O! f7 {+ {+ E# g
再看看这里呢?谜底是三个。有点奇异吗?说到这里,我们就需要惹人对字符串池相关常识的回首回头回忆了。
" \3 I* M% i) D1 I2 C3 R 在JAVA虚拟机(JVM)中存在着一个字符串池,其中保留着良多String对象,而且可以被共享使用,是以它提高了效率。因为String 类是final的,它的值一经建树就不成改变,是以我们不用担忧String对象共享而带来轨范的杂乱。字符串池由String类维护,我们可根柢用 intern()体例来访谒字符串池。4 r( G9 }( D2 K
我们再回头看看String a="abc";,这行代码被执行的时辰,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc"的这么一个对象,它的判定依据是String 类equals(Object obj)体例的返回值。如不美观有,则不再建树新的对象,直接返回已存在对象的引用;如不美观没有,则先建树这个对象,然后把它插手到字符串池中,再将它的引用返回。是以,我们不难理解前面庞个例子中头两个例子为什么是这个谜底了。2 ]! j" N- x" y! T. a7 \" p$ v: \
对于第三个例子:
* f: C% o$ F. U" K- @7 ? Java代码
4 b7 R9 r8 y) }- {+ w/ [ String a="ab"+"cd";
: k! L0 ~6 K& _: q9 B' [! Q "ab"和"cd"分袂建树了一个对象,它们经由“+”毗连后又建树了一个对象"abcd",是以一共三个,而且它们都被保留在字符串池里了。
; p: }* a, `% W" \' v1 ` J, [ 此刻问题又来了,是不是所有经由“+”毗连后获得的字符串城市被添加到字符串池中呢?我们都知道“==”可以用来斗劲两个变量,它有以下两种情形:( R; K P5 \+ N! w. n- I. |: l5 K% \
如不美观斗劲的昵嘟个根基类型(char,byte,short,int,long,float,double,boolean),则是判定它们的值是否相等。
; r! M' ~2 ~* l. x 如不美观表较的昵嘟个对象变量,则是判定它们的引用是否指向统一个对象。
9 }' K! R g* z1 p7 S2 r" w" ~5 y 下面我们就用“==”来做几个测试。为了便于声名,我们把指向字符串池中已经存在的对象也视为该对象被插手了字符串池:
" |0 ?. `, c. d% s, M Java代码
% ]# F1 {8 R4 u/ t5 Z public class StringTest {
8 H1 d1 m) b4 \- \" |, t8 R public static void main(String[] args) {
, M& W4 t9 f. G. D: G L String a = "ab";// 建树了一个对象,并插手字符串池中- y# ?+ P' y$ R7 p
System.out.println("String a = "ab";");
1 _# x1 c; X, L; _, U# r: } String b = "cd";// 建树了一个对象,并插手字符串池中
% d! r& F0 E/ N% ^3 J1 W3 N& M. |' ` System.out.println("String b = "cd";");
: C! Z! V- p- y, u" X) U String c = "abcd";// 建树了一个对象,并插手字符串池中; E8 x7 p$ J" W; u3 _
String d = "ab" + "cd";
3 z0 @* M6 g- h& _' S // 如不美观d和c指向了统一个对象,则声名d也被插手了字符串池' S b( [* [' c2 @' R2 O
if (d == c) {5 g. n. H4 r3 {0 a; \. B, z, C
System.out.println(""ab"+"cd" 建树的对象 "插手了" 字符串池中");1 z, V4 F4 b. P" P& p; }1 g
}
1 |) w/ x* }0 B$ x- A // 如不美观d和c没有指向了统一个对象,则声名d没有被插手字符串池. Z% L$ s( U* d8 r: b8 _! U: ^
else {6 w( I! C6 d7 T E+ j. q+ ~, N! l
System.out.println(""ab"+"cd" 建树的对象 "没插手" 字符串池中");
' v" B1 P' \' ^) S
) k6 k' c/ n8 r! F( ^6 n) M4 n9 v } |