2016-11-21 16 views
0

执行String S1 = "hello";后JVM将在SCP创建字符串对象,并该对象将持有字符数组中value场像使用新字符串(“hello”)在简单的“hello”中完全无用,当它间接指向“hello”时?

s1.value = {'h', 'e', 'l', 'l', 'o'} 

当我们说

String s2 = new String("hello"); 

并根据源代码String类在构造函数执行后s2.value也将变为"hello".value,它将类似于s1.value

public String(String original) { 
    this.value = original.value; 
    this.hash = original.hash; 
} 

所以每次我们创建一个使用new JVM String对象将创建在堆

  1. 一个对象,并
  2. 一个字符串字面对象SCP的时间,如果它已经不存在

堆中的对象在内部指向SCP中的文字对象。

而每一次,我们作出s2或以其他任何字符串的变化(不要紧它是从字面上或使用new创建)字面一个新字符串将会在堆中,这是新更改s2将创建点。使用String s2 = new String("hello")不会创建"hello"堆中的对象。 JVM正在SCP中创建"hello",除非它不存在,s2指向它。

我的问题是,new String("hello")或简单的"hello"有什么区别。当使用public String(String original)刚刚创建堆空字符串对象,并浪费内存为什么Java允许开发人员调用public String(String original),为什么它甚至在String类提供什么好处它给

我的问题是什么?

+0

新的字符串(“文本”)使字符的副本[] –

+0

@simas_ch:不,它不。它曾经这样做,但三年前就改变了。 – Holger

+0

@Jens我已经更新了这个问题,这个问题与您提到的问题并不重复 –

回答

1

有一个有趣的说法在约书亚布洛赫的“有效的Java”,第2版,第4章,第15项:

的事实是不可变对象可以自由共享的一个后果是, 你永远不会有制作防御性拷贝(条目39)。事实上,你永远不必 任何副本,因为副本将永远等于原件。 因此,您不需要也不应该提供clone方法或复制 构造函数(项目11)在不可变类上。这在Java平台早期的 中并没有得到很好的理解,所以String类确实有一个拷贝构造函数 ,但它应该很少使用(项目5)。

(第76页在我的副本)
我认为,约书亚布洛赫可以看作是一个权威的来源,尤其是詹姆斯·高斯林,Java的发明者之一,已被列为说,“我当然希望我十年前写过这本书......“(指的是2001年的第一版)。


所以String(String)构造的存在,可以被看作是一个设计错误,多为无参数的构造函数String()。还请注意工厂方法String.valueOf(char[])/String.valueOf(char[],int,int)String.copyValueOf(char[])/String.copyValueOf(char[],int,int)的存在,其命名表明存在根本不存在的根本差异。 String的不可变性质要求所有变体创建所提供阵列的防御副本,以防止后续修改。因此,行为是完全相同的(文档明确告诉您),无论您使用的是valueOf还是copyValueOf


这就是说,有一些实际的用例,虽然不一定在初衷之内。其中一些在this question的答案中进行了描述。由于new操作保证产生新的实例,因此对于任何依赖于不同身份的后续操作可能是有用的,例如,在该实例上进行同步(不是这是一个好主意),或者试图通过身份比较来识别该实例,以确保它不是来自外部源。例如,您可能想要区分属性的默认值和已明确设置的值。但是,这样做的用处有限,因为即使字符串内容没有更改,其他代码也可能无法保持对象身份的正确性。或者它可能会记住你的特殊实例并在它遇到字符串时重用它。

爪哇7,更新6,String之前有一个offsetlength字段,允许廉价substring操作,指的是原始阵列内的范围内,而不进行复制。这导致了这样一种情况,一个(概念上)小的字符串可以持有对一个相当大的数组的引用,从而防止其垃圾收集。对于参考实现(由Sun/later Oracle提供),通过构造函数String(String)重新创建字符串,生成了带有全新数组副本的String,只占用尽可能多的内存。因此,这是在String(String)构造函数的使用情况纳入实现特有的修复,以实现特有的问题...

当前的Java版本不维护这些offsetlength领域,这意味着一个潜在的更加昂贵的substring操作,但没有复制行为了。这是你在问题中引用的源代码版本。旧版本可在this answer中找到。

+0

因此对于当前版本的Java 8,字符串的拷贝构造函数是完全无用的,甚至会降低性能你的Java应用程序 –

相关问题