java常见面试题之字符串


同学去面试的java笔试题很多基础的都是字符串的题目,有时候还比较难,很容易弄错,这里我做一下总结

字符串常量池机制

首先介绍下字符串常量池机制

字符串常量池目的

jvm为了提高性能和减少开销,实现数据共享

1.为字符串开辟一个字符串常量池(存在方法区)
2.创建字符常量时,首先确认字符串常量池是否存在该字符串
3.存在该字符串,则返回应用实例,不存在,实例化该字符串并放入池中

接下来我们看下例题把

1.String str=new String(“abcd”);实例化了几个字符串对象

public static void main(String[] args) {
    
    
        String str=new String("abcd");
    }

观察命令

javac xxx。class
javap -verbose xxx

在这里插入图片描述

答案

两个或者一个

如果在执行该代码之前常量池中没有abcd那么就创建了两个字符串对象,一个在常量池,另一个在堆中,如果原来已经存在常量池中则,只会在堆中创建一个

大家也可以看见原来常量池里面有没有会影响后面的判断,因此我们后面的题目都默认当做原来常量池中不存在该字符串

2.String str=“a”+"b"产生了几个字符串对象

    public static void main(String[] args) {
    
    

    String str="a"+"b";

    }

在这里插入图片描述

扫描二维码关注公众号,回复: 13281120 查看本文章

答案

一个

虚拟机看到两个字符串或多个字面量字符串直接相加会对其进行优化直接生成一个字符串到常量池中(常量池“ab”)

3.String str=“a”+new String(“b”) 产生了几个字符串对象

  public static void main(String[] args) {
    
    

   String str="a"+new String("b");

    }

在这里插入图片描述

答案

四个

一共创建了4个字符串对象,常量池中有两个(分别为a和b)堆中有两个(b和StringBuilder)

4.String str1=new String(“abc”); String str2=new String(“abc”);产生了几个字符串对象

 public static void main(String[] args) {
    
    

        String str1=new String("abc");
        String str2=new String("abc");
    }

在这里插入图片描述

答案

三个

一共创建了3个字符串对象,常量池中有1个(“abc”)堆中有两个(“abc”)

5.String str=new String(“a”)+new String(“a”);产生了几个字符串对象

   public static void main(String[] args) {
    
    
        String str=new String("a")+new String("a");

    }

在这里插入图片描述

答案

四个

一共创建了4个字符串对象,一个在常量池中(“a”)堆中3个(其中一个是StringBuilder,和两个"a")

6.String str=new String(“a”)+new String(“b”);产生了几个字符串对象

public static void main(String[] args) {
    
    
        String str=new String("a")+new String("b");

    }

在这里插入图片描述

答案

五个

一共创建了5个字符串对象,一个在常量池中(“a”,“b”)堆中3个(其中一个是StringBuilder,和一个"a",一个“b”)

注意

使用引号包含文本的方式创建对象之间使用"+“连接,产生的对象会被加到String常量池中,对于所有包含new方式创建的字符串对象的”+"连接表达式,所产生的新对象不会加入到产量池中
当字符串引用之间使用+号拼接的时候,系统底层会自动创建一个StringBuilder对象然后再调用其append方法完成拼接,拼接后再调用tostring方法转换成string类型

7.String s1=“abcd”;String s2=“ab”+“cd”; System.out.println(s1==s2);

public static void main(String[] args) {
    
    
        String s1="abcd";
        String s2="ab"+"cd"; //字面量拼接
        System.out.println(s1==s2);
    }

答案

true

当执行 string s1=“abcd” 的时候会在常量池中创建一个“abcd”,
当执行 String s2=“ab”++"cd"的时候会将两个字符串常量拼接生成“abcd”,先检查常量池中有无“abcd”
若常量池中以存在则直接返回应用,否者保存到常量池中

8.下面程序的运行结果是

String str1 = "hello";
String str2 = "he" + new String("llo");
System.err.println(str1 == str2);//flase

答案

false

String str1 = “hello”;这里的str1指的是方法区的字符串常量池中的“hello”,编译时期就知道的; String str2 = “he” + new String(“llo”);这里的str2必须在运行时才知道str2是什么,所以它是指向的是堆里定义的字符串“hello”,所以这两个引用是不一样的。

如果用str1.equal(str2),那么返回的是True;因为两个字符串的内容一样

在这里插入图片描述

9. String s = “Hello”;s = s + " world!";这两行代码执行后,原始的 String 对象中的内容到底变了没有?

没有。因为 String 被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。在这段代码中,s 原先指
向一个 String 对象,内容是 “Hello”,然后我们对 s 进行了“+”操作,那么 s 所指向的那个对象是否发生了改变呢?
答案是没有。这时,s 不指向原来那个对象了,而指向了另一个 String 对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是 s 这个引用变量不再指向它了。
在这里插入图片描述
见了这么多例子,大家可以试试下面这题

10.请说出下面程序的输出

		String s1 = "Programming";
		String s2 = new String("Programming");
		String s3 = "Program";
		String s4 = "ming";
		String s5 = "Program" + "ming";
		String s6 = s3 + s4;
		System.out.println(s1 == s2); //false
		System.out.println(s1 == s5); //true
		System.out.println(s1 == s6); //false
		System.out.println(s1 == s6.intern()); //true
		System.out.println(s2 == s2.intern()); //false

String 对象的 intern()方法会得到字符串对象在常量池中对应的版本的引用(如果常量池中有一个字符串与String 对象的 equals 结果是 true),如果常量池中没有对应的字符串,则该字符串将被添加到常量池中,然后返回常量池中字符串的引用

11. 下面程序运行结果

public class Example {
    
    
    String str=new String("good");
    char[] ch={
    
    'a','b','c'};

    public static void main(String[] args) {
    
    
        Example example = new Example();
        example.change(example.str,example.ch);
        System.out.print(example.str+"and");
        System.out.print(example.ch);
    }

    public void change(String str,char ch[]){
    
    
        str="test ok";
        ch[0]='g';
    }
}
goodandgbc

首先说下String确实是个不可变对象,这个不可变是JDK特有的,写JAVA的人特意针对的 但是这与本题无关,题目中的形参str只是原引用ex.str的一个引用副本,传的是一个副本地址值,这个值与ex.str地址值是不一样的,但是它们同时指向了堆中的对象new String(“good”),当你在函数中改变形参也就是地址的副本值也就是这句str=“test ok"只是将副本地址指向常量"test ok”,并没有改变原ex.str的指向方向,它还是指向对象new String(“good”)的 char数组与String一样传的也是地址的副本,但是关键是形参ch它没有新的指向 ch[0]只是ch在指向原对象时改变了对象的内部结构, 所以在ex.ch指向与它是同一个对象的情况下当然也会随之变化

最后谢谢大家观看,如果有什么不对的地方麻烦指出来,祝大家秋招找到好工作

猜你喜欢

转载自blog.csdn.net/qq_44866153/article/details/120358610