各种数据类型的常量池技术

it2025-03-06  22

文章目录

一、前言二、基本类型常量池2.1 Boolean常量池代码1——常量池比较 true代码2——新建对象比较 一定返回false代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关) 2.2 字符型(Character)常量池代码1——常量池比较(涉及常量池:Character在(0 ~ 127)使用常量池技术,返回为true,范围外在堆中新建对象,返回为false)代码2——新建对象比较(直接比较new对象,一定为false,拆箱比较,一定为true)代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关) 2.3 Byte常量池代码1——常量池比较(-128~127全部为true,byte也不能超过这个范围,所以byte全部为true)代码2——新建对象后比较(直接比较new对象,一定为false,拆箱比较,一定为true)代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关) 2.4 Short常量池代码1——常量池比较(涉及常量池:Short在(-128 ~ 127)使用常量池技术,返回为true,范围外在堆中新建对象,返回为false)代码2——新建对象后比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较)代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关) 2.5 Integer常量池代码1——常量池比较(涉及常量池:Integer在(-128 ~ 127)使用常量池技术,返回为true,范围外在堆中新建对象,返回为false)代码2——新建对象比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较)代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关) 2.6 Long常量池代码1——常量池比较(涉及常量池:Long在(-128 ~ 127)使用常量池技术,返回为true,范围外在堆中新建对象,返回为false)代码2——新建对象比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较)代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关) 2.7 Float常量池代码1——常量池比较(涉及常量池:Float无常量池技术,所以在堆中新建对象,所以返回为false)代码2——新建对象比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较;整个过程与常量池技术无关)代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关) 2.8 Double常量池代码1——常量池比较(涉及常量池:Double无常量池技术,所以在堆中新建对象,所以返回为false)代码2——新建变量比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较;整个过程与常量池技术无关)代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关) 三、引用类型常量池(String常量池)四、面试金手指4.1 对象类型4.2 基本类型4.3 常量池技术 五、尾声

一、前言

Java中常量池大体可以分为:静态常量池,运行时常量池。

class文件常量池:存在于class文件中,如经常使用的javap -verbose中;

运行时常量池:就是在class文件被加载进了内存之后,常量池保存在了方法区中。

通常说的常量池指的是运行时常量池,本文讨论的都是运行时常量池。

二、基本类型常量池

Java中基本类型的常量池技术不是由基本类型实现的,而是由基本类型对应的包装类型实现的。但是因为Java5.0后引入自动装包和自动拆包,所以这一点已经不重要了。

基本类型包装类型常量池技术常量池范围boolBoolean实现了常量池true/falsecharCharacter实现了常量池0~127byteByte实现了常量池-128~127shortShort实现了常量池-128~127intInterger实现了常量池-128~127longLong实现了常量池-128~127floatFloat未实现常量池未实现常量池doubleDouble未实现常量池未实现常量池

2.1 Boolean常量池

代码1——常量池比较 true

