昨天晚上无意间和小伙伴的一个问题关于new String("")到底创建了几个对象?然后就折腾了两个半小时!-_-。ok不说废话直接来干货。
网上都说new String("")是创建了两个对象。其实这条语句到底创建了几个对象是根据不同的情景来确定的,有可能是两个,也有可能是一个。接下来我们就分情况详细的讨论一下。
创建一个对象
String s = "123";
String s1 = new String("123");
如上面的这段代码所示这个时候new String("123")就创建了一个对象,这个对象是创建在JVM堆区中的。这个时候字符串常量池并不会创建新的"123"字符串,因为这个字符串在运行到 s = "123"已经在字符串常量区中,所以说是只创建了一个对象。网上还说执行new String("123")的时候会有一个去字符串常量区查询是否有这样的一个字符串的操作,其实这个是没有的。我们来看一下源码:
/** * Initializes a newly created {@code String} object so that it represents * the same sequence of characters as the argument; in other words, the * newly created string is a copy of the argument string. Unless an * explicit copy of {@code original} is needed, use of this constructor is * unnecessary since Strings are immutable. * * @param original * A {@code String} */ public String(String original) { this.value = original.value; this.hash = original.hash; }
Ok我们会在源码的说明中看到,这个构造器会创建一个新的String,新的String是拷贝参数字符串.关于先检查常量池中有没有这个字符串,然后添加啊,返回引用的什么操作一个字都没有提(如果有找到人也可以指出来我的错误- | -)。那么我们如何证明它就只是在堆里面创建了一个String对象呢?还是对于上面的两行代码,我们执行如下操作。
System.out.println(s == s1.intern()); // true
这个在我的环境(1.8_73)下是true,很明显如果new String()这句话如果创建了两个对象那么显示的结果就是false.这里就会有一点疑问了,网上说这个时候(执行 new String())会去常量池里面找是否存在这个字符串,没有则创建,有则返回引用,那明明是人家intern()方法的功劳了!再贴一段源码。
/** * Returns a canonical representation for the string object. * <p> * A pool of strings, initially empty, is maintained privately by the * class {@code String}. * <p> * When the intern method is invoked, if the pool already contains a * string equal to this {@code String} object as determined by * the {@link #equals(Object)} method, then the string from the pool is * returned. Otherwise, this {@code String} object is added to the * pool and a reference to this {@code String} object is returned. * <p> * It follows that for any two strings {@code s} and {@code t}, * {@code s.intern() == t.intern()} is {@code true} * if and only if {@code s.equals(t)} is {@code true}. * <p> * All literal strings and string-valued constant expressions are * interned. String literals are defined in section 3.10.5 of the * <cite>The Java™ Language Specification</cite>. * * @return a string that has the same contents as this string, but is * guaranteed to be from a pool of unique strings. */ public native String intern();
那个啥本人四级都没有考过就不细翻译了,大概的意思是,当执行这个方法的时候会去常量池中判断是否有一个与本字符串相等的字符串,如果有则返回这个对象,否则将这个对象的引用返回,等等。到这里有人可能就会问了,下面这段代码为什么执行结果和它说明的不一样,别着急,我们来看看什么情况下回生成两个对象。
String s = new String("123");
System.out.println(s == s.intern()); //false
创建两个对象
为了方便再把上面的代码粘贴过来用一用
/** * Initializes a newly created {@code String} object so that it represents * the same sequence of characters as the argument; in other words, the * newly created string is a copy of the argument string. Unless an * explicit copy of {@code original} is needed, use of this constructor is * unnecessary since Strings are immutable. * * @param original * A {@code String} */ public String(String original) {
/** * Initializes a newly created {@code String} object so that it represents * the same sequence of characters as the argument; in other words, the * newly created string is a copy of the argument string. Unless an * explicit copy of {@code original} is needed, use of this constructor is * unnecessary since Strings are immutable. * * @param original * A {@code String} */ public String(String original) { this.value = original.value; this.hash = original.hash; }} 不知道大家注意到了没有,这里创建字符串的时候有这样一个操作:
this.value = original.value;
ok不知道这句话给大家有没有什么启发,有没有很像 String s = "123",这句话就解释通了为啥new String("123")会创建了两个对象,首先在执行上面这段代码的时候其实"123"已经被加入到常量池中(有则不添加没有则添加),希望大家不要误会这样就证明了new String("")这句话会证明它有一个到常量池检查等一系列操作。只是程序运行到这里的时候发现有一个String s ="123"操作才回去常量池里面检查的。之后就是在堆中创建一个String对象。所以就是创建了两个对象。
总结
说到这里差不多就到结束的时候了,总结一下吧。new String("")创建几个对象是由不同的情况决定的,如果创建这个对象时传进去的字符串本来就是在常量池中出现过的就只会创建一个对象,如果没有出现过就会创建两个对象。如果有什么问题请大家指出谢谢