Java基础面试——String“==”问题

来源:互联网 发布:mysql charindex 编辑:程序博客网 时间:2024/06/16 00:02

1.面试题一:

public static void main(String[] args) {    String a = "helloworld";    String c = "hello"+"world";    if(a == c){        System.out.println("a=c");    }else{        System.out.println("a!=c");    }}

输出:a=c
解释:JVM在编译时会将 String c = “hello”+”world”; 优化成 “helloworld”。

  • 然后编译器在常量池中查找是否有值相同的变量,存在则返回字符串的引用,不存在就将字符串存到常量池中,然后返回存入后字符串的引用。

所以,该题在常量池中查找“helloworld”,发现已存在,则返回常量池中的“helloworld”的引用,这样,String a和String c就指向了同一个引用,即a==c;

补充:

  • 另外,其实正常情况下,执行 String c = “hello”+”world”; 这句话,会产生2个临时对象“hello”和“world”,最后的对象“helloworld”才会赋给String c,但由于JVM编译时优化,所以不会这样,而是会创建一个新对象StringBuilder,然后append()拼接,这样省去了多个临时对象的产生。
  • 也就是说对于用“+”连接字符串时,JVM会创建一个StringBuilder并调用append()拼接字符串,然后使用toString()返回拼接好的字符串。如果连接的不止字符串,比如String c = “hello”+ 2;将String类型的“hello”和int型的“2”连接在一起,append()的各种重载方法也会处理好。
  • 那么这样就能解释为什么非常不推荐类似这样的写法:

    public static void main(String[] args) {String str = "ha";    for(int i = 0; i < 100; i++){        str += "ha";    }}

    这个程序循环使用“+”会重复的创建许多个StringBuilder,性能降低,浪费内存,所以应该一开始就使用StringBuilder,然后不断append()。

2.面试题二:

public static void main(String[] args) {    String a = "helloworld";    String b = "world";    String c = "hello" + b;    if(a == c){        System.out.println("a=c");    }else{        System.out.println("a!=c");    }}

输出:a!=c
解释:编译 String c = “hello” + b; 这行代码时并不会像上面一样优化,b是一个变量,不是已知字符串字面量,所以编译器无法做出优化,到运行时才能知道b是什么,然后做拼接,最后保存为一个新地址,所以与String a不是同一个地址,即a != c。

3.面试题三:

public static void main(String[] args) {    String a = "helloworld";    final String b = "world";    String c = "hello" + b;    if(c == a){        System.out.println("c=a");    }else{        System.out.println("c!=a");    }}

输出:c=a
解释:当String b被final修饰为常量,会在常量池中有一个副本,编译时可以直接取到,而不是像面试题二中String b是不确定的,所以JVM也会将String c优化为“helloworld”,然后和String a指向同一个地址,即c==a。

4.面试题四:

public static void main(String[] args) {    String a = "helloworld";    final String b = getString();    String c = "hello" + b;    if(c == a){        System.out.println("c=a");    }else{        System.out.println("c!=a");    }}static String getString(){    return "world";}

输出:c!= a
解释:虽然String b是final,但是编译时是无法确定b的值的,那么就不会JVM编译时优化,只有在运行时才能知道getString()会返回什么,然后拼接成为String c,所以String a和String c不会是同一个地址,即c != a。

补充:
引号声明的字符串是会直接在字符串常量池中生成的。例如:

  • String s = new String(“hello”)

则会生成常量池中的“hello” 和堆空间中的字符串对象s。

原创粉丝点击