package mypackage; public class TestConstantPool { public static void main(String[] args) { Boolean boolean1 = true; Boolean boolean2 = true; System.out.println(boolean1 == boolean2);// 打印true 包装类型Boolean实现了常量池技术 boolean1 = false; boolean2 = false; System.out.println(boolean1 == boolean2);// true } }

输出:

true true

代码2——新建对象比较 一定返回false

package mypackage; public class TestConstantPool { public static void main(String[] args) { Boolean boolean1 = new Boolean(true); Boolean boolean2 = new Boolean(true); System.out.println(boolean1 == boolean2);// false 不同对象指向不同地址 } }

输出:

false

代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { boolean _b1=true; boolean _b2=true; System.out.println(_b1==_b2);//true } }

输出:

true

金手指:Boolean/boolean

第一,基本类型仅比较值,全为true;

第二,新建对象比较引用(即内存地址),全为false, 运算符拆箱后变为基本类型,全为true;

第三,常量池(编译时类型为包装类型,运行时类型为基本类型)比较介于两者之间,常量池范围内(true|false)为true,又常量池覆盖Boolean所有范围(true|false),故Boolean常量池均为true。

2.2 字符型(Character)常量池

代码1——常量池比较(涉及常量池:Character在(0 ~ 127)使用常量池技术,返回为true,范围外在堆中新建对象,返回为false)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Character _cCharacter = (char) -1; Character _cCharacter2 = (char) -1; System.out.println(_cCharacter == _cCharacter2);// false Character _cCharacter3 = (char) 0; Character _cCharacter4 = (char) 0; System.out.println(_cCharacter3 == _cCharacter4);// true Character _cCharacter5 = (char) 127; Character _cCharacter6 = (char) 127; System.out.println(_cCharacter5 == _cCharacter6);// true Character _cCharacter7 = (char) 128; Character _cCharacter8 = (char) 128; System.out.println(_cCharacter7 == _cCharacter8);// false } }

输出:

false true true false

代码2——新建对象比较(直接比较new对象,一定为false,拆箱比较,一定为true)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Character _cCharacter0 = new Character((char) 0); Character _cCharacter = new Character((char) -1); Character _cCharacter2 = new Character((char) -1); System.out.println("新建对象后比较: " + (_cCharacter == _cCharacter2)); System.out.println("自动拆箱后比较: " + (_cCharacter == _cCharacter2 + _cCharacter0)); Character _cCharacter3 = new Character((char) 0); Character _cCharacter4 = new Character((char) 0); System.out.println("新建对象后比较: " + (_cCharacter3 == _cCharacter4)); System.out.println("自动拆箱后比较: " + (_cCharacter3 == _cCharacter4 + _cCharacter0)); Character _cCharacter5 = new Character((char) 127); Character _cCharacter6 = new Character((char) 127); System.out.println("新建对象后比较: " + (_cCharacter5 == _cCharacter6)); System.out.println("自动拆箱后比较: " + (_cCharacter5 == _cCharacter6 + _cCharacter0)); Character _cCharacter7 = new Character((char) 128); Character _cCharacter8 = new Character((char) 128); System.out.println("新建对象后比较: " + (_cCharacter7 == _cCharacter8)); System.out.println("自动拆箱后比较: " + (_cCharacter7 == _cCharacter8 + _cCharacter0)); } }

输出:

新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true

注意: 当出现运算符的时候,包装类型不可能直接用来运算,所以会进行一次拆箱成为基本数字进行比较,所以变成了两个基本类型之间的比较,仅比较值,则为true。

代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { char _cCharacter = (char) -1; char _cCharacter2 = (char) -1; System.out.println(_cCharacter == _cCharacter2);// true char _cCharacter3 = (char) 0; char _cCharacter4 = (char) 0; System.out.println(_cCharacter3 == _cCharacter4);// true char _cCharacter5 = (char) 127; char _cCharacter6 = (char) 127; System.out.println(_cCharacter5 == _cCharacter6);// true char _cCharacter7 = (char) 128; char _cCharacter8 = (char) 128; System.out.println(_cCharacter7 == _cCharacter8);// true } }

输出:

true true true true

金手指:Character/char

第一,基本类型仅比较值,全为true;

第二,新建对象比较引用(即内存地址),全为false, 运算符拆箱后变为基本类型,全为true;

第三,常量池(编译时类型为包装类型,运行时类型为基本类型)比较介于两者之间,常量池范围内(0~127)为true,常量池范围外jvm会重新新建对象,故为false。

2.3 Byte常量池

代码1——常量池比较(-128~127全部为true,byte也不能超过这个范围,所以byte全部为true)

package mypackage; public class TestConstantPool { public static void main(String[] args) { // Byte _bByte=(byte) -129; // Byte _bByte2=(byte) -129; byte仅一个字节 -128~127 超出范围 Byte _bByte3 = -128; Byte _bByte4 = -128; System.out.println(_bByte3 == _bByte4); Byte _bByte5 = 127; Byte _bByte6 = 127; System.out.println(_bByte5 == _bByte6); // Byte _bByte7=(byte) 128; // Byte _bByte8=(byte) 128; byte仅一个字节 -128~127 超出范围 } }

输出:

true true

代码2——新建对象后比较(直接比较new对象,一定为false,拆箱比较,一定为true)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Byte _bByte0 = new Byte((byte) 0); Byte _bByte3 = new Byte((byte) -128); Byte _bByte4 = new Byte((byte) -128); System.out.println("新建对象后比较: " + (_bByte3 == _bByte4)); System.out.println("自动拆箱后比较: " + (_bByte3 == _bByte4 + _bByte0)); Byte _bByte5 = new Byte((byte) 127); Byte _bByte6 = new Byte((byte) 127); System.out.println("新建对象后比较: " + (_bByte5 == _bByte6)); System.out.println("自动拆箱后比较: " + (_bByte5 == _bByte6 + _bByte0)); } }

输出:

新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true

注意: 当出现运算符的时候,包装类型不可能直接用来运算,所以会进行一次拆箱成为基本数字进行比较,所以变成了两个基本类型之间的比较,仅比较值,则为true。

代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { byte _bByte3 = -128; byte _bByte4 = -128; System.out.println(_bByte3 == _bByte4); byte _bByte5 = 127; byte _bByte6 = 127; System.out.println(_bByte5 == _bByte6); } }

输出:

true true

金手指:Byte/byte

第一,基本类型仅比较值,全为true;

第二,新建对象比较引用(即内存地址),全为false, 运算符拆箱后变为基本类型,全为true;

第三,常量池(编译时类型为包装类型,运行时类型为基本类型)比较介于两者之间,常量池范围内(-128 ~ 127)为true,又常量池覆盖Byte所有范围(-128~127),故Byte常量池均为true。

2.4 Short常量池

代码1——常量池比较(涉及常量池:Short在(-128 ~ 127)使用常量池技术,返回为true,范围外在堆中新建对象,返回为false)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Short _sShort=-129; Short _sShort2=-129; System.out.println(_sShort==_sShort2); Short _sShort3=-128; Short _sShort4=-128; System.out.println(_sShort3==_sShort4); Short _sShort5=127; Short _sShort6=127; System.out.println(_sShort5==_sShort6); Short _sShort7=128; Short _sShort8=128; System.out.println(_sShort7==_sShort8); } }

输出:

false true true false

代码2——新建对象后比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Short _sShort0 = new Short((short) 0); Short _sShort = new Short((short) -129); Short _sShort2 = new Short((short) -129); System.out.println("新建对象后比较: " + (_sShort == _sShort2)); System.out.println("自动拆箱后比较: " + (_sShort == _sShort2 + _sShort0)); Short _sShort3 = new Short((short) -128); Short _sShort4 = new Short((short) -128); System.out.println("新建对象后比较: " + (_sShort3 == _sShort4)); System.out.println("自动拆箱后比较: " + (_sShort3 == _sShort4 + _sShort0)); Short _sShort5 = new Short((short) 127); Short _sShort6 = new Short((short) 127); System.out.println("新建对象后比较: " + (_sShort5 == _sShort6)); System.out.println("自动拆箱后比较: " + (_sShort5 == _sShort6 + _sShort0)); Short _sShort7 = new Short((short) 128); Short _sShort8 = new Short((short) 128); System.out.println("新建对象后比较: " + (_sShort7 == _sShort8)); System.out.println("自动拆箱后比较: " + (_sShort7 == _sShort8 + _sShort0)); } }

