‹3› Java面试必备知识点:『字符串』

字符串是什么?

String 是标准的不可变类(immutable),对它的任何改动,其实就是创建了一个新对象,再把引用指向该对象;String 对象赋值之后就会在常量池中缓存,如果下次创建会判定常量池是否已经有缓存对象,如果有的话直接返回该引用给创建者。

String 类的修饰符

public final class String
    	implements java.io.Serializable, Comparable<String>, CharSequence {}

字符串创建的方式有哪些?

String 的两种创建方式

String str = "Cat"; // 在【常量池】中直接创建。
String str = new String("Dog"); // 在【常量池】创建后,再在【堆】上创建。

字符串拼加的三种方式:

String s1 = "Cat" + "Cat"; // 常量池

String s2 = s1 += "Cat"; // 堆

String s3 = s1 + "Cat"; // 堆

JVM 也会对 String 进行特殊处理,以此来提供程序的运行效率,比如以下代码:

String str = "A" + "Cat";
String str2 = "ACat";
System.out.println(str == str2); // true

字符串截取的方式有哪些?

字符串截取使用 substring() 方法,使用如下:

String str = "abcdef";
System.out.println(str.substring(2)); // cdef (2~length)
System.out.println(str.substring(2,str.length())); // cde (2~length-1)

字符串格式化的方式有哪些?

字符串格式化可以让代码更简洁更直观,如果使用 “+” 号拼接的话很容易出错,这个时候 静态方法 String.format() 就派上用场了,代码如下:

String str = String.format("我叫%s,今年%d岁,喜欢%s", "周杰伦", 40, "唱歌");

转换符说明列表:

转换符说明
%s字符串类型
%d整数类型(十进制)
%c字符类型
%b布尔类型
%x整数类型(十六进制)
%o整数类型(八进制)
%f浮点类型
%e指数类型
%%百分比类型
%n换行符

字符串对比的方式有哪些?

根据前面的知识我们知道,使用 String 和 new String 声明的对象是不同的,那有没有简单的方法,可以忽略它们的创建方式(有没有 new)而只对比它们的值是否相同呢?

答案是肯定的,使用 equals() 方法可以直接比较字符串的值,代码如下:

String s1 = "A" + "Cat"; // 常量池
String s2 = "A"; // 常量池
s2 += "Cat"; // 堆
String s3 = "ACat"; // 常量池
System.out.println(s1.equals(s2)); 
System.out.println(s1.equals(s3)); 
System.out.println(s2.equals(s3)); 

以上使用 equals 对比的结果都为 true

如果要忽略字符串的大小写对比值可以使用 equalsIgnoreCase()

字符串的方法有哪些?

"a".compareTo("able to") // 首字母相同,比较长度:-6
"a".compareTo("z") // 首字母不相同,比较首字母Unicode值:-25
 
byte[] bytes = "cat".getBytes();
char[] chars = "cat".toCharArray();

char[] chars = {'A', 'B', 'C', 'D', 'E', 'F'};
String.valueOf(chars); // ABCDEF
String.valueOf(chars, 0, 3); // ABC

"ABCDEF".substring(1) // BCDEF
"ABCDEF".substring(1, 3) // BC
    
"It's a".concat(" orange cat") // It's a orange cat
    
"cat".replace("cat", "dog") // dog
    
"  dog   ".trim() // dog
    
String[] strings = "a`b`c`d`e`t".split("`");
System.out.println(strings[2]+strings[0]+strings[5]); // cat
    
"cat".charAt(1) // a
"cat".codePointAt(1) // 97
    
"cat cat".indexOf('c') // 0
"cat cat".lastIndexOf('c') // 4 
    
"cat".hashCode() // 98262  
    
"cat".length() // 3
    
"cat".contains(new String("a")) // true
"cat".contains(new StringBuilder("a")) //true
    
"cat".startsWith("c") // true
"cat".endsWith("t") // true
    
"".isEmpty() // true
    
String.format(" %s,%g块,你欠了%d年了", "王南", 1.25, 10)
String.format("%n %tc", new Date())

字符串:

1.String 属于基础数据类型吗?

答:String 不是基础数据类型,它是从堆上分配来的。基础数据类型有 8 个,分别为:boolean、byte、short、int、long、float、double、char。

2.什么是字符串常量池?

答:字符串常量池是存储在 Java 堆内存中的字符串池,是为防止每次新建字符串带的时间和空间消耗的一种解决方案。在创建字符串时 JVM 会首先检查字符串常量池,如果字符串已经存在池中,就返回池中的实例引用,如果字符串不在池中,就会实例化一个字符串放到池中并把当前引用指向该字符串。

3.String s=new String(“cat”) 创建了几个对象?

答:创建了一个或两个对象。字符串先出现在常量池,然后才出现在堆。

  • 如果常量池中已经有了字符串 “cat”,就只会创建一个堆中的对象 ”cat“;
  • 如果常量池中没有字符串 ”cat“,则先会在常量池中创建一个对象 ”cat“,再创建一个堆中的对象。

4. String 不可变性都有哪些好处?

