详解String
引言
在java中每天都会使用String。对于String的特性和用法需要进行深入的了解
immutable(不可变)
- 安全性:final修饰的类意味着不能被继承,所有的属性方法不能被修改,安全。
不可变也意味着可以被共享- 效率:因为都是final修饰编译器可以做一定的优化。
可以被共享不需要进行多线程之间的同步。String 加号的本质
|
|
由于我们不熟悉Class文件结构,
而且字节码非常不容易看懂,在这里不直接查看编译生成的StringTest.class文件的内容,
而是通过jad工具反编译字节码查看结果。
在cmd下执行jad命令jad -o -a -sjava StringTest.class成功执行上述命令后,
会发现StringTest.class文件所在目录下会多出源文件StringTest.java,
内容如下:
|
|
所以应该避免使用加号,直接使用StringBuffer(),
因为都是方法内应用不存在线程安全问题。StringBuffer更快
相等判断的说明
String中==判断结果解释1234String a = "a1"; String b = "a" + 1; System.out.println(a == b);
结果为true
说明在编译期间生成的字节码命令已经决定这些对象指向哪些地址,
存在什么位置
实际上在java编译器的编译期,已经进行了字面量的拼接。
也就是说编译生成的Class文件中并不存在String b = “a” + 1对应的字节码指令,
已经被优化为String b = “a1”对应的字节码指令。
在编译期间能够确定结果并进行计算,
(也就是生成class文件时)就能有效减少Class文件中的字节码指令,
即减少了程序运行时需要执行的指令,提高了程序效率
|
|
结果为false
存在new StringBulider(String.valueOf(h))
所以前面的h指向的是java的堆,而”world”指向的是常量池很显然这两个不是一个地址。
|
|
true、true、false、false
局部变量h1被final修饰,意味着h1是常量。
常量和常量组合在编译器就能计算出结果。
h2同理,是静态常量
h3也是常量但是h3值得确定需要通过方法调用进行赋值。在编译期间无法确定所以。
所以h3也是指向>java堆
h4同理
|
|
结果为false
一个是对象存放在java堆中一个事常量存放在常量池中
面两种给String类型变量赋值的方式,除了它们指向不同的String对象外,其它并没有什么区别。从程序效率的角度看,推荐使用方式一给String类型变量赋值,因为方式二多了一次java堆的String对象分配。
前面说过,字符串字面量直接被看作String类的一个实例,实际是其在编译期就存放在Class文件的常量池中,当Class文件被jvm加载时,其就进入到方法区的运行时常量池中。如果想在运行期间将新的常量加入常量池中,可调用String的intern()方法。 当调用 intern方法时,如果常量池已经包含一个等于此String对象的字符串(用equals(Object)方法确定),则返回常池中的字符串。否则,将此String 对象添加到池中,并返回此String对象的引用。