输出:

新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true

注意: 当出现运算符的时候,包装类型不可能直接用来运算,所以会进行一次拆箱成为基本数字进行比较,所以变成了两个基本类型之间的比较,仅比较值,则为true。

代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { short _sShort = -129; short _sShort2 = -129; System.out.println(_sShort == _sShort2); short _sShort3 = -128; short _sShort4 = -128; System.out.println(_sShort3 == _sShort4); short _sShort5 = 127; short _sShort6 = 127; System.out.println(_sShort5 == _sShort6); short _sShort7 = 128; short _sShort8 = 128; System.out.println(_sShort7 == _sShort8); } }

输出:

true true true true

金手指:Short/short

第一,基本类型仅比较值,全为true;

第二,新建对象比较引用(即内存地址),全为false, 运算符拆箱后变为基本类型,全为true;

第三,常量池(编译时类型为包装类型,运行时类型为基本类型)比较介于两者之间,常量池范围内(-128~127)为true,常量池范围外会jvm重新新建对象,故为false。

2.5 Integer常量池

代码1——常量池比较(涉及常量池:Integer在(-128 ~ 127)使用常量池技术,返回为true,范围外在堆中新建对象,返回为false)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Integer _iInteger=-129; Integer _iInteger2=-129; System.out.println(_iInteger==_iInteger2); Integer _iInteger3=-128; Integer _iInteger4=-128; System.out.println(_iInteger3==_iInteger4); Integer _iInteger5=127; Integer _iInteger6=127; System.out.println(_iInteger5==_iInteger6); Integer _iInteger7=128; Integer _iInteger8=128; System.out.println(_iInteger7==_iInteger8); } }

