Java中String面试难题

前置知识

  • String str = "xxx"到底new了几个对象?
  • new String("xxx")到底new了几个对象?
  • new String("xxx") + new String("xx") 到底new了几个对象?
  • string.intern()在不同jdk版本的变化?

String str = "xxx"到底new了几个对象?

  • 下面通过字节码的角度来观察,String str = "xxx"的字节码如下
0 ldc #2 <xxx>
2 astore_1
3 return

答案:String str = "xxx"一共创建了一个对象,返回的是字符串常量池中的地址,其中ldc指令会在字符串常量池中创建一个对象

思考?
  • new String(char[] chars)new String(byte[] bytes)创建了几个对象?;

答案:只创建了一个对象,并没有去调用ldc指令,即在常量池中不存在这个字符串对象,字节码如下:

    public static void main(String[] args) {
        char[] chars = new char[]{'x','x','x'};
        String str = new String(chars);
    }
 0 iconst_3
 1 newarray 5 (char)
 3 dup
 4 iconst_0
 5 bipush 120
 7 castore
 8 dup
 9 iconst_1
10 bipush 120
12 castore
13 dup
14 iconst_2
15 bipush 120
17 castore
18 astore_1
19 new #2 <java/lang/String>
22 dup
23 aload_1
24 invokespecial #3 <java/lang/String.<init>>
27 astore_2
28 return

new String(“xxx”)到底new了几个对象?

    public static void main(String[] args) {
        String str = new String("xxx");
    }
  • 反编译后的字节码如下
 0 new #2 <java/lang/String>
 3 dup
 4 ldc #3 <xxx>
 6 invokespecial #4 <java/lang/String.<init>>
 9 astore_1
10 return

答案:new String(“xxx”)一共创建了2个对象,一个对象在堆中,一个在常量池中,并且返回的是堆中的地址

new String("ab") + new String("c") 到底new了几个对象?

    public static void main(String[] args) {
        String str = new String("ab") + new String("c");
    }
  • 反编译后的字节码如下
 0 new #2 <java/lang/StringBuilder>                      // 第一个
 3 dup
 4 invokespecial #3 <java/lang/StringBuilder.<init>>
 7 new #4 <java/lang/String>                             // 第二个
10 dup
11 ldc #5 <ab>                                          // 第三个
13 invokespecial #6 <java/lang/String.<init>>
16 invokevirtual #7 <java/lang/StringBuilder.append>
19 new #4 <java/lang/String>                             // 第四个
22 dup
23 ldc #8 <c>                                           // 第五个
25 invokespecial #6 <java/lang/String.<init>>
28 invokevirtual #7 <java/lang/StringBuilder.append>
31 invokevirtual #9 <java/lang/StringBuilder.toString>   // 第六个
34 astore_1
35 return

答案:new String("xxx") + new String("xx")一共创建了6个对象,凡是涉及到变量的拼接操作,都会创建一个StringBuilder对象,转为String调用的是StringBuilder.toString()方法,返回的是StringBuilder.toString()下new String()堆中的地址

思考?

字符串对象"abc"在字符串常量池中吗?

答案:

  • 字符串"abc"不存在字符串常量池中,查看StringBuilder.toString()方法源码如下,因为new String(char[] chars),上面有讲到

    /**
     * The value is used for character storage.
     */
    char[] value;

    // ...

    @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }

string.intern()在不同jdk版本的变化?

string.intern()方法的作用

  • intern()是String中的静态方法,调用该方法会先从字符串常量池中判断该字符串是否存在,若存在则直接返回字符串常量池中的地址,若不存在则在字符串常量池中创建这个字符串对象,然后再返回。

  • 从jdk7开始,字符串常量池从方法区移动到堆中

  • jdk6及以前:调用intern方法符合上面的概述。

  • jdk7及以后:在调用intern方法时,若在字符串常量池中不存在这个字符串对象,但是在堆中存在这个字符串对象,这个时候并不会在字符串常量池中创建这个对象,而是直接引用这堆中这个字符串对象的地址,以达到节省空间的效果。

    public static void main(String[] args) {
        // 以字面量的方式定义字符串,会在字符串常量池中创建对象
        String abc = new StringBuilder("abc").toString();
        // StringBuilder.toString(): 不会在字符串常量池中创建"def"字符串对象,但在堆中创建了这个"def"字符串对象
        String def = new StringBuilder("de").append("f").toString();

        // jdk7及以后: 若在堆中存在这个字符串对象,但在字符串常量池中不存在
        //              这个时候会直接引用堆中字符串对象的地址
        abc.intern();
        def.intern();
        System.out.println(abc == "abc"); // false
        System.out.println(def == "def"); // true
    }

面试题

    @Test
    public void test1(){
        String s1 = "javaEE";
        String s2 = "hadoop";
        String s3 = "javaEE" + "hadoop";
        String s4 = "javaEEhadoop";
        String s5 = "javaEE" + s2;
        String s6 = s1 + "hadoop";
        String s7 = s1 + s2;

        System.out.println(s3 == s4); // true
        System.out.println(s3 == s5); // false
        System.out.println(s3 == s6); // false
        System.out.println(s3 == s7); // false
        System.out.println(s5 == s6); // false
        System.out.println(s6 == s7); // false

        String s8 = s6.intern();
        System.out.println(s3 == s8); // true
    }

    @Test
    public void test2(){
        String s1 = new String("a");
        s1.intern();
        String s2 = "a";
        System.out.println(s1 == s2); // jdk6及以前: false jdk7及以后: false

        String s3 = new String("a") + new String("a");
        s3.intern();
        String s4 = "aa";
        System.out.println(s3 == s4); // jdk6及以前: false jdk7及以后: true

    }

    @Test
    public void test3(){
        String s3 = new String("a") + new String("a");
        String s4 = "aa";
        String s5 = s3.intern();
        System.out.println(s3 == s4); // false
        System.out.println(s4 == s5); // true

    }

    @Test
    public void test4(){
        String s1 = new String("a") + new String("a");
        String s2 = s1.intern();
        System.out.println(s1 == "aa"); // jdk6及以前: false jdk7及以后: true
        System.out.println(s2 == "aa"); // jdk6及以前: false jdk7及以后: true

    }

    @Test
    public void test5(){
        String x = "aa";
        String s1 = new String("a") + new String("a");
        String s2 = s1.intern();
        System.out.println(s1 == "aa"); // false
        System.out.println(s2 == "aa"); // true

    }

    @Test
    public void test6(){
        String s1 = new String("ab");
        s1.intern();
        String s2 = "ab";
        System.out.println(s1 == s2); // false
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值