前天晚上想干完饭补一补String的笔记,碍于学校渣网,加上笔记本没电,一拖拖到现在… 话不多说!
String定义
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {}
为什么设置为不可变类
主要考虑到效率和安全
效率:
1.在早期的JVM实现版本中,被final修饰的方法会被转为内嵌调用以提升执行效率。而从Java SE5/6开始,就渐渐摈弃这种方式了。因此在现在的Java SE版本中,不需要考虑用final去提升方法调用效率。只有在确定不想让该方法被覆盖时,才将方法设置为final。
2.缓存hashcode,String不可变,所以hashcode不变,这样缓存才有意义,不必重新计算
安全:
String常被作为网络连接,文件操作等参数类型,倘若可改变,会出现意想不到的结果
String的创建方式
1. 直接赋值
String str = "hello";
2. 构造器
在堆内存创建对象
String str = new String("hello");
要理解String,得了解JVM内存的栈(Stack)、堆(heap)和方法区。
堆:
- 存储的是对象,每个对象包含一个与之对应的class
- JVM只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
- 对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定
栈:
- 每个线程包含一个栈区,栈中只保存基本数据类型的对象和自定义对象的引用(不是对象)
- 每个栈中的数据都是私有的
- 栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)
- 数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失
方法区:
- 静态区,跟堆一样,被所有的线程共享
- 方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量
字符串常量池则位于方法区中
String str1 = "ff";
String str2 = "ff";
System.out.println(str1 == str2); // true
当执行第一句时,JVM会先去常量池中查找是否存在ff,当存在时直接返回常量池里的引用;当不存在时,会在字符创常量池中创建一个对象并返回引用。
当执行第二句时,同样的道理,由于第一句已经在常量池中创建了,所以直接返回上句创建的对象的引用。
String str1 = "ff";
String str3 = new String("ff");
System.out.println(str1 == str3); // false
当执行第一句时,JVM会先去常量池中查找是否存在ff,当存在时直接返回常量池里的引用;当不存在时,会在字符创常量池中创建一个对象并返回引用。
执行第二句时,会在堆(heap)中创建一个对象,当字符串常量池中没有‘ff’时,会在常量池中也创建一个对象;当常量池中已经存在了,就不会创建新的了。
String str4 = "lovehuihui";
String str5 = "love" + "huihui";
System.out.println(str4 == str5); // true
由于”love”和”huihui”都是常量,编译时,第二句会被自动编译为‘String str5 = “lovehuihui”;
String str4 = "lovehuihui";
String str6 = "love";
String str7 = "huihui";
String str8 = str6 + str7;
System.out.println(str4 == str8); // false
前三句存储的是常量池中的引用地址
第四句String str8 = str6 + str7;执行时,JVM会在堆中创建一个以str6为基础的StringBuilder对象,然后调用StringBuilder对象的append方法完成和str7的合并。之后会调用toString()方法在堆(heap)中创建一个String对象,并把这个String对象的引用赋给str8
类可变和线程安全
- String不可变安全
- StringBuffer可变安全
- StringBuilder可变非安全
使用选择:
- 当有少量连接操作时,使用String
- 当单线程下有大量连接操作时,使用StringBuilder
- 当多线程下有大量连接操作时,使用StringBuffer
常见题目
String str = new String(“abc”)创建了多少个实例?
分开类的加载和类的执行来讲:
类的加载:
当加载类时,”abc”被创建并驻留在了字符创常量池中(如果先前加载中没有创建驻留过)
类的执行:
当执行此句时,因为”abc”对应的String实例已经存在于字符串常量池中,所以JVM会将此实例复制到会在堆(heap)中并返回引用地址
这篇文章也是以前找了很多篇一起结合整出来的 侵删
有何不妥请多多提出~