输出:

false true true false

代码2——新建对象比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Integer _iInteger0=new Integer(0); Integer _iInteger=new Integer(-129); Integer _iInteger2=new Integer(-129); System.out.println("新建对象后比较: "+(_iInteger==_iInteger2)); System.out.println("自动拆箱后比较: "+(_iInteger==_iInteger2+_iInteger0)); Integer _iInteger3=new Integer(-128); Integer _iInteger4=new Integer(-128); System.out.println("新建对象后比较: "+(_iInteger3==_iInteger4)); System.out.println("自动拆箱后比较: "+(_iInteger3==_iInteger4+_iInteger0)); Integer _iInteger5=new Integer(127); Integer _iInteger6=new Integer(127); System.out.println("新建对象后比较: "+(_iInteger5==_iInteger6)); System.out.println("自动拆箱后比较: "+(_iInteger5==_iInteger6+_iInteger0)); Integer _iInteger7=new Integer(128); Integer _iInteger8=new Integer(128); System.out.println("新建对象后比较: "+(_iInteger7==_iInteger8)); System.out.println("自动拆箱后比较: "+(_iInteger7==_iInteger8+_iInteger0)); } }

输出:

新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true

注意: 当出现运算符的时候,包装类型不可能直接用来运算,所以会进行一次拆箱成为基本数字进行比较,所以变成了两个基本类型之间的比较,仅比较值,则为true。

代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { int _int1 = -129; int _int2 = -129; System.out.println(_int1 == _int2); int _int3 = -128; int _int4 = -128; System.out.println(_int3 == _int4); int _int5 = 127; int _int6 = 127; System.out.println(_int5 == _int6); int _int7 = 128; int _int8 = 128; System.out.println(_int7 == _int8); } }

输出:

true true true true

金手指:Integer/int

第一,基本类型仅比较值,全为true;

第二,新建对象比较引用(即内存地址),全为false, 运算符拆箱后变为基本类型,全为true;

第三,常量池(编译时类型为包装类型,运行时类型为基本类型)比较介于两者之间,常量池范围内(-128~127)为true,常量池范围外会jvm重新新建对象,故为false。

2.6 Long常量池

代码1——常量池比较(涉及常量池:Long在(-128 ~ 127)使用常量池技术,返回为true,范围外在堆中新建对象,返回为false)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Long _iLong = (long) -129; Long _iLong2 = (long) -129; System.out.println(_iLong == _iLong2); Long _iLong3 = (long) -128; Long _iLong4 = (long) -128; System.out.println(_iLong3 == _iLong4); Long _iLong5 = (long) 127; Long _iLong6 = (long) 127; System.out.println(_iLong5 == _iLong6); Long _iLong7 = (long) 128; Long _iLong8 = (long) 128; System.out.println(_iLong7 == _iLong8); } }

输出:

false true true false

