Java面试String相关的问题
文章目录
- Java面试String相关的问题
- 1.字符型常量和字符串常量的区别
- 2.什么是字符串常量池?
- 3.String 是最基本的数据类型吗
- 4.String有哪些特性
- 5.String不可变的吗
- 5.是否可以继承String类
- 6.String str="i" 与 String str=new String(“i”)一样吗?
- 7.String s = new String(“xyz”) 创建了几个字符串对象?
- 8.在Java当中.equals()方法和==的不同?
- 9.如何将字符串反转?
- 10.数组有没有length()方法?String有没有length()方法?
- 11.String 类的常用方法都有那些?
- 12.在使用 HashMap 的时候,用 String 做 key 有什么好处?
- 13.String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的
1.字符型常量和字符串常量的区别
- 字符型常量是 char 类型,表示单个字符。
- 字符串常量是 String 类型,表示一串字符。
- 字符型常量用单引号 ‘’ 括起来,字符串常量用双引号 “” 括起来。
- 字符型常量只能包含一个字符,字符串常量可以包含多个字符。
- 字符型常量可以进行字符级别的操作,字符串常量可以进行字符串级别的操作。
char c = 'a';
String str = "Hello";
System.out.println(c); // 输出 'a'
System.out.println(str); // 输出 "Hello"
// 以下示例会报错
//c = "123";
//str = '4';
2.什么是字符串常量池?
字符串常量池是Java运行时数据区中的一个特殊区域,用于存储字符串字面量。它通过确保每个字符串字面量在内存中只存在一个副本来提高性能和节省内存。
// s1和s2都是指向常量池中的"hello"对象的
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // 输出 true,因为 s1 和 s2 指向的是同一个对象
// s3和s4在堆内存中各自创建了新的对象
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3 == s4); // 输出 false,因为 s3 和 s4 是两个不同的对象
3.String 是最基本的数据类型吗
不是。Java 中的基本数据类型只有 8 个 :byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(referencetype),Java 5 以后引入的枚举类型也算是一种比较特殊的引用类型。
4.String有哪些特性
-
不可变性:String 对象一旦创建,其内容就不能被改变。任何对 String 对象的操作,如拼接、替换等,都会返回一个新的 String 对象,而不会修改原始对象。
-
字符串常量池:Java中的字符串常量池用于存储字符串字面量。当创建一个字符串字面量时,Java会首先检查字符串常量池,如果常量池中已经存在相同内容的字符串,那么就直接返回该字符串的引用,否则会在常量池中创建一个新的字符串对象。
-
重写了 equals() 和 hashCode() 方法:String 类重写了 equals() 方法,使其比较的是字符串的内容,而不是对象的内存地址。同时,String 类也重写了 hashCode() 方法,用于生成字符串的哈希码。
-
不可变性带来的线程安全:由于 String 对象是不可变的,所以它们是线程安全的。这意味着多个线程可以共享同一个 String 对象,而不需要担心数据竞争或线程安全问题。
5.String不可变的吗
不可变。String 对象被创建,它的值就不能被改变。任何对 String 对象的操作,如拼接、替换等,都会返回一个新的 String 对象,而不会修改原始对象。
示例代码:
String str = "Hello";
str = str + " World";
System.out.println("str=" + str);
-
结果:
str=Hello World
-
解析:
-
实际上,原来String的内容是不变的,只是str由原来指向"Hello"的内存地址转为指向"Hello World"的内存地址而已,也就是说多开辟了一块内存区域给"Hello World"字符串。
5.是否可以继承String类
答:String类是final类,不可以被继承。
6.String str=“i” 与 String str=new String(“i”)一样吗?
答:不一样,因为内存的分配方式不一样。String str="i"会将其分配到常量池中;
而String str=new String(“i”)则会被分配到堆内存中。
7.String s = new String(“xyz”) 创建了几个字符串对象?
答:一共创建了两个字符串对象。
- 字符串字面量对象:
"xyz"是一个字符串字面量,它在字符串常量池中创建。字符串常量池是Java运行时数据区中的一个特殊区域,用于存储字符串字面量,以避免重复创建相同的字符串对象。 - 通过 new 关键字创建的字符串对象:new String(“xyz”) 这部分代码会在堆内存中创建一个新的字符串对象。这个新对象的内容与字符串常量池中的 “xyz” 相同,但它们是两个不同的对象。
因此,这行代码总共创建了两个字符串对象。
8.在Java当中.equals()方法和==的不同?
- == 比较的是对象的内存地址。
- equals() 比较的是对象的内容。
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // 输出 true,因为 s1 和 s2 指向字符串常量池中的同一个对象
String s3 = new String("hello");
String s4 = new String("hello");
System.out.println(s3 == s4); // 输出 false,因为 s3 和 s4 是两个不同的对象
System.out.println(s1.equals(s3)); // 输出 true,因为 s1 和 s3 的内容相同
System.out.println(s1.equals(s4)); // 输出 true,因为 s1 和 s4 的内容相同
9.如何将字符串反转?
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
示例代码:
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("abcdefg");
System.out.println(stringBuffer.reverse()); //gfedcba
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("abcdefg");
System.out.println(stringBuilder.reverse()); //gfedcba
10.数组有没有length()方法?String有没有length()方法?
- 数组没有 length()方法 ,有 length 的属性。
- String 有 length()方法。JavaScript中,获得字符串的 。
- 长度是通过 length 属性得到的。
int[] arr = {1, 2, 3};
System.out.println(arr.length); // 输出 3
String str = "hello";
System.out.println(str.length()); // 输出 5
11.String 类的常用方法都有那些?
- indexOf():返回指定字符的索引。
- charAt():返回指定索引处的字符。
- replace():字符串替换。
- trim():去除字符串两端空白。
- split():分割字符串,返回一个分割后的字符串数组。
- getBytes():返回字符串的 byte 类型数组。
- length():返回字符串长度。
- toLowerCase():将字符串转成小写字母。
- toUpperCase():将字符串转成大写字符。
- substring():截取字符串。
- equals():字符串比较。
12.在使用 HashMap 的时候,用 String 做 key 有什么好处?
HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。
示例代码:
// 创建一个 HashMap 对象
HashMap<String, Integer> map = new HashMap<>();
map.put("one", 1);
map.put("two", 2);
map.put("three", 3);
// 使用 get 方法获取键对应的值
System.out.println(map.get("one")); // 输出 1
System.out.println(map.get("two")); // 输出 2
System.out.println(map.get("three")); // 输出 3
在上面的示例中,String 对象 “one”、“two” 和 “three” 被用作 HashMap 的键。由于 String 是不可变的,所以 HashMap 可以安全地使用它们作为键。
13.String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的
可变性
- String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。
- StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
线程安全性
- String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
性能
- 每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结
- 如果要操作少量的数据用 = String
- 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
ngBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结
- 如果要操作少量的数据用 = String
- 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
- 多线程操作字符串缓冲区下操作大量数据 = StringBuffer

796

被折叠的 条评论
为什么被折叠?



