1、什么是常量
- 用final修饰的成员变量表示常量,值一旦给定就无法改变;
- final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量;
2、常量池的好处
- 常量池是为了避免频繁的创建和销毁对象而影响系统的性能,其实现了对象的共享;
- 例如字符串常量池,在编译阶段就把所有的的字符串文字放到一个常量池中。
- 节省内存空间:相同的字符串只占一个空间;
- 节省运行时间:比较字符串时,==比equal()快。(注意==比较的是对象的内存地址,二String中将equal重写了,是比较的字符串内容)
3、连接表达式+
- 只有使用引号"",包含文本的方式创建的String对象之间使用“+”连接产生的新对象才会被加入字符串池中。
- 对于所有包含new方式新建对象(包括null)的“+”连接表达式,他所产生的新对象都不会加入字符串常量池。
public static void main(String[] args) {
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、String字符串直接使用+号进行连接,速率要快于StringBuffer(StringBuild),因为反编译之后会发现虚拟机将字符串直接优化成
String str = "abcd";,编译时期进行优化。
package nc.demo;
public class ContactDemo {
public static void main(String[] args) {
String string = "a"+"b"+"c"+"d"; //编译期间优化后在字符串常量池中创建一个对象
System.out.println(string);
String aString = "abcd";//直接在字符串常量池中引用创建好的对象
String intern = string.intern();
String dString = new String("abcd");//堆中创建
System.out.println(string == aString);//true
System.out.println(string == dString);//false
}
}
反编译后的文件:
package nc.demo;
import java.io.PrintStream;
public class ContactDemo
{
public static void main(String[] paramArrayOfString)
{
String str = "abcd";
System.out.println(str);
}
}
2、有关String常量池的位置
在JDK1.6之前,常量池的位置位于永久区,但是1.7以后该区域移到堆内存中进行管理;
package action;
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
int i = 0;
while (true) {
list.add(String.valueOf(i++).intern());
}
}
}
=======================================================
使用 -Xmx5m -XX:-UseGCOverheadLimit 参数运行此程序,可以打出以下堆栈信息;
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.lang.Integer.toString(Integer.java:403)
at java.lang.String.valueOf(String.java:3099)
at action.Main.main(Main.java:12)