答:不可变的好处如下。

  • 多线程安全,因为字符串是不可变的,所以同一个字符串实例可以被多个线程共享,保证了多线程的安全性;
  • 适合做缓存的 key,因为字符串是不可变的,所以在它创建的时候哈希值就被缓存了,不需要重新计算速度更快,所以字符串很适合作缓存的中的 key。
  • 只有当字符串是不可变的,字符串常量池才能实现,字符串池的实现可以在运行时节约很多堆空间,因为不同的字符串变量都指向池中的同一个字符串;
  • 可以避免一些安全漏洞,比如在 Socket 编程中,主机名和端口都是以字符串的形式传入,因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞;

5. String 是否可以被继承?为什么?

答:String 不能被继承。因为 String 被声明为 final(最终类),所以不能被继承,源码如下(JDK 8)。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    
}

6.不可变对象 是什么?

不可变对象(Immutable Object):对象一旦被创建后,对象所有的状态及属性在其生命周期内不会发生任何变化。例如,String类和包装类。

以 String 类和 StringBuffer 类为例:

String s = "123";
s.replace("123", "999");
System.out.println(s);

StringBuffer sb = new StringBuffer("123");
sb.replace(0,3,"999");
System.out.println(sb);

输出结果:

123
999

我们可以看出来,String 执行 replace 方法后,String 对象本身没有发生改变;StringBuffer 执行 replace 方法后,StringBuffer 对象发生了改变。

字符串方法:

1.以下可以正确获取字符串长度的是?

A:str.length
B:str.size
C:str.length()
D:str.size()

答:C

题目解析:字符串没有 length 属性,只有 length() 方法。

2.以下代码输出的结果是?

String str = "cat";
str.substring(0,1);
System.out.println(str);

A:c
B:ca
C:cat

答:C

题目解析:因为 String 的 substring() 方法不会修改原字符串内容,所以结果还是 cat。

3.以下使用 substring 执行的结果什么?

String str = "abcdef";
System.out.println(str.substring(3, 3));

答:""(空)

4.判定字符串是否为空,有几种方式?

答:常用的方式有以下两种。

  • str.equals("")
  • str.length()==0

5.String 对象的 intern() 有什么作用?

答:intern() 方法用于查找常量池中是否存在该字符值,如果常量池中不存在则先在常量池中创建,如果已经存在则直接返回。

示例代码:

String s1 = "laowang";
String s2 = s1.intern();
System.out.println(s1 == s2);  // true

比较:

1."==" 和 equals 的区别是什么?

① “==” 解读

  • 基本数据类型进行值比较;
  • 引用类型进行引用比较。

② equals 解读

  • equals 本质上就是 ==
  • 不过 String 和 Integer 等类重写了 equals 方法,把引用类型的的引用比较改成了值比较。

看下面的代码就明白了:

Cat c1 = new Cat("喵~");
Cat c2 = new Cat("喵~");
System.out.println(c1.equals(c2));  // false(Object类默认的equals方法,本质是==)

String s1 = new String("喵~");
String s2 = new String("喵~");
System.out.println(s1.equals(s2));  // true(String类重写的equals方法)

2.以下字符串对比的结果是什么?

String s1 = "A" + "Cat";
String s2 = "A";
s2 += "Cat";
String s3 = "ACat";
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s3);

答:false true false

题目解析:String s1 = “hi,” + “lao” + “wang” 代码会被 JVM 优化为:String s1 = “hi,laowang”,这样就和 s3 完全相同,s1 创建的时候会把字符 “hi,laowang” 放入常量池,s3 创建的时候,常量池中已经存在对应的缓存,会直接把引用返回给 s3,所以 s1==s3 就为 true,而 s2 使用了 += 其引用地址就和其他两个不同。

StringBuffer:

1.以下 String 传值修改后执行的结果是什么?

public static void main(String[] args) {
  String str = new String("ACat");
  change(str);
  System.out.println(str);
}
public static void change(String str) {
    str = "ADog";
}

答:ACat ,如果输出change方法返回的变量str会得到“ADog”。

2.以下 StringBuffer 传值修改后的执行结果是什么?

public static void main(String[] args) {
  StringBuffer sf = new StringBuffer("A");
  change(sf);
  System.out.println(sf);
}
public static void change(StringBuffer sf){
    sf.append("laowang");
}

答:ACat

题目解析:String 为不可变类型,在方法内对 String 修改的时候,相当修改传递过来的是一个 String 副本,所以 String 本身的值是不会被修改的;而 StringBuffer 为可变类型,参数传递过来的是对象的引用,对其修改它本身就会发生改变。

3.String、StringBuffer、StringBuilder 的区别?

答:字符串相关类型主要有这三种:String、StringBuffer、StringBuilder,其中 StringBuffer、StringBuilder 都是可以变的字符串类型StringBuffer 在字符串拼接时使用 synchronized 来保障线程安全,因此在多线程字符串拼接中推荐使用 StringBuffer。

以下是 String、StringBuffer、StringBuilder 的区别:

  • String
    • 不可变对象;
    • 使用 不可变对象 来保证线程安全;
    • 性能最低,每次修改都创建新对象;
    • 重写了 equals 方法。
  • StringBuffer
    • 可变对象;
    • 使用 synchronized 来保证线程安全;
    • 性能优于 String,但不如 StringBuilder,因为使用了同步。
  • StringBuilder
    • 可变对象;
    • 非线程安全;
    • 性能最高。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值