JAVA面试集锦String相关的经典面试题
Posted bloghxr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA面试集锦String相关的经典面试题相关的知识,希望对你有一定的参考价值。
序言
有关String类型的很经典的面试题很多,面试的时候会由String引入JVM、集合、多线程等比较深的问题,进而测试个人的基础知识是否扎实和学习态度,理应重视,先大概整理些,后续再补充整理吧...
一、String、StringBuilder和StringBuffer的区别
1. String是字符串常量,StringBuilder和StringBuffer是字符串变量
String对象创建完成之后,如果对其更改,都是重新创建一个String对象,创建的过程是先向字符串常量池查找,如果没有则先创建该对象,然后把该字符串对象添加到字符串常量池中(jdk1.6复制的是字符串对象实例,jdk1.7则是复制字符串对象的实例引用);而StringBuilder和StringBuffer都是可变的;
2. StringBuilder是线程不安全的,StringBuffer是线程安全的
StringBuffer相关方法添加了线程同步关键字synchronize关键字,故线程安全的,但效率低。
二、String为什么设计成不可变(immutable)
1. 字符串常量池的优化需要
字符串常量池针对String字符串使用的一种优化策略,创建字符串对象前,首先检查字符串常量是否已经有该字符串(通过equal比较),有直接返回字符串在字符串常量池的引用,避免重复创建字符串而消耗多余的内存空间,如果String为可变的,这种优化策略则无效;
2. 允许String对象缓存HashCode
字符串的不变性保证了hashcode唯一性,不可变的hashcode可以被缓存而不用重新计算,提升了像使用String作为键值的hashmap的效率,这也侧面反映了hashmap为什么多数使用String作为键值的原因了;
3. 多线程使用安全性
字符串不可变,所以在多线程可以共享一个字符串实例,而不需要做额外的线程同步;
4. 类加载器需要
类加载器用到字符串,不可变性提供了安全性,以便类的正确加载;例如在加载java.sql.Connection类,如果这个值被改成myhacked.Connection,则会对数据库造成不可知的破坏;
5. 安全性
如果字符串是不可变的,则会引起很严重的安全问题;例如数据库的用户名和密码都是以字符串形式传入获得数据库的连接,socket编程中,主机名等都是以字符串形式传入,如果字符串可变,黑客可以很容易改变字符串对象的值,造成安全漏洞。
三、String直接创建对象(String s="abc")和intern()方法的区别
两者在创建字符串对象的时候都会先去字符串常量池查找该对象是否存在,如果没有,在堆中创建字符串对象,并把字符串实例引用(jdk1.7+)复制到字符串常量池中;大概看上去intern()方法该有的功能String s="abc";都有的,那么intern存在的意义为何?
测试代码 Test.java
String s1 = "ab";
String s2 = "c";
String s3 = "abc";
System.out.println(s3=="ab"+"c"); //true
System.out.println(s3==s1+s2); //false
System.out.println(s3==(s1+s2).intern()); //true
编译代码 Test.class
String s1 = "ab";
String s2 = "c";
String s3 = "abc";
System.out.println(s3 == "abc");
System.out.println(s3 == s1 + s2);
System.out.println(s3 == (s1 + s2).intern());
String s="abc"和intern()方法的区别是一个在编译期,一个在运行期
四、StringBuilder和"+"号的区别?
1. 拼接字符串常量
测试类
6 String s1 = "a" + "b" + "c";
7 String s2 = new StringBuilder().append("a").append("b").append("c").toString();
编译class
String s1 = "abc";
String s2 = "a" + "b" + "c";
字节件ByteCode
L0
LINENUMBER 6 L0
LDC "abc"
ASTORE 1
L1
LINENUMBER 7 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "a"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "b"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "c"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
使用“+”进行字符串常量的拼接在编译时就已经完成,而使用 StringBuilder 进行字符串拼接需要在运行时完成。所以单纯的字符串常量拼接“+”的效率 应该高于 StringBuilder
2. 拼接字符串和引用
测试类
6 String s1 = "a";
7 String s2 = new StringBuilder().append(s1).append("b").append("c").toString();
8 String s3 = s1 + "b" + "c";
编译class
String s1 = "a";
String s2 = s1 + "b" + "c";
String s3 = s1 + "bc";
字节码ByteCode
L0
LINENUMBER 6 L0
LDC "a"
ASTORE 1
L1
LINENUMBER 7 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "b"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "c"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 2
L2
LINENUMBER 8 L2
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "bc"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 3
从字节码可以看出“+”拼接的字符串引用底层还是使用StringBuilder
参考链接
Java中的String,StringBuilder,StringBuffer三者的区别?
java String中的intern和String a="abc"的区别是什么?
以上是关于JAVA面试集锦String相关的经典面试题的主要内容,如果未能解决你的问题,请参考以下文章