基础面试,为什么面试官总喜欢问String?
关于 Java String,这是面试的基础,但是还有很多童鞋不能说清楚,所以本文将简单而又透彻的说明一下那个让你迷惑的 String
在 Java 中,我们有两种方式创建一个字符串
String x = "abc"; String y = new String("abc");
你常见也常写第一种,很少见第二种,但面试还总问这类问题,双引号和构造器两种形式创建字符串到底有什么差别呢?
先来看例子
例子 1
String a = "abcd"; String b = "abcd"; System.out.println(a == b); // True System.out.println(a.equals(b)); // True
a == b
结果为 true,是因为 a 和 b 都指向 方法区(method area) 同一个字符串文字,内存引用是同一个
当多次创建相同的字符串文字时,只存储每个不同字符串值的一个副本。这个叫做字符串留驻/留用,Java 中所有编译期字符串常量都会被自动留驻
例子 2
String c = new String("abcd"); String d = new String("abcd"); System.out.println(c == d); // False System.out.println(c.equals(d)); // True
c==d
结果为 false,因为 c 和 d 的引用指向堆中不同的对象,不同的对象肯定有不同的内存引用
举了两个例子,文字描述有点懵?我们来试图通过图形来理解上述两种情况:
也许你已经看看出来了,一个是在方法区
,一个是在堆
中,在 JVM 模型中这是两个不同的区域,也许你面试时也经常被问到吧,来看下图:
再次提醒一下,所有 new 的对象都会在 Heap 中,这样以后你就好区分了
运行期字符串留驻
上面说的字符串留驻是在编译期,那么运行期可以吗?答案是肯定的,我们需要一个函数来帮忙
String c = new String("abcd").intern(); String d = new String("abcd").intern(); System.out.println(c == d); // Now true System.out.println(c.equals(d)); // True
看到 c == d
结果为 true,你应该理解 intern (英文有拘留,软禁的意思)的作用了,通过调用 intern()方法,就好比把创建的字符串拘留在方法区一样了
在面试时甚至还会问你下面代码创建了几个对象:
String d = new String("abcd")
- 如果方法区已存在"abcd", 那么只创建一个 new String 的对象
- 如果方法区没有"abcd", 那么要创建两个对象,一个在方法区,一个在堆中
所以,正常情况下我们没必要使用构造器创建对象,因为这很可能会产生一个额外的没用的对象,但是有例外哦,我们下面说
String s = "abcd"; s = s.concat(