简体   繁体   English

当新的String(“ hello”)间接指向“ hello”时,它是否对简单的“ hello”完全没有用?

[英]Does use of new String(“hello”) is completely useless over simple “hello”, when it is indirectly pointing to “hello”?

After executing String S1 = "hello"; 执行完String S1 = "hello"; JVM will create a String object in SCP and that object will hold an array of char in value field like JVM将在SCP中创建一个String对象,并且该对象将在value字段中保存一个char数组,例如

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

And when we say 当我们说

String s2 = new String("hello");

And according to the source code of String class after constructor execution s2.value will also become "hello".value which will be similar to s1.value . 并且根据构造函数执行后String类的源代码, s2.value也将变为"hello".value ,类似于s1.value

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

So every time we create String object using new JVM will create 因此,每次我们使用new JVM创建String对象时,都会创建

  1. one object in heap and 堆中有一个对象
  2. one string literal object in SCP if it already not there SCP中的一个字符串文字对象(如果尚未存在)

And the object in heap points to the literal object in SCP internally. 并且堆中的对象内部指向SCP中的文字对象。

And every time, we make a change in s2 or in any other string (doesn't matter it is created from literal or using new ) one new string literal will get created on the heap, which that newly changed s2 will point. 每次我们更改s2或任何其他字符串(无论是从文字中创建还是使用new更改),都会在堆上创建一个新的字符串文字,新更改的s2将指向该字符串。

Using String s2 = new String("hello") is not creating "hello" object in heap. 使用String s2 = new String("hello")不会在堆中创建"hello"对象。 JVM is creating "hello" in SCP only if it is not present there and s2 pointing to it. JVM仅在SCP中不存在并且s2指向它时才在SCP中创建"hello"

My question is not, what is the difference between new String("hello") or simple "hello" . 我的问题不是, new String("hello")或简单的"hello"什么区别。

My question is when using public String(String original) is just creating empty string object in heap and wasting memory Why Java allows developers to call public String(String original) and why is it even provided in String class, what benefit it is giving? 我的问题是使用public String(String original)仅在堆中创建空字符串对象并浪费内存时,为什么Java允许开发人员调用public String(String original) ,为什么甚至在String类中也提供了它,这有什么好处呢?

There is an interesting statement in Joshua Bloch's “Effective Java”, 2nd edition, chapter 4, item 15: 在Joshua Bloch的“ Effective Java”(第二版)第4章第15项中有一个有趣的陈述:

A consequence of the fact that immutable objects can be shared freely is that you never have to make defensive copies (Item 39). 可以自由共享不可变对象这一事实的结果是,您不必制作防御性副本 (第39项)。 In fact, you never have to make any copies at all because the copies would be forever equivalent to the originals. 实际上,您根本不必制作任何副本,因为这些副本将永远等同于原始副本。 Therefore, you need not and should not provide a clone method or copy constructor (Item 11) on an immutable class. 因此,您不需要也不应该在不可变类上提供clone方法或副本构造函数 (项目11)。 This was not well understood in the early days of the Java platform, so the String class does have a copy constructor, but it should rarely, if ever, be used (Item 5). 在Java平台的早期,这还没有得到很好的理解,因此String类确实具有复制构造函数,但是很少使用(如果有的话)(第5项)。

(page 76 in my copy) (我的副本中的第76页)
I think, Joshua Bloch can be seen as an authoritative source, especially as James Gosling, one of the Java inventors, has been cited saying, “I sure wish I had this book ten years ago…” (referring to the 1st edition from 2001). 我认为,约书亚·布洛赫(Joshua Bloch)可以被视为权威资料,尤其是有人引用Java发明者之一詹姆斯·高斯林(James Gosling)的话说:“我希望我十年前有这本书……”(指的是2001年的第一版) )。


So the existence of the String(String) constructor can be seen as a design mistake, much as the parameterless String() constructor. 因此, String(String)构造函数的存在可以看作是设计错误,就像无参数的String()构造函数一样。 Note also the presence of the factory methods String.valueOf(char[]) / String.valueOf(char[],int,int) and String.copyValueOf(char[]) / String.copyValueOf(char[],int,int) , whose naming suggests a fundamental difference that simply isn't there. 还要注意工厂方法String.valueOf(char[]) / String.valueOf(char[],int,int)String.copyValueOf(char[]) / String.copyValueOf(char[],int,int) ,其命名表明根本不存在根本的区别。 The immutable nature of String mandates that all variants create a defensive copy of the provided array, to protect against subsequent modifications. String不变性要求所有变体都创建所提供数组的防御性副本,以防止后续修改。 So the behavior is exactly the same (the documentation tells this explicitly), whether you use valueOf or copyValueOf . 因此,无论您使用valueOf还是copyValueOf ,其行为都是完全相同的(文档明确地告诉了这一点)。


That said, there are some practical use cases, though not necessarily being within original intentions. 也就是说,有一些实际用例,尽管不一定在原始意图之内。 Some of them are described in the answers to this question . 在对这个问题的回答中描述了其中一些 As the new operation guarantees to produce a new instance, it might be useful for any subsequent operation relying on a distinct identity, eg synchronizing on that instance (not that this was a good idea) or trying to recognize that instance via identity comparison to be sure that it doesn't originate from an external source. 由于new操作保证产生一个新实例,因此对于依赖于唯一标识的任何后续操作可能都是有用的,例如,在该实例上进行同步(这并不是一个好主意),或者尝试通过标识比较来识别该实例确保它不是来自外部来源。 Eg, you might want to distinguish between a property's default value and a value that has been explicitly set. 例如,您可能想区分属性的默认值和已明确设置的值。 This, however, is of limited use as other code might not guaranty to maintain the object identity in its operations, even if the string contents doesn't change. 但是,这是有限的用途,因为即使字符串内容未更改,其他代码也可能无法保证在其操作中保持对象标识。 Or it might remember your special instance and reuse it, once it encountered the string. 否则,一旦遇到字符串,它可能会记住您的特殊实例并重新使用它。

Before Java 7, update 6, String had an offset and length field, allowing a cheap substring operation, referring to a range within the original array, without copying. 在Java 7 Update 6之前, String具有offsetlength字段,允许廉价的substring操作,无需复制即可引用原始数组中的范围。 This led to the scenario, that a (conceptually) small string could hold a reference to a rather large array, preventing its garbage collection. 这就导致了这样的情况:一个(概念上)小的字符串可能包含对一个相当大的数组的引用,从而阻止了其垃圾回收。 For the reference implementation (that shipped by Sun/later Oracle), recreating the string via the String(String) constructor produced a String with a fresh copy of the array, occupying only as much memory as needed. 对于参考实现(由Sun /后来的Oracle交付),通过String(String)构造函数重新创建字符串会产生一个带有数组新副本的String ,仅占用所需的内存。 So this was a use case incorporating an implementation specific fix to an implementation specific problem… 因此,这是一个用例,其中包含针对特定于实现的问题的特定于实现的修复…

Current Java releases do not maintain these offset and length fields, implying a potentially more expensive substring operation, but no copying behavior in the String(String) constructor anymore. 当前的Java版本不维护这些offsetlength字段,这意味着可能更昂贵的substring操作,但是String(String)构造函数中不再有复制行为。 This is the version, whose source code you have cited in the question. 这是版本,您在问题中引用了其源代码。 The older version can be found in this answer . 可以在此答案中找到较旧的版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM