String是final类!
String str1 = “hello world”的意义–(方法区)
在编译期间生成了 字面常量和符号引用,
运行期间字面常量”hello world”被存储在运行时常量池(方法区中)(当然只保存了一份)。
通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,
如果存在,则直接将引用指向已经存在的字面常量;
否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。
String str=new String(“hello world”)的意义–(堆中)
通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。
因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。
String、StringBuilder、StringBuffer三者的执行效率:(相对而言,并不一定)
StringBuilder > StringBuffer(StringBuffer类的成员方法前面多了一个关键字:synchronized) > String
很有趣的问题
- 下面这段代码的输出结果是什么?
String a = “hello2”;
String b = “hello” + 2;
System.out.println((a == b));
输出结果为:true。原因很简单,”hello”+2在编译期间就已经被优化成”hello2”,因此在运行期间,变量a和变量b指向的是同一个对象。
2.下面这段代码的输出结果是什么?
String a = “hello2”;
String b = “hello”;
String c = b + 2;
System.out.println((a == c));
输出结果为:false。由于有符号引用的存在,所以 String c = b + 2;不会在编译期间被优化,不会把b+2当做字面常量来处理的,因此这种方式生成的对象事实上是保存在堆上的。因此a和c指向的并不是同一个对象
3.下面这段代码的输出结果是什么?
String a = “hello2”;
final String b = “hello”;
String c = b + 2;
System.out.println((a == c));
输出结果为:true。对于被final修饰的变量,会在class文件常量池中保存一个副本,也就是说不会通过连接而进行访问,对final变量的访问在编译期间都会直接被替代为真实的值。那么String c = b + 2;在编译期间就会被优化成:String c = “hello” + 2;
4.String str = new String(“abc”)创建了多少个对象?
new只调用了一次,也就是说只创建了一个对象。
5.String str = new String(“abc”)涉及到几个String对象?
2个
总结
StringBuffer是线程安全的,所以效率上比Stringbuilder差一些
关于编译器自动优化的问题,如果在编译期间能确定值,编译器会进行优化,有符号引用存在的话就不能优化
new String()是对象,在堆中
直接赋值,其实是先在运行时常量池中寻找是否有相同的相同的字面常量,有就直接引用过去,没有的话先创建再引用。