Java常量池理解与总结

澳门新浦京8455com 10

一.相关概念

澳门新浦京8455com 1

java虚构机:运转时常量池,java虚构机量池

何以是常量

用final修饰的积极分子变量表示常量,值借使给定就不能转移!

final修饰的变量有三种:静态变量、实例变量和有个别变量,分别表示三连串型的常量。

image.png

一、运转时常量池简单介绍

运营时常量池(Runtime Constant
Pool),它是方法区的一部分。Class文件中除去有类的本子、字段、方法、接口等描述等音信外,还应该有一项音信是常量池(Constant
Pool
Table),用于寄放编写翻译期生成的种种字面量和标识引用,那有的剧情将要类加载后贮存到常量池中。

运作时常量是对峙于常量来讲的,它有着叁个要害特征是:动态性。当然,值相像的动态常量与大家何奇之有说的常量只是来源分歧,可是都是积累在池内同一块内部存款和储蓄器区域。Java语言并不须要常量一定只可以在编写翻译期产生,运维时期也说不许暴发新的常量,那个常量被放在运转时常量池中。这里所说的常量富含:基本项目包装类(包装类不管理浮点型,整形只会管理-128到127)和String(也能够经过String.intern(State of Qatar方法能够压迫将String放入常量池)

Class文件中的常量池

在Class文件布局中,最头的4个字节用于存储魔数Magic
Number,用于明确二个文本是或不是能被JVM选用,再跟着4个字节用于存款和储蓄版本号,前2个字节存款和储蓄次版本号,后2个存储主版本号,再接着是用以寄存常量的常量池,由于常量的数额是不固定的,所以常量池的进口放置多少个U2类型的多少(constant_pool_count卡塔尔国存款和储蓄常量池容积计数值。

常量池首要用于贮存两大类常量:字面量(LiteralState of Qatar和标志援引量(Symbolic
References卡塔尔(قطر‎,字面量也便是Java语言层面常量的定义,如文本字符串,注解为final的常量值等,符号援用则归属编写翻译原理方面包车型地铁定义,包括了如下二种档次的常量:

  • 类和接口的全限制名
  • 字段名称和陈诉符
  • 方法名称和汇报符

java是依据一门设想机的言语,所以掌握而且了然设想机运营规律极度主要。

二、 Class文件中的音信常量池

在Class文件构造中,最头的4个字节用于存款和储蓄Megic
Number,用于明确叁个文书是或不是能被JVM选拔,再接着4个字节用于存款和储蓄版本号,前2个字节存款和储蓄次版本号,后2个存款和储蓄主版本号,再接着是用来寄存常量的常量池,由于常量的数据是不固定的,所以常量池的输入放置三个U2类型的数目(constant_pool_count卡塔尔国存款和储蓄常量池容积计数值。

常量池首要用以贮存两大类常量:字面量(Literal卡塔尔(قطر‎和符号援引量(Symbolic
References卡塔尔(قطر‎,字面量也正是Java语言层面常量的概念,如文本字符串,表明为final的常量值等,符号援用则归属编写翻译原理方面包车型大巴定义,包涵了之类三种档期的顺序的常量:

  • 类和接口的全限制名
  • 字段名称和叙述符
  • 主意名称和描述符

方法区中的运维时常量池

运维时常量池是方法区的一部分。

CLass文件中除去有类的版本、字段、方法、接口等描述音信外,还或然有一项信息是常量池,用于存放编写翻译期生成的种种字面量和标记援用,这一部分剧情将要类加载后跻身方法区的运营时常量池中寄存。

运行时常量池相对于CLass文件常量池的此外一个至关重要特色是兼具动态性,Java语言并不供给常量一定唯有编写翻译期能力发生,也正是无须预置入CLass文件中常量池的从头到尾的经过能力跻身方法区运转时常量池,运营时期也恐怕将新的常量归入池中,这种特点被开垦职员利用相当多的便是String类的intern(卡塔尔(قطر‎方法。

方法区

方法区,Method Area,
对于习贯在HotSpot虚构机上支出和布局程序的开采者来讲,很六个人乐意把方法区称为“长久代”(Permanent
Generation),本质上两个并不等价,仅仅是因为HotSpot虚构机的规划团队选择把GC分代收集扩充至方法区,可能说使用永世代来促成方法区而已。对于其余设想机(如BEA
J罗克it、IBM J9等)来说是不设有长久代的概念的。

重在存放在已被虚构机加载的类新闻、常量、静态变量、即时编写翻译器编写翻译后的代码等数据(比方spring
使用IOC大概AOP创立bean时,也许使用cglib,反射的样式动态生成class音讯等)。

在意:JDK 6 时,String等字符串常量的新闻是置于方法区中的,不过到了JDK
7
时,已经移动到了Java堆。所以,方法区也好,Java堆也罢,到底详细的保留了什么,其实远非具体结论,要整合不一样的JVM版本来深入分析。

异常

当方法区不恐怕满足内部存储器分配必要时,将抛出OutOfMemoryError。
运营时常量池溢出:举个例子平昔往常量池参预数据,就能够引起OutOfMemoryError万分。

三、 常量池的好处

常量池是为了制止频仍的创建和销毁对象而影响系统品质,其贯彻了目的的分享。举例字符串常量池,在编写翻译阶段就把具有的字符串文字放到三个常量池中。

  • 节省里存空间:常量池中享有同一的字符串常量被统一,只占用二个上空。
  • 节约运营时刻:比较字符串时,==比equals(卡塔尔(قطر‎快。对于七个援引变量,只用==剖断引用是不是等于,也就能够剖断实际值是或不是等于。

双等号==的含义
  • 主导数据类型之间选取双等号,比较的是他们的数值。
  • 复合数据类型(类卡塔尔国之直接收双等号,比较的是她们在内存中的存放地方。

常量池的好处

常量池是为了制止频仍的创建和销毁对象而影响系统特性,其促成了目的的分享。

举个例子字符串常量池,在编写翻译阶段就把具有的字符串文字放到一个常量池中。
(1)节省里部存款和储蓄器空间:常量池中具备同一的字符串常量被统一,只占用二个空间。
(2)节省运维时刻:比较字符串时,==比equals(卡塔尔国快。对于三个引用变量,只用==决断援引是还是不是等于,也就可以判定实际值是或不是等于。

类信息

  1. 品种全节制名。
  2. 品类的直白超类的全节制名(除非那么些项目是java.lang.Object,它未有超类)。
  3. 花色是类类型如故接口类型。
  4. 品类的拜望修饰符(public、abstract或final的有个别子集)。
  5. 任何直接超接口的全节制名的平稳列表。
  6. 品类的常量池。
  7. 字段音讯。
  8. 方式新闻。
  9. 除去常量意外的全数类(静态)变量。
  10. 二个到类ClassLoader的援引。
  11. 三个到Class类的援引。

四、 基本类型的卷入类和常量池

java中着力类型的包装类的大部都完结了常量池技艺,即Byte,Short,Integer,Long,Character,Boolean。那5种包装类暗中认可创建了数值[-128,127]澳门新浦京8455com,的呼应类其余缓存数据,然则抢先此约束还是会去创设新的指标。
三种浮点数类型的卷入类Float,Double并从未实现常量池本事。

双等号==的含义

主旨数据类型之间利用双等号,相比的是他们的数值。

复合数据类型(类卡塔尔(قطر‎之间利用双等号,相比的是她们在内部存储器中的寄存地点。

1 常量池

1)Integer与常量池

澳门新浦京8455com 2

Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);

System.out.println("i1=i2   " + (i1 == i2));
System.out.println("i1=i2+i3   " + (i1 == i2 + i3));
System.out.println("i1=i4   " + (i1 == i4));
System.out.println("i4=i5   " + (i4 == i5));
System.out.println("i4=i5+i6   " + (i4 == i5 + i6));  
System.out.println("40=i5+i6   " + (40 == i5 + i6));


i1=i2   true
i1=i2+i3   true
i1=i4   false
i4=i5   false
i4=i5+i6   true
40=i5+i6   true

澳门新浦京8455com 3

二.8种为主项指标包裹类和常量池

java中基本类型的包装类的大部都贯彻了常量池本领,即Byte,Short,Integer,Long,Character,Boolean;

Integer i1 = 40;
Integer i2 = 40;
System.out.println(i1==i2);//输出TRUE

那5种包装类暗中同意创立了数值[-128,127]的照顾品种的缓存数据,然则抢先此约束如故会去创立新的对象。

//Integer 缓存代码 :
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 i1 = 400;
Integer i2 = 400;
System.out.println(i1==i2);//输出false

两种浮点数花色的包裹类Float,Double并未完毕常量池本领。

Double i1=1.2;
Double i2=1.2;
System.out.println(i1==i2);//输出false

1.1 Class文件中的常量池

在Class文件构造中,最头的4个字节用于存款和储蓄Megic
Number,用于鲜明多少个文件是或不是能被JVM采用,再接着4个字节用于存款和储蓄版本号,前2个字节存款和储蓄次版本号,后2个存款和储蓄主版本号,再接着是用于寄存常量的常量池,由于常量的数据是不稳固的,所以常量池的入口放置叁个U2类型的数量(constant_pool_count)存款和储蓄常量池体量计数值。

常量池重要用来寄存两大类常量:字面量(Literal卡塔尔(قطر‎和标记援用量(Symbolic
References卡塔尔(قطر‎,字面量相当于Java语言层面常量的定义,如文本字符串,注解为final的常量值等,符号援引则归于编写翻译原理方面包车型大巴定义,富含了之类二种等级次序的常量:

  • 类和接口的全节制名
  • 字段名称和描述符
  • 艺术名称和描述符
解释:
  • Integer i1=40;Java在编写翻译的时候会直接将代码封装成Integer
    i1=Integer.valueOf(40State of Qatar;,进而采用常量池中的对象。
  • Integer i1 = new Integer(40卡塔尔国;这种状态下会创建新的目的。
  • 语句i4 == i5 +

    i6,因为+那一个操作符不适用于Integer对象,首先i5和i6举办活动拆箱操作,进行数值相加,即i4

    40。然后Integer对象不可能与数值实行直接相比较,所以i4自动拆箱转为int值40,最后那条语句转为40
    == 40扩充数值比较。

应用常量池的景色

(1)Integer i1=40;Java在编写翻译的时候会直接将代码封装成Integer i1=Integer.valueOf(40);,进而采用常量池中的对象。

(2)Integer i1 = new Integer(40);这种意况下会创设新的靶子。

Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2);//输出false

Integer相比更丰硕的三个例证

Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);

System.out.println("i1=i2   " + (i1 == i2));
System.out.println("i1=i2+i3   " + (i1 == i2 + i3));
System.out.println("i1=i4   " + (i1 == i4));
System.out.println("i4=i5   " + (i4 == i5));
System.out.println("i4=i5+i6   " + (i4 == i5 + i6));   
System.out.println("40=i5+i6   " + (40 == i5 + i6));

i1=i2   true
i1=i2+i3   true
i1=i4   false
i4=i5   false
i4=i5+i6   true
40=i5+i6   true

解释:语句i4 == i5 + i6,因为+这么些操作符不适用于Integer对象,首先i5和i6进行活动拆箱操作,实行数值相加,即i4 == 40。然后Integer对象不能够与数值进行直接相比,所以i4自动拆箱转为int值40,最后那条语句转为40 == 40拓宽数值相比。
Java中的自动装箱与拆箱

1.2 运转时常量池

CLass文件中除了有类的版本、字段、方法、接口等描述信息外,还应该有一项信息是常量池,用于存放编写翻译期生成的各个字面量和标识引用,这一部分剧情将要类加载后步入方法区的运维时常量池中贮存。

运作时常量池相对于CLass文件常量池的别的二个首要特点是有着动态性,Java语言并不供给常量一定唯有编写翻译期技能发生,也便是不用预置入CLass文件中常量池的内容本事进来方法区运转时常量池,运维时期也许有可能将新的常量归入池中,这种天性被开垦职员利用相当多的正是String类的intern(卡塔尔国方法。

2)String与常量池-普通方法赋值

澳门新浦京8455com 4

String str1 = "abcd";
String str2 = new String("abcd");
System.out.println(str1==str2);//false

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
System.out.println("string" == "str" + "ing");// true
System.out.println(str3 == str4);//false

String str5 = "string";
System.out.println(str3 == str5);//true

澳门新浦京8455com 5

三.String类和常量池

1.3 常量池的利润

常量池是为着防止频仍的成立和销毁对象而影响系统天性,其贯彻了对象的分享。

比方字符串常量池,在编写翻译阶段就把富有的字符串文字放到一个常量池中。

  • (1)节本省部存款和储蓄器空间:常量池中具备同一的字符串常量被归并,只占用二个空间。
  • (2)节省运维时刻:相比较字符串时,==比equals(卡塔尔(قطر‎快。对于八个援引变量,只用==决断引用是不是等于,也就足以判明实际值是或不是等于。

双等号==的含义

  • 大旨数据类型之直接受双等号,相比的是他俩的数值。
  • 复合数据类型(类State of Qatar之间利用双等号,比较的是他们在内部存储器中的寄放地方。
解释:
  • “abcd”是在常量池中拿对象,new
    String(“abcd”State of Qatar是直接在堆内部存款和储蓄器空间成立一个新的对象。只要使用new方法,便需求创造新的目的。
  • 连接表明式
    +,独有选拔引号包涵文本的办法创建的String对象之间利用“+”连接发生的新对象才会被投入常量池中。
  • 对此字符串变量的“+”连接表明式,它所产生的新对象都不会被投入字符串池中,其归属在运作时创设的字符串,具有独自的内部存款和储蓄器地址,所以不引用自同一String对象。

String对象创制情势

String str1 = "abcd";
String str2 = new String("abcd");
System.out.println(str1==str2);//false

那三种差异的创办方法是有出入的,第一种艺术是在常量池中拿对象,第二种方式是一贯在堆内部存款和储蓄器空间创立三个新的目的。
万一利用new方法,便须要创制新的靶子。

1.4 基本类型的包装类和常量池

java中挑益州项目标包装类的大好多都实现了常量池技能,即Byte,Short,Integer,Long,Character,Boolean。

那5种包装类私下认可创设了数值[-128,127]的应和类别的缓存数据,但是超越此约束照旧会去创设新的靶子。
三种浮点数类型的卷入类Float,Double并未有完结常量池技艺。

3)String与常量池-静态方法赋值

澳门新浦京8455com 6

public static final String A; // 常量A
public static final String B;    // 常量B
static {  
   A = "ab";  
   B = "cd";  
}  
public static void main(String[] args) {  
// 将两个常量用+连接对s进行初始化  
String s = A + B;  
String t = "abcd";  
if (s == t) {  
    System.out.println("s等于t,它们是同一个对象");  
  } else {  
    System.out.println("s不等于t,它们不是同一个对象");  
  }  
}

澳门新浦京8455com 7

总是表明式 +

(1)唯有选取引号包括文本的议程创制的String对象之直接受“+”连接发生的新对象才会被投入字符串池中。
(2)对于具有满含new方式新建对象(蕴涵null)的“+”连接表明式,它所发生的新对象都不会被投入字符串池中。

String str1 = "str";
String str2 = "ing";

String str3 = "str" + "ing";
String str4 = str1 + str2;
System.out.println(str3 == str4);//false

String str5 = "string";
System.out.println(str3 == str5);//true

特例1

public static final String A = "ab"; // 常量A
public static final String B = "cd"; // 常量B
public static void main(String[] args) {
String s = A + B;  // 将两个常量用+连接对s进行初始化 
String t = "abcd";   
if (s == t) {   
    System.out.println("s等于t,它们是同一个对象");   
} else {   
    System.out.println("s不等于t,它们不是同一个对象");   
}   
} 
s等于t,它们是同一个对象

A和B都以常量,值是原则性的,因而s的值也是定点的,它在类被编译时就早就显著了。也等于说:String
s=A+B; 等同于:String s=”ab”+”cd”;

特例2

public static final String A; // 常量A
public static final String B;    // 常量B
static {   
A = "ab";   
B = "cd";   
}   
public static void main(String[] args) {   
// 将两个常量用+连接对s进行初始化   
String s = A + B;   
String t = "abcd";   
if (s == t) {   
    System.out.println("s等于t,它们是同一个对象");   
} else {   
    System.out.println("s不等于t,它们不是同一个对象");   
}   
} 
s不等于t,它们不是同一个对象

A和B纵然被定义为常量,但是它们都不曾及时被赋值。在运算出s的值在此之前,他们哪天被赋值,以至被赋予什么样的值,都以个变数。由此A和B在被赋值以前,性质相符于一个变量。那么s就不能够在编译期被鲜明,而不能不在运作时被创立了。

Integer与常量池

Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);

System.out.println("i1=i2   " + (i1 == i2));
System.out.println("i1=i2+i3   " + (i1 == i2 + i3));
System.out.println("i1=i4   " + (i1 == i4));
System.out.println("i4=i5   " + (i4 == i5));
System.out.println("i4=i5+i6   " + (i4 == i5 + i6));  
System.out.println("40=i5+i6   " + (40 == i5 + i6));


i1=i2   true
i1=i2+i3   true
i1=i4   false
i4=i5   false
i4=i5+i6   true
40=i5+i6   true
解释:

s不等于t,它们不是同三个指标。A和B固然被定义为常量,可是它们都未曾应声被赋值。在运算出s的值早先,他们何时被赋值,以至被赋予什么样的值,都以个变数。由此A和B在被赋值以前,性质相仿于两个变量。那么s就不能在编写翻译期被鲜明,而不能不在运转时被创制了。

String s1 = new String("xyz"); 创制了多少个目的?

考虑类加载阶段和实在实行时。

(1)类加载对一个类只会进展二遍。”xyz”在类加载时就早已创办并驻留了(假设此类被加载早前已经有”xyz”字符串被驻留过则不要求重新成立用于驻留的”xyz”实例)。驻留的字符串是献身全局分享的字符串常量池中的。

(2)在这里段代码后续被运转的时候,”xyz”字面量对应的String实例已经牢固了,不会再被再度创立。所以这段代码将常量池中的对象复制一份放到heap中,並且把heap中的那一个指标的援用交给s1
持有。
那条语句成立了2个对象。

解释:

  • (1State of QatarInteger i1=40;Java在编写翻译的时候会一向将代码封装成Integer
    i1=Integer.valueOf(40卡塔尔国;,从而选择常量池中的对象。
  • (2State of QatarInteger i1 = new Integer(40卡塔尔国;这种情形下会创制新的靶子。
  • (3)语句i4 == i5 +

    i6,因为+那个操作符不适用于Integer对象,首先i5和i6进行自动拆箱操作,进行数值相加,即i4

    40。然后Integer对象不可能与数值实行直接相比较,所以i4自动拆箱转为int值40,最后那条语句转为40
    == 40开展数值比较。

4)String与常量池-intern方法

澳门新浦京8455com 8

public static void main(String[] args) {
  String s1 = new String("计算机");
  String s2 = s1.intern();
  String s3 = "计算机";
  System.out.println("s1 == s2? " + (s1 == s2));
  System.out.println("s3 == s2? " + (s3 == s2));
}

s1 == s2? false
s3 == s2? true

澳门新浦京8455com 9

java.lang.String.intern()

运营时常量池相对于CLass文件常量池的其余一个根本特点是具有动态性,Java语言并不须要常量一定唯有编写翻译期技能生出,也正是毫不预置入CLass文件中常量池的剧情本领进来方法区运营时常量池,运维时期也说不好将新的常量放入池中,这种特征被开垦职员利用很多的正是String类的intern(卡塔尔(قطر‎方法。

String的intern(卡塔尔(قطر‎方法会查找在常量池中是或不是留存一份equal相等的字符串,假设有则赶回该字符串的援用,若无则增加自个儿的字符串步向常量池。

public static void main(String[] args) {    
   String s1 = new String("计算机");
   String s2 = s1.intern();
   String s3 = "计算机";
   System.out.println("s1 == s2? " + (s1 == s2));
   System.out.println("s3 == s2? " + (s3 == s2));
}

s1 == s2? false
s3 == s2? true

String与常量池

String str1 = "abcd";
String str2 = new String("abcd");
System.out.println(str1==str2);//false

String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
System.out.println(str3 == str4);//false

String str5 = "string";
System.out.println(str3 == str5);//true
解释:

String的intern(卡塔尔国方法会查找在常量池中是还是不是存在一份equal相等的字符串,若是有则赶回该字符串的援引,若无则拉长本身的字符串步入常量池。

字符串相比更丰裕的二个事例

public class Test {
public static void main(String[] args) {   
   String hello = "Hello", lo = "lo";
   System.out.println((hello == "Hello") + " ");
   System.out.println((Other.hello == hello) + " ");
   System.out.println((other.Other.hello == hello) + " ");
   System.out.println((hello == ("Hel"+"lo")) + " ");
   System.out.println((hello == ("Hel"+lo)) + " ");
   System.out.println(hello == ("Hel"+lo).intern());
}   
}
class Other { static String hello = "Hello"; }
package other;
public class Other { public static String hello = "Hello"; }

true true true true false true

在同包同类下,援用自同一String对象.

在同包差别类下,引用自同一String对象.

在分化包分歧类下,依然援引自同一String对象.

在编写翻译成.class时可以分辨为同一字符串的,自动优化成常量,引用自同一String对象.

在运行时创制的字符串具备独立的内部存储器地址,所以不援引自同一String对象.

解释:

  • (1卡塔尔new
    String(“abcd”State of Qatar是在常量池中拿对象,”abcd”是一向在堆内部存款和储蓄器空间创造二个新的指标。只要接受new方法,便必要创设新的对象。
  • (2卡塔尔国连接表明式 +
    唯有接纳引号富含文本的艺术创立的String对象之间接选举取“+”连接发生的新对象才会被投入字符串池中。
    对于具备包蕴new方式新建对象(满含null)的“+”连接表明式,它所产生的新对象都不会被投入字符串池中。

public static final String A; // 常量A
public static final String B;    // 常量B
static {  
   A = "ab";  
   B = "cd";  
}  
public static void main(String[] args) {  
// 将两个常量用+连接对s进行初始化  
String s = A + B;  
String t = "abcd";  
if (s == t) {  
    System.out.println("s等于t,它们是同一个对象");  
  } else {  
    System.out.println("s不等于t,它们不是同一个对象");  
  }  
}

5)String与常量池-延伸

String s1 = new String("xyz"); //创建了几个对象?

解释:

s不等于t,它们不是同三个对象。

A和B固然被定义为常量,不过它们都未曾及时被赋值。在运算出s的值以前,他们什么日期被赋值,甚至被给与什么样的值,都以个变数。由此A和B在被赋值从前,性质形似于一个变量。那么s就不能够在编写翻译期被分明,而只能在运作时被创建了。

String s1 = new String("xyz"); //创建了几个对象?
解释:

虚构类加载阶段和实在实施时。

  • 类加载对叁个类只会进展三回。”xyz”在类加载时就已经创办并驻留了(假设此类被加载以前早就有”xyz”字符串被驻留过则不要求再度创立用于驻留的”xyz”实例)。驻留的字符串是身处全局共享的字符串常量池中的。
  • 在这里段代码后续被运营的时候,”xyz”字面量对应的String实例已经牢固了,不会再被重新创建。所以这段代码将常量池中的对象复制一份放到heap中,何况把heap中的这几个指标的引用交给s1
    持有。

这条语句成立了2个对象。

一、运行时常量池简要介绍 运营时常量池(Runtime Constant
Pool),它是方法区的一有的。 Class 文件中…

解释:

酌量类加载阶段和事实上实践时。

  • (1)类加载对一个类只会进展壹回。”xyz”在类加载时就早就创办并驻留了(假诺此类被加载早前已经有”xyz”字符串被驻留过则无需重新创建用于驻留的”xyz”实例)。驻留的字符串是坐落于全局分享的字符串常量池中的。
  • (2)在这里段代码后续被运行的时候,”xyz”字面量对应的String实例已经稳定了,不会再被重复成立。所以这段代码将常量池中的对象复制一份放到heap中,并且把heap中的这些指标的援用交给s1
    持有。

这条语句创制了2个对象。

public static void main(String[] args) {
String s1 = new String("计算机");
String s2 = s1.intern();
String s3 = "计算机";
System.out.println("s1 == s2? " + (s1 == s2));
System.out.println("s3 == s2? " + (s3 == s2));
}
s1 == s2? false
s3 == s2? true

解释:

String的intern(State of Qatar方法会查找在常量池中是或不是存在一份equal相等的字符串,假如有则赶回该字符串的援用,若无则增进自身的字符串走入常量池。

public class Test {public static void main(String[] args) {
 String hello = "Hello", lo = "lo";
 System.out.println((hello == "Hello") + " "); //true
 System.out.println((Other.hello == hello) + " "); //true
 System.out.println((other.Other.hello == hello) + " "); //true
 System.out.println((hello == ("Hel"+"lo")) + " "); //true
 System.out.println((hello == ("Hel"+lo)) + " "); //false
 System.out.println(hello == ("Hel"+lo).intern()); //true
 }
}

class Other {
 static String hello = "Hello";
}


package other;

public class Other {
 public static String hello = "Hello";
} 

解释:

在同包同类下,援用自同一String对象.

在同包不一致类下,援引自同一String对象.

在分裂包不相同类下,依然援用自同一String对象.

在编写翻译成.class时能够分辨为同一字符串的,自动优化成常量,援用自同一String对象.

在运行时成立的字符串具有独立的内部存款和储蓄器地址,所以不引用自同一String对象.


村办介绍:

** 高广超**
:多年稍稍网络研究开发与构造划虚构计经历,擅长设计与出生高可用、高品质互联网构造。近期上任于美团网,肩负基本专门的学问研究开发职业。

正文首发在 高广超的简书博客
转发请评释!

澳门新浦京8455com 10

image.png

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图