“文本”和新的string(“文本”)有什么区别?

这两个声明有什么区别?

String s = "text"; String s = new String("text"); 

new String("text"); 显式地创build一个新的和不同的String对象的实例; String s = "text"; 可以重用string常量池中的实例(如果有)。

很less会想要使用new String(anotherString)构造函数。 从API:

String(String original) :初始化新创build的 String对象,使其表示与参数相同的字符序列; 换句话说,新创build的string是参数string的副本。 除非需要显式拷贝原始文件,否则使用这个构造函数是不必要的,因为string是不可变的。

相关问题

  • Javastring:“String s = new String(”傻“);”
  • string是Java中的对象,那么为什么我们不使用“新”来创build它们呢?

区别是指什么

检查以下代码片段:

  String s1 = "foobar"; String s2 = "foobar"; System.out.println(s1 == s2); // true s2 = new String("foobar"); System.out.println(s1 == s2); // false System.out.println(s1.equals(s2)); // true 

==两个引用types是参考标识比较。 两个equals对象不一定是== 。 在引用types上使用==通常是错误的; 大部分时间equals需要使用。

尽pipe如此,如果由于某种原因需要创build两个equals而不是==string,则可以使用new String(anotherString)构造函数。 需要再说的是,这是非常奇特的,很less有这个意图。

参考

  • JLS 15.21.3参考平等操作符==和!=
  • class Objectboolean Object(equals)

相关问题

  • Java String.equals与==
  • 如何比较Java中的string?

string文字将进入string常量池

下面的快照可能会帮助您直观地了解它,以便更长时间记住它。

在这里输入图像描述


逐行创build对象:

 String str1 = new String("java5"); 

在构造函数中使用string文字“java5”,一个新的string值被存储在string常量池中使用new操作符在堆中创build一个新的string对象,其值为“java5”

 String str2 = "java5" 

参考“str2”指向string常量池中已经存储的值

 String str3 = new String(str2); 

在堆中创build一个新的string对象,其值与“str2”引用的值相同

 String str4 = "java5"; 

参考“str4”指向string常量池中已经存储的值

总物件:堆 – 2,池 – 1

进一步阅读Oracle社区

一个在string常量池中创build一个string

 String s = "text"; 

另一个在常量池( "text" )中创build一个string,在正常的堆空间中创build另一个string。 这两个string将具有相同的值,即“文本”。

 String s = new String("text"); 

如果后来未被使用的话,则丢失(符合GC的条件)。

另一方面,string文字被重用。 如果你在你的类的多个地方使用"text" ,它实际上将是一个且只有一个string(即对该string在池中的多个引用)。

JLS

这个概念被JLS称为“实习”。

JLS 7相关文章3.10.5 :

而且,一个string文字总是引用类String的同一个实例。 这是因为string文字 – 或者更一般地说,是常量expression式(§15.28)的值的string – 被“interned”,以便使用方法String.intern共享唯一的实例。

例3.10.5-1。 string文字

由编制单位(第7.3节)组成的计划:

 package testPackage; class Test { public static void main(String[] args) { String hello = "Hello", lo = "lo"; System.out.print((hello == "Hello") + " "); System.out.print((Other.hello == hello) + " "); System.out.print((other.Other.hello == hello) + " "); System.out.print((hello == ("Hel"+"lo")) + " "); System.out.print((hello == ("Hel"+lo)) + " "); System.out.println(hello == ("Hel"+lo).intern()); } } class Other { static String hello = "Hello"; } 

和编制单位:

 package other; public class Other { public static String hello = "Hello"; } 

产生输出:

 true true true true false true 

JVMS

JVMS 7 5.1说 :

string文字是对类String的一个实例的引用,并且是从类或接口的二进制表示中的CONSTANT_String_info结构(第4.4.3节)派生的。 CONSTANT_String_info结构给出了构成string文字的Unicode代码点序列。

Java编程语言要求相同的string文字(即包含相同的代码点序列的文字)必须引用同一类String(JLS§3.10.5)的实例。 此外,如果在任何string上调用String.intern方法,则结果是对同一个类实例的引用,如果该string显示为文字,则会返回该实例。 因此,以下expression式必须具有真值:

 ("a" + "b" + "c").intern() == "abc" 