代码2——新建对象比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Long _iLong0 = new Long(0); Long _iLong = new Long((long) -129); Long _iLong2 = new Long((long) -129); System.out.println("新建对象后比较: " + (_iLong == _iLong2)); System.out.println("自动拆箱后比较: " + (_iLong == _iLong2 + _iLong0)); Long _iLong3 = new Long((long) -128); Long _iLong4 = new Long((long) -128); System.out.println("新建对象后比较: " + (_iLong3 == _iLong4)); System.out.println("自动拆箱后比较: " + (_iLong3 == _iLong4 + _iLong0)); Long _iLong5 = new Long((long) 127); Long _iLong6 = new Long((long) 127); System.out.println("新建对象后比较: " + (_iLong5 == _iLong6)); System.out.println("自动拆箱后比较: " + (_iLong5 == _iLong6 + _iLong0)); Long _iLong7 = new Long((long) 128); Long _iLong8 = new Long((long) 128); System.out.println("新建对象后比较: " + (_iLong7 == _iLong8)); System.out.println("自动拆箱后比较: " + (_iLong7 == _iLong8 + _iLong0)); } }

输出:

新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true 新建对象后比较: false 自动拆箱后比较: true

注意: 当出现运算符的时候,包装类型不可能直接用来运算,所以会进行一次拆箱成为基本数字进行比较,所以变成了两个基本类型之间的比较,仅比较值,则为true。

代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { long _iLong = -129L; long _iLong2 = -129L; System.out.println(_iLong == _iLong2); long _iLong3 = -128L; long _iLong4 = -128L; System.out.println(_iLong3 == _iLong4); long _iLong5 = 127L; long _iLong6 = 127L; System.out.println(_iLong5 == _iLong6); long _iLong7 = 128L; long _iLong8 = 128L; System.out.println(_iLong7 == _iLong8); } }

输出:

true true true true

金手指:Long/long

第一,基本类型仅比较值,全为true;

第二,新建对象比较引用(即内存地址),全为false, 运算符拆箱后变为基本类型,全为true;

第三,常量池(编译时类型为包装类型,运行时类型为基本类型)比较介于两者之间,常量池范围内(-128~127)为true,常量池范围外会jvm重新新建对象,故为false。

2.7 Float常量池

代码1——常量池比较(涉及常量池:Float无常量池技术,所以在堆中新建对象,所以返回为false)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Float _fFloat = 1.0f; Float _fFloat2 = 1.0f; System.out.println(_fFloat == _fFloat2);// false 浮点型没有实现常量池技术 } }

输出:

false

代码2——新建对象比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较;整个过程与常量池技术无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Float _fFloat0 = new Float(0.0f); Float _fFloat = new Float(1.0f); Float _fFloat2 = new Float(1.0f); System.out.println("新建对象后比较: " + (_fFloat == _fFloat2)); System.out.println("自动拆箱后比较: " + (_fFloat == _fFloat2 + _fFloat0)); } }

输出:

新建对象后比较: false 新建对象后比较: true

注意: 当出现运算符的时候,包装类型不可能直接用来运算,所以会进行一次拆箱成为基本数字进行比较,所以变成了两个基本类型之间的比较,仅比较值,则为true。

代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { float _float1 = 1.0f; float _float2 = 1.0f; System.out.println(_float1 == _float2); } }

输出:

true

金手指:Float/float

第一,基本类型仅比较值,全为true;

第二,新建对象比较引用(即内存地址),全为false, 运算符拆箱后变为基本类型,全为true;

第三,Float无常量池技术,常量池比较jvm会重新新建对象,故为false。

2.8 Double常量池

代码1——常量池比较(涉及常量池:Double无常量池技术,所以在堆中新建对象,所以返回为false)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Double _dDouble = 1.0d; Double _dDouble2 = 1.0d; System.out.println(_dDouble == _dDouble2);// false 浮点型没有实现常量池技术 } }

输出:

false

