面试问题(在看看b站视频)
1、有了String可以不使用volatile?
2、为什么会有这两种方式?因为他们的存储区域的不同
3、String底层是char类型的数组
一、String的三大特性
1.1、不变性
1.1.1、String是一个immutable模式的对象,不变模式的主要作用就是当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。
1.2、常量池优化
1.2.1、String对象创建之后,会在字符串常量池中进行缓存,下次创建同样的对象时,会直接返回缓存的引用。
1.3、final
1.3.1、String类不可被继承,提高了系统的安全性。
二、String的实例化有三种方式():
2.1、直接赋值
2.2、通过构造函数,可以直接将字符串的值传入,也可以传入一个char数组。
2.3、通过构造函数,可以直接传入char类型的数组
两者的区别(存储的区域):直接赋值是存储在字符串常量池中,而通过构造实例,是存储在堆中的。
三、面试考点总结
3.1、String不是基本数据类型
String底层其实是一个char类型的数组
3.2、String的实例化
3.3、equals方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value) :
StringUTF16.equals(value, aString.value);
} }
return false;
}
3.3.1、Object中的equals方法和“==”是一样的。
3.3.2、String对Object中的equal是方法进行了重写,比较的不再是地址值,而是其值()。
3.4、String 不可变
3.4.1、只要对String的值改变,就变成了一个新的对象
3.5、intern()方法
3.5.1、当String对象调用intern()方法时,会去字符串常量池去找值;如果该值存在,则返回该值的引用;如果不存在,则在字符串常量池中创建新的地址值并返回。
四、常用方法
4.1、字符串的切割
4.1.1、split()方法支持正则表达式
五、面试经典题
5.1、== 和 equals的区别?
5.1.1、“==”从数据类型分类比较,如果比较基本数据类型就是比较值;如果比较引用数据类型就是比较内存中的地址值。
5.1.2、equals是Object提供的方法和“==”没区别,但是String对他进行了重写,比较的是其值,而不是内存中的地址值。
5.2、下面代码运行结果是:
String str1 = "Hello World";
String str2 = "Hello";
str2 += " World";
System.out.println(str1 == str2);
用命令 javap -c xx.class 可以看到执行顺序,过程中有new StringBuilder();的方法append,所以str2是在堆里面出现的,结果即false;
5.3、下面代码运行结果是:
String str1 = "Hello World";
final String str2 = " World";
String str3 = "Hello" + str2;
System.out.println(str1 == str3);
结果为true,被final修饰的会被直接编译成显式的值,没有被final修饰的不会编译成显式的值。
参考资料:java中final 修饰的String 变量与未修饰的String变量的区别
5.4、下面代码运行结果是:
String str1 = "Hello World";
final String str2 = new String(" World");
String str3 = "Hello"+str2;
System.out.println(str1 == str3);
结果为false,即是被final修饰了,但是他一开始是在堆内存创建的,所以不管他是否被final修饰,始终在堆内存里。
5.5、下面代码运行结果是:
String str1 = "Hello World";
String str2 = "Hello";
String str3 = " World";
String str4 = str2 + str3;
System.out.println(str4 == str1);
System.out.println(str4.intern() == str1);
结果是:false,true。因为String的intern();方法,是先字符串常量池找,如果有则返回该引用,如果没有则在常量池中创建。
5.6、字符串常量池的作用
多个相同的值可以共用一个地址值。可以减少内存消耗。
5.7、String是否是线程安全的?
是的,值是不可变的,只要值改变,就是一个新的地址值。
5.8、在使用HashMap的时候,用String做key有什么好处?
由于HashMap是根据key的hashcode来找value,而String在创建的时候,就已经缓存了。所以在HashMap中,就不需要计算hashcode,缓存中就有,效率要比其他对象高。