为了派生string文字,Java虚拟机检查由CONSTANT_String_info结构给出的代码点序列。

  • 如果方法String.intern先前在包含与CONSTANT_String_info结构相同的Unicode代码点序列的String类实例上调用,则string文字派生的结果是对类String相同实例的引用。

  • 否则,将创build一个包含由CONSTANT_String_info结构给出的Unicode代码点序列的类String的新实例; 该类实例的引用是string文字派生的结果。 最后,调用新的String实例的intern方法。

字节码

查看OpenJDK 7上的字节码实现也是有益的。

如果我们反编译:

 public class StringPool { public static void main(String[] args) { String a = "abc"; String b = "abc"; String c = new String("abc"); System.out.println(a); System.out.println(b); System.out.println(a == c); } } 

我们有不断的池:

 #2 = String #32 // abc [...] #32 = Utf8 abc 

main

  0: ldc #2 // String abc 2: astore_1 3: ldc #2 // String abc 5: astore_2 6: new #3 // class java/lang/String 9: dup 10: ldc #2 // String abc 12: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V 15: astore_3 16: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 19: aload_1 20: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 23: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 26: aload_2 27: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 30: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 33: aload_1 34: aload_3 35: if_acmpne 42 38: iconst_1 39: goto 43 42: iconst_0 43: invokevirtual #7 // Method java/io/PrintStream.println:(Z)V 

请注意:

  • 03 :加载相同的ldc #2常量(文字)
  • 12 :创build一个新的string实例(以#2作为参数)
  • 35 :将ac作为常规对象与if_acmpne进行比较

常量string的表示在字节码上非常神奇:

  • 它有一个专用的CONSTANT_String_info结构,不像常规对象(例如new String
  • 该结构指向包含数据的CONSTANT_Utf8_info结构 。 这是表示string的唯一必要数据。

而上面的JVMS报价似乎表示,只要Utf8指向的是相同的,则相同的实例由ldc加载。

我已经做了类似的testing领域,并且:

  • static final String s = "abc"通过ConstantValue属性指向常量表
  • 非final字段没有该属性,但仍可以使用ldc进行初始化

结论 :对string池有直接的字节码支持,并且内存表示是有效的。

奖金:比较那整体池 ,没有直接的字节码支持(即没有CONSTANT_String_info模拟)。

想想"bla"是一个像Strings.createString("bla") (伪)的魔法工厂。 工厂拥有一个所有string池,但这种方式创build。

如果被调用,它会检查池中是否已经有string。 如果为true,则返回此string对象,因此以这种方式获得的string的确是同一个对象。

如果没有,则在内部创build一个新的string对象,将其保存在池中,然后返回。 因此,当下一次查询相同的string值时,它将返回相同的实例。

手动创buildnew String("")通过绕过string文字池来覆盖此行为。 所以平等应该总是使用equals()来检查,它比较字符序列而不是对象引用的相等性。

了解差异的一个简单方法如下:

 String s ="abc"; String s1= "abc"; String s2=new String("abc"); if(s==s1){ System.out.println("s==s1 is true"); }else{ System.out.println("s==s1 is false"); } if(s==s2){ System.out.println("s==s2 is true"); }else{ System.out.println("s==s2 is false"); } 

输出是

 s==s1 is true s==s2 is false 

因此,新的String()将始终创build一个新的实例。

尽pipe从程序员的angular度来看它是一样的,但是它对性能有很大的影响。 你会想要几乎总是使用第一种forms。

 String str = new String("hello") 

它将检查是否string常量池已经包含string“你好”? 如果存在,则不会在string常量池中添加条目。 如果不存在,则会在String常量池中添加一个条目。

将在堆内存区域中创build一个对象,并在堆内存位置创build对象以创build对象。

如果你想str引用包含在String常量池中的point对象,那么你必须显式调用str.intern();

 String str = "world"; 

它将检查是否string常量池已经包含string“你好”? 如果存在,则不会在string常量池中添加条目。 如果不存在,则会在String常量池中添加一个条目。

在以上两种情况下,常量池中的str参考指向String "world"

@布拉杰:我想你已经提到了另一种方式。 如果我错了,请纠正我

逐行创build对象:

String str1 = new String(“java5”)

  Pool- "java5" (1 Object) Heap - str1 => "java5" (1 Object) 

String str2 =“java5”

  pool- str2 => "java5" (1 Object) heap - str1 => "java5" (1 Object) 

String str3 = new String(str2)

  pool- str2 => "java5" (1 Object) heap- str1 => "java5", str3 => "java5" (2 Objects) 

String str4 =“java5”

  pool - str2 => str4 => "java5" (1 Object) heap - str1 => "java5", str3 => "java5" (2 Objects)