代码2——新建变量比较(直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较;整个过程与常量池技术无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { Double _dDouble0 = new Double(0.0d); Double _dDouble = new Double(1.0d); Double _dDouble2 = new Double(1.0d); System.out.println("新建对象后比较: " + (_dDouble == _dDouble2));// false 浮点型没有实现常量池技术 System.out.println("自动拆箱后比较: " + (_dDouble == _dDouble2 + _dDouble0)); } }

输出:

新建对象后比较: false 自动拆箱后比较: true

注意: 当出现运算符的时候,包装类型不可能直接用来运算,所以会进行一次拆箱成为基本数字进行比较,所以变成了两个基本类型之间的比较,仅比较值,则为true。

代码3——基本类型比较(true 栈内存中,数值相等即为true,与常量池无关)

package mypackage; public class TestConstantPool { public static void main(String[] args) { double _dDouble = 1.0d; double _dDouble2 = 1.0d; System.out.println(_dDouble == _dDouble2); } }

输出:

true

金手指:Double/double

第一,基本类型仅比较值,全为true;

第二,新建对象比较引用(即内存地址),全为false, 运算符拆箱后变为基本类型,全为true;

第三,Double无常量池技术,常量池比较jvm会重新新建对象,故为false。

三、引用类型常量池(String常量池)

package mypackage; public class TestConstantPool { public static void main(String[] args) { String s1 = "Hello"; String s2 = "Hello"; String s3 = "Hel" + "lo"; String s4 = "Hel" + new String("lo"); String s5 = new String("Hello"); String s6 = s5.intern(); String s7 = "H"; String s8 = "ello"; String s9 = s7 + s8; // System.out.println(s1 == s2); // true 理由:s1和s2右边赋值都是显式写死的,是编译器可以预知的,编译期间,直接放到class文件的常量池中,运行时,指向同一个地址 System.out.println(s1 == s3); // true 理由:s1右边是显式写死的,s3也是显式写死的,没有使用变量,所有s1、s3都是编译器可以预见的,编译时放入静态常量池中,指向同一地址 System.out.println(s1 == s4); // false 理由:s4右边拼接的时候使用了new String(),编译时不可预知,需要运行时确定, System.out.println(s1 == s9); // false 理由:s9由s7、s8拼接,s7和s8都是变量,编译时不可预知 System.out.println(s4 == s5); // false 理由:s4右边使用new String(),编译时不可预知,s5右边也使用new String(),编译时不可预知 System.out.println(s1 == s6); // true 理由:s5已经在堆中,s6 = s5.intern(); //intern方法会尝试将Hello字符串添加到常量池中,并返回其在常量池中的地址,因为常量池中已经有了Hello字符串,所以intern方法直接返回地址;而s1在编译期就已经指向常量池了,因此s1和s6指向同一地址,相等。 } }

输出:

true // 两边都有变量,但是没有变量拼接 true // 两边变量,右边常量拼接 false // 两边变量,右边变量拼接,有newString() 一定false false // 两边都有变量,右边变量拼接,为false,没有intern()和final false // 两边都有变量,右边变量拼接,有newString() 一定false true 两边都有变量,右边变量拼接,但是右边intern()

四、面试金手指

4.1 对象类型

对于八种对象(即boolean character byte short int long float double):

第一,如果直接比较new对象,一定为false,与-128 ~ 127范围无关,纯对象比较;

第二,对于拆箱:short int long float double (即后面五种)拆箱比较,一定为true,与-128 ~ 127范围无关,纯数值比较(拆箱比较等同于下面的基本数据类型比较,全为true),整个过程与常量池技术无关。

4.2 基本类型

对于基本类型(boolean char byte short int long float double)都栈内存上,不涉及-128 ~ 127的数值范围,与常量池技术无关。

4.3 常量池技术

对于六种类型使用的常量池技术:

boolean 全部为true 取值就两个;

Character 0-127 全部为true 超出为false;

byte -128~127 为true,但是它的取值范围就是这样,所有全部为true;

Short Integer Long -128 ~ 127 全部为true,其他为false;

Float Double 全部为false,没有常量池技术,都要在堆上新建。

五、尾声

各种数据类型的常量池技术,完成了。

天天打码,天天进步!!!

最新回复(0)