1、字节和字符的区别?

字节是存储容量的基本单位;
字符是数字、字⺟、汉字以及其他语⾔的各种符号;
1 字节 = 8 个⼆进制单位,⼀个字符由⼀个字节或多个字节的⼆进制单位组成。

2、String 为什么要设计为不可变类?

  1. 字符串常量池的需要:字符串常量池是 Java 堆内存中⼀个特殊的存储区域, 当创建⼀个 String 对象时,假如 此字符串值已经存在于常量池中,则不会创建⼀个新的对象,而是引用已经存在的对象;
  2. 允许 String 对象缓存 HashCode:Java 中 String 对象的哈希码被频繁地使⽤, ⽐如在 HashMap 等容器中。 字符串不变性保证了 hash 码的唯⼀性,因此可以放⼼地进⾏缓存。这也是⼀种性能优化⼿段,意味着不必每次都 去计算新的哈希码;
  3. String 被许多的 Java 类(库)用来当做参数,例如:网络连接地址 URL、文件路径 path、还有反射机制所需要 的 String 参数等, 假若 String 不是固定不变的,将会引起各种安全隐患。

    3、String、StringBuilder、StringBuffer 的区别?

    String:用于字符串操作,属于不可变类;

    补充:String 不是基本数据类型,是引⽤类型,底层用 char 数组实现的

StringBuilder:与 StringBuffer 类似,都是字符串缓冲区,但线程不安全;
StringBuffer:也⽤于字符串操作,不同之处是 StringBuffer 属于可变类,对⽅法加了同步锁,线程安全。

StringBuffer的补充 说明:StringBuffer 中并不是所有方法都使用了 Synchronized 修饰来实现同步:

执⾏效率:StringBuilder > StringBuffer > String

4、String 字符串修改实现的原理?

当用 String 类型来对字符串进行修改时,其实现方法是首先创建⼀个 StringBuffer,其次调用 StringBuffer 的 append() 方法,最后调用 StringBuffer 的 toString() 方法把结果返回。

5、String str = “i” 与 String str = new String(“i”) ⼀样吗?

不⼀样,因为内存的分配方式不一样。

  • String str = “i” 的方式,Java 虚拟机会将其分配到常量池中;
  • String str = new String(“i”) 则会被分到堆内存中。
    1. public class StringTest {
    2. public static void main(String[] args) {
    3. String str1 = "abc";
    4. String str2 = "abc";
    5. String str3 = new String("abc");
    6. String str4 = new String("abc");
    7. System.out.println(str1 == str2); // true
    8. System.out.println(str1 == str3); // false
    9. System.out.println(str3 == str4); // false
    10. System.out.println(str3.equals(str4)); // true
    11. }
    12. }
  1. 在执行 String str1 = “abc” 的时候,JVM 会⾸先检查字符串常量池中是否已经存在该字符串对象,如果已经存在, 那么就不会再创建了,直接返回该字符串在字符串常量池中的内存地址;如果该字符串还不存在字符串常量池中, 那么就会在字符串常量池中创建该字符串对象,然后再返回。所以在执⾏ String str2 = “abc” 的时候,因为字符串 常量池中已经存在“abc”字符串对象了,就不会在字符串常量池中再次创建了,所以栈内存中 str1 和 str2 的内存地 址都是指向 “abc” 在字符串常量池中的位置,所以 str1 = str2 的运⾏结果为 true。
  2. 在执⾏ String str3 = new String(“abc”) 的时候,JVM 会⾸先检查字符串常量池中是否已经存在“abc”字符串,如果已经存在,则不会在字符串常量池中再创建了;如果不存在,则就会在字符串常量池中创建 “abc” 字符串对象, 然后再到堆内存中再创建⼀份字符串对象,把字符串常量池中的 “abc” 字符串内容拷⻉到内存中的字符串对象中, 然后返回堆内存中该字符串的内存地址,即栈内存中存储的地址是堆内存中对象的内存地址。String str4 = new String(“abc”) 是在堆内存中⼜创建了⼀个对象,所以 str 3 == str4 运⾏的结果是 false。

str1、str2、str3、str4 在内存中的存储状况如下图所示:
Snipaste_2021-12-24_15-36-25.png

6、final 修饰 StringBuffer后还可以 append 吗?

可以。final 修饰的是⼀个引用变量,那么这个引用始终只能指向这个对象,但是这个对象内部的属性是可以变化的。