所以我的问题是关于声明和分配字符串。
我通常声明字符串的方式是执行以下操作:
String s1 = "Stackoverflow";
然后,如果我需要更改s1的值,我会执行以下操作:
s1 = "new value";
今天我找到了另一种方法,然后声明一个字符串:
String s2 = new String("Stackoverflow");
然后更改值将是:
s2 = new String("new value");
我的问题是两者之间有什么区别,还是只是优惠。从第四行查看代码
s2 = new String ("new value");
我假设这样做会创建一个新的内存位置,然后s2指向它,所以我怀疑它会用于更改值,但我可以看到它在声明字符串时被使用。
答案 0 :(得分:6)
来自the javadoc:
初始化一个新创建的String对象,使其代表 与参数相同的字符序列;换句话说,新的 created string是参数字符串的副本。 除非明确 需要使用原始副本,不需要使用此构造函数 因为字符串是不可变的。
所以不,你没有理由不使用简单的文字。
简单地做
String s1 = "Stackoverflow";
从历史上看,这个构造函数主要用于获取通过拆分较大的字符串获得的字符串的较轻副本(请参阅this question)。现在,使用它没有正常的理由。
答案 1 :(得分:0)
String s1 = "Stackoverflow"; // declaring & initializing s1
String s2 = new String("Stackoverflow"); // declaring & initializing s2
在上述情况下,您宣布&初始化String对象。
之间的区别
//first case
String s2 = new String("new String"); // declaring & initializing s2 with new memory
// second case
s2 = "new String" // overwriting previous value of s2
是第一种情况,你是 创建一个新对象 ,i-e;为新对象分配内存,该对象将被s2引用。 s2指向/引用的先前地址尚未释放存储器,当程序结束或系统需要时,该存储器将是gc。
良好的编程习惯(第二种情况)是初始化一次对象,如果要更改其值,为其分配和然后为它分配新内存或者在字符串的情况下你可以这样做
s2= "new String";
答案 2 :(得分:0)
主要区别在于构造函数总是创建一个全新的String实例,其中包含与原始String相同的字符。
String s1 = "Stackoverflow";
String s2 = "Stackoverflow";
然后s1 == s2
将返回true
String s1 = "Stackoverflow";
String s2 = new String("Stackoverflow");
然后s1 == s2
将返回false
使用双引号选项通常更好:
答案 3 :(得分:0)
String s1 = "Stackoverflow";
该行将在String池中创建一个新对象(如果它尚不存在)。这意味着首先它会首先尝试在String池中搜索“Stackoverflow”,如果找到则s1将开始指向它,如果没有找到则会创建一个新对象,s1将引用它。
String s2 = new String("Stackoverflow");
无论String池中是否已存在该值,都将始终创建一个新的String对象。因此堆中的对象将具有值“Stackovrflow”,s2将开始指向它。
s2 = new String("new value");
这将再次创建一个新的对象,s2将开始指向它。 s2指向的早期对象未打开垃圾收集(gc)。
如果有帮助,请告诉我。
答案 4 :(得分:0)
@ user2612619这里我想说的是..当你用“new”运算符创建对象时,它总是落在堆内存中。所以,每当你拥有相同的内容但不同的对象时,它也会通过这种无法保存的内存在堆上创建新对象....
但是为了节省内存java人们带来了不可变的概念我们可以节省内存..如果你创建一个具有相同内容的不同对象..字符串将识别dat差异并且只创建一个具有相同内容的对象并指向两个仅引用一个对象..
我可以从这个数字中解决你的怀疑..
案例1:
String s = new String("stackoverflow");
String s1 = new String("stackoverflow");
因为它们是堆内存上的两个不同对象,具有两个不同的hashcode值。所以s == s1(参考比较)它是false ..但s.equals(s1)是内容比较..所以它是真
案例2:
String s = "stackoverflow";
String s1 = "stackoverflow";
这里的对象属于scp(字符串常量池内存) 相同的对象为两个不同的引用..所以哈希码也相同..相同的参考值..所以s == s1在这里是真的[你可以从图中清楚地看到] s.equals(s1)是真实的内容比较..这是非常漂亮的概念..你会喜欢它,你解决了一些问题......一切都是最好的
答案 5 :(得分:0)
String s1 = "Hip Hop"
将创建一个字符串对象,但第一个JVM会检查 String常量或文字 池,如果该字符串不存在,则会创建一个新的String对象“Hip jop”和池中保持引用。变量s1
也引用相同的对象。现在,如果我们在此之后发表声明:
String s2 = "Hip Hop"
JVM首先检查 String常量池,因为该字符串已经存在,所以对池化实例的引用将返回到s2
。
System.out.println(s1==s2) // comparing reference and it will print true
java可以进行此优化,因为字符串不可变并且可以共享而不用担心数据损坏。
String s3 = new String("Hip Hop")
对于 new
关键字,会在 堆内存 中创建一个String对象,否则已存在相等的字符串对象在池中,s3
将引用新创建的。
System.out.println(s3==s2) // two reference is different, will print false
使用 new
运算符创建的字符串对象不引用字符串池中的对象,但可以使用String的intern()
方法。 java.lang.String.intern()
会返回 实习字符串 ,即在全局字符串文字池中有条目的字符串。如果String不在全局字符串文字池中,则它将被添加到池中。
String s4 = s3.intern();
Systen.out.println(s4 == s2); // will print `true` because s4 is interned,
//it now have the same reference to "Hip Hop" as s2 or s1
但请尝试:
Systen.out.println(s4 == s3) // it will be false,
作为s4
的引用,s2
和s1
是对池化实例的引用,而s3
是指 中创建的对象堆内存 。
在OpenJDK 7,Update 6之前,Java String.susbtring
方法存在潜在的内存泄漏。 substring
方法将构建一个新的String对象,保持对整个char数组的引用,以避免复制它。因此,您可能无意中仅使用一个字符串保留对非常大的字符数组的引用。如果我们想在substring
之后拥有最少的字符串,我们使用构造函数取另一个字符串:
String s2 = new String(s1.substring(0,1));
问题在JDK 7 update 6中得到解决。因此,不需要再创建带有new
的字符串,以便利用 String literal pool 机制提供的优势。