一些常见的面试题:

String a = "hello2";
String b = "hello" + 2;
System.out.println(a == b);

a == b输出true。很明显b在编译时就被优化成“hello2”,因此在运行期间,a和b指向的是统一对象

String a = "hello2";
String b = "hello";
String c = b + 2;
System.out.println(a == c);

a==c输出false,因为b是变量,不会在编译期间被优化,不会把 b + 2当成字符常量来处理的。这种情况生成的对象实际上保存在堆上。

String a = "hello2";
final String b = "hello";
String c = b + 2;
System.out.println(a == c);

输出:true。被final修饰的变量,会在class文件常量池中保存一个副本。那么b + 2在编译期间会被优化成”hello” + 2。也可以把final修饰的变量看做常量。

public class Main {
    public static void main(String[] args) {
        String a = "hello2";
        final String b = getHello();
        String c = b + 2;
        System.out.println((a == c));
    }

    public static String getHello() {
        return "hello";
    }
}

输出:false。因为b虽然是final变量,但是由于其赋值只能在运行期间确定。

public class Main {
    public static void main(String[] args) {
        String a = "hello";
        String b =  new String("hello");
        String c =  new String("hello");
        String d = b.intern();

        System.out.println(a==b);
        System.out.println(b==c);
        System.out.println(b==d);
        System.out.println(a==d);
    }
}

输出:false,false,false,true

intern方法是一个本地方法,会在运行时常量池中查找是否存在内容相同的字符串,如果有则返回该对象的引用;如果没有,则将该字符串入池,并且返回该对象的引用,所以是true。