0

所以我的问题与声明和分配字符串有关。

我通常声明字符串的方式是执行以下操作:

String s1 = "Stackoverflow";

然后,如果我需要更改 s1 的值,我会执行以下操作:

s1 = "new value";

今天我找到了另一种方法,并声明一个字符串如下:

String s2 = new String("Stackoverflow");

然后更改值将是:

s2 = new String("new value");

我的问题是两者之间有什么区别,或者只是优惠。从第四行看代码

s2 = new String ("new value"); 

我假设这样做会创建一个新的内存位置,然后 s2 会指向它,所以我怀疑它会被用来更改值,但我可以看到它在声明字符串时被使用。

4

6 回答 6

6

From the javadoc :

Initializes a newly created 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 original is needed, use of this constructor is unnecessary since Strings are immutable.

So no, you have no reason not to use the simple literal.

Simply do

String s1 = "Stackoverflow";

Historically, this constructor was mainly used to get a lighter copy of a string obtained by splitting a bigger one (see this question). Now, There's no normal reason to use it.

于 2013-10-11T16:08:50.203 回答
0

主要区别在于构造函数总是创建一个全新的 String 实例,其中包含与原始 String 相同的字符。

String s1 = "Stackoverflow";
String s2 = "Stackoverflow";

然后s1 == s2将返回true

String s1 = "Stackoverflow";
String s2 = new String("Stackoverflow");

然后s1 == s2将返回false

仅使用双引号选项通常会更好:

  • 使用构造函数,您可以创建两个 String 实例。
  • 更容易阅读,更少混乱
于 2013-10-11T16:17:56.403 回答
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

在第一种情况下,您正在创建一个新对象,即;为将由 s2 引用的新对象分配内存。s2 指向/引用的先前地址尚未释放内存,当程序结束或系统需要时,这将是 gc。

良好的编程习惯(第二种情况)是初始化一个对象一次,如果你想改变它的值,要么给它分配空值,然后给它分配新的内存,或者在字符串的情况下你可以这样做

s2= "new String";
于 2013-10-11T16:12:09.787 回答
0
String s1 = "Stackoverflow";

如果 String 池中尚不存在该对象,则此行将在该对象中创建一个新对象。这意味着首先它将首先尝试在字符串池中搜索“Stackoverflow”,如果找到则 s1 将开始指向它,如果未找到则它将创建一个新对象并 s1 将引用它。

String s2 = new String("Stackoverflow");

将始终创建一个新的 String 对象,无论该值是否已存在于 String 池中。因此堆中的对象将具有值“Stackovrflow”,并且 s2 将开始指向它。

s2 = new String("new value");

这将再次创建一个新对象,并且 s2 将开始指向它。s2 指向的较早对象未对垃圾收集 (gc) 开放。

让我知道这是否有帮助。

于 2013-10-11T16:23:11.680 回答
0

在此处输入图像描述

@user2612619 在这里我想说的是.. 当您使用“new”运算符创建对象时,它总是落在堆内存中。所以无论你有相同的内容但不同的对象,它都会在堆上创建新的对象,这样你就无法节省内存......

但是为了节省内存,Java人们带来了不可变的概念,我们可以在其中节省内存..如果您创建具有相同内容的不同对象..字符串将识别数据差异并仅创建一个具有相同内容的对象并将两个引用指向仅一个对象..

我可以从这个数字中解决你的疑问..

情况1:

String s = new String("stackoverflow");
String s1 = new String("stackoverflow");

因为它们是堆内存上的两个不同对象,具有两个不同的哈希码值 .. 所以 s==s1 (是参考比较)它是错误的 .. 但 s.equals(s1) 是内容比较 .. 所以它是真的

案例2:

String s = "stackoverflow";
String s1 = "stackoverflow";

这里的对象落入 scp(字符串常量池内存) 两个不同的引用的相同对象.. 所以哈希码也相同.. 相同的引用值.. 所以这里 s==s1 是真的[你可以从图中清楚地观察] s.equals( s1)作为内容比较是正确的..这是一个非常漂亮的概念..如果你解决了一些问题,你会喜欢它的......一切都好

于 2013-10-11T17:18:36.240 回答
0

直接创建字符串对象:

String s1 = "Hip Hop" 

将创建一个字符串对象,但首先 JVM 检查字符串常量或文字,如果字符串不存在,它会创建一个新的字符串对象“Hip jop”,并在池中维护一个引用。该变量s1也引用同一个对象。现在,如果我们在此之后添加一个声明:

 String s2 = "Hip Hop"

JVM 首先检查字符串常量池,因为字符串已经存在,所以对池实例的引用返回到s2.

System.out.println(s1==s2) // comparing reference and it will print true

java 可以进行这种优化,因为字符串是不可变的,并且可以共享而不必担心数据损坏。

使用 new 创建字符串对象

String s3 = new String("Hip Hop")

对于new关键字,在堆内存中创建一个字符串对象,或者在池中不存在相等的字符串对象,s3并将引用新创建的对象。

System.out.println(s3==s2) // two reference is different, will print false 

使用运算符创建的字符串对象new不引用字符串池中的对象,但可以使用 String 的intern()方法。java.lang.String.intern()返回一个实习字符串,即在全局字符串文字池中有一个条目的字符串。如果 String 尚未在全局 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,

作为 的引用s4s2s1是对池化实例的引用,同时是对堆内存s3中创建的对象的引用。

使用 new 来创建字符串:

在 OpenJDK 7 Update 6 之前,JavaString.susbtring方法存在潜在的内存泄漏。substring方法将构建一个新的 String 对象,保留对整个 char 数组的引用,以避免复制它。因此,您可能会在不经意间保留对只有一个字符串的非常大的字符数组的引用。如果我们想在 之后有最少的字符串substring,我们使用构造函数来获取另一个字符串:

String s2 = new String(s1.substring(0,1));

该问题已在 JDK 7 更新 6 中得到解决。因此,无需再创建字符串即可利用字符串文字池机制 new提供的优势。

参考:

  1. 字符串文字池
  2. 使用 new 来防止使用子字符串的内存泄漏
于 2013-10-11T18:21:40.663 回答