java中的字符串到底是在方法区的常量池里还是new出来的对象里?
看视频教程将内存图时说字符串类在常量池,后来讲String数组时又说会新建一个对象,把我搞晕了.. 展开
String实质是字符数组,两个特点:1、该类不可被继承;2、不可变性(immutable)
例如 String s1 = new String("myString");
和 String s1 = "myString";
第一种方式通过关键字new定义过程:在程序编译期,编译程序先去字符串常量池检查,是否存在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”;如果存在的话,则不用重新开辟空间,保证常量池中只有一个“myString”常量,节省内存空间。然后在内存堆中开辟一块空间存放new出来的String实例,在栈中开辟一块空间,命名为“s1”,存放的值为堆中String实例的内存地址,这个过程就是将引用s1指向new出来的String实例
第二种方式直接定义过程:在程序编译期,编译程序先去字符串常量池检查,是否存在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”;如果存在的话,则不用重新开辟空间。然后在栈中开辟一块空间,命名为“s1”,存放的值为常量池中“myString”的内存地址
String str ="nihao";
当这段代码编译的时候,首先它会去堆里的方法区常量池里去查找,如果有一个同样的字符串“nihao”,存在,那么它会把当前声明的对象的地址指向那个字符串对象,调用的是String.itern()方法。如果没有的话,它会开启堆内存,分割一块新的地址指向str对象。
String是不可变的(final的),不必担心稳定性问题。
而当你新new一个String数组的时候,当你给String数组赋值的时候,它同样遵循这个原理。
这样做的好处:字符串多重利用,防止产生冗余。
详情参考jdk中String类的的itern方法:
public String intern()
返回字符串对象的规范化表示形式。
一个初始为空的字符串池,它由类 String 私有地维护。
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。
它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当
s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。所有字面值字符串和字符串赋值常量表达式都使用 intern 方法进行操作。
String str ="nihao";
当这段代码编译的时候,首先它会去堆里的方法区常量池里去查找,如果有一个同样的字符串“nihao”,存在,那么它会把当前声明的对象的地址指向那个字符串对象,调用的是String.itern()方法。如果没有的话,它会开启堆内存,分割一块新的地址指向str对象。
String是不可变的(final的),不必担心稳定性问题。
而当你新new一个String数组的时候,当你给String数组赋值的时候,它同样遵循这个原理。
这样做的好处:字符串多重利用,防止产生冗余。
详情参考jdk中String类的的itern方法:
public String intern()
返回字符串对象的规范化表示形式。
一个初始为空的字符串池,它由类 String 私有地维护。
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。
它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
所有字面值字符串和字符串赋值常量表达式都使用 intern 方法进行操作。
String str = "nihao"; 程序开始执行这句代码,肯定是要创建一个对象的, 只是这个对象创建后就是一个常量,不可以更改, 并且这个对象是放在串池里面的,也就是你说的那个常量池
如果我后面在写一句代码: String other = "nihao";
str和other这2个引用的地址就是一样的, 因为str和other的声明方式是一样的, 都是在串池, str的对象创建时,串池中没有"nihao"这个常量,就创建一个. other对象创建时,发现串池中已经有了"nihao"这个常量, 就直接拿过来用就是了
String a1 = new String("nihao");
String b1 = new String("nihao");
但是如果我们通过上面的方式直接new String() 那个a1和b1这2个引用的对象就不是在串池中了,而是在堆中, 但是new String() 的参数"nihao"也是一个字符串啊, 这个字符串从哪里来呢?如果我们吧代码拆分一下就明白了:
String para = "nihao";
String a1 = new String(para);
就会发现String a1 = new String("nihao"); 这一句代码实际上创建了2个对象, 一个是String对象,存放在堆中, 一个是字符串常量对象,存放在串池中