常量池
- 相同的值只存储一份,节省内存,共享访问,提高运行效率
基本类型的包装类
Boolean
Byte
Short
Integer
Long
Character
Float
Double
八种基本类型的包装类- 常量值范围
Boolean
:true, falseByte
Character
: \u0000 - \u007fShort
Integer
Long
: -128 - 127Float
Double
: 无常量池
==与equals()
- 对于基本数据类型,
==
比较他们的数值 - 对于对象,
==
比较两个对象在内存中的存放地址,可以通过重写equals()
来比较两个对象的内容是否相等
字符串常量
- Java为常量字符串建立了常量池缓存机制
1
2
3
4
5
6String s1 = "abc";
String s2 = "ab" + "c";
String s3 = "a" + "b" + "c"; //都是常量,是确定的,编译器将优化
System.out.println(s1==s2); //true
System.out.println(s1==s3); //true
System.out.println(s2==s3); //true
基本类型的包装类和字符串的两种创建方式
- 字面值赋值,放在栈内存(将被常量化)
Integer a = 1;
String b = "abc";
- new对象进行创建,放在堆内存(不会常量化)
Integer c = new Integer(1);
String d = new String("abc");
- 栈内存读取速度快,容量小
- 堆内存读取速度慢,容量大,可以通俗的理解为Java认为new出来的对象所占内存较大(不确定,而字面值是确定的),所以需要放在堆内存
Integer常量池的例子
1 | int i1 = 10; |
String常量池的例子
字符串常量池存在于方法区,方法区包含的都是在整个程序中唯一的元素,如static变量
一个简单的例子
1
2
3
4
5
6
7String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1==s2); //true 都是常量池
System.out.println(s1==s3); //false 一个是栈内存,一个是堆内存
System.out.println(s3==s4); //false 都是堆内存,但是不同对象图解:(
"
由'
代替)graph LR; subgraph 方法区 s['abc'] end subgraph 堆 A["s3 = new String('abc')"] B["s4 = new String('abc')"] end subgraph 栈 s1 s2 s3 s4 end s1-->s s2-->s A-->s B-->s s3-->A s4-->B
- 更为复杂的例子
1
2
3
4
5
6
7
8
9
10
11
12String s5 = "abcdef";
String s6 = s1 + "def"; //涉及到变量(不确定的),编译器不会优化
String s7 = "abc" + "def"; //都是常量,编译器会优化成abcdef
String s8 = "abc" + new String("def"); //涉及到new对象,编译器不优化
System.out.println(s6==s7); //false
System.out.println(s6==s8); //false
System.out.println(s7==s8); //false
System.out.println(s5==s7); //true
String s9 = s3 + "def"; //由于s3是new的,涉及到new对象,编译器不优化
System.out.println(s7==s9); //false
//对于s5~s9,只有s5,s7是在常量池中,其余都在堆内存上,且地址互不相同