和有什么区别
String str = new String("abc");
和
String str = "abc";
当您使用字符串文字时,字符串可以被interned,但是当您使用时,new String("...")
您会得到一个新的字符串对象。
在这个例子中,两个字符串字面量都引用同一个对象:
String a = "abc";
String b = "abc";
System.out.println(a == b); // true
在这里,创建了 2 个不同的对象,它们具有不同的引用:
String c = new String("abc");
String d = new String("abc");
System.out.println(c == d); // false
通常,您应该尽可能使用字符串文字表示法。它更容易阅读,它让编译器有机会优化你的代码。
A String literal is a Java language concept. This is a String literal:
"a String literal"
A String object is an individual instance of the java.lang.String
class.
String s1 = "abcde";
String s2 = new String("abcde");
String s3 = "abcde";
All are valid, but have a slight difference. s1
will refer to an interned String object. This means, that the character sequence "abcde"
will be stored at a central place, and whenever the same literal "abcde"
is used again, the JVM will not create a new String object but use the reference of the cached String.
s2
is guranteed to be a new String object, so in this case we have:
s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true
长答案可以在这里找到,所以我给你一个简短的答案。
当你这样做时:
String str = "abc";
您正在调用Stringintern()
上的方法。此方法引用内部对象池。如果您调用的 String已经存在于池中,那么对它的引用将分配给. 如果不是,则将 new放入池中,然后将对其的引用分配给.String
intern()
String
str
String
str
给定以下代码:
String str = "abc";
String str2 = "abc";
boolean identity = str == str2;
当您通过做检查对象身份时==
(您实际上是在问:这两个引用是否指向同一个对象?),您得到true
.
但是,您不需要. intern()
Strings
您可以通过执行以下操作强制在堆上创建新Object
的:
String str = new String("abc");
String str2 = new String("abc");
boolean identity = str == str2;
在这种情况下,str
andstr2
是对不同的引用Objects
,它们都没有被interned,因此当您使用 测试Object
身份时==
,您将得到false
.
就良好的编码实践而言:不要用于检查==
字符串是否相等,.equals()
而是使用。
由于字符串是不可变的,当你这样做时:
String a = "xyz"
在创建字符串时,JVM 会在字符串池中搜索是否已经存在字符串 value "xyz"
,如果存在'a'
则只是对该字符串的引用,并且不会创建新的 String 对象。
但如果你说:
String a = new String("xyz")
你强制 JVM 创建一个新的String
引用,即使"xyz"
它在它的池中。
欲了解更多信息,请阅读此。
"abc"
是一个文字字符串。
在 Java 中,这些文字字符串在内部进行池化,并且"abc"
在您的代码中声明了该字符串文字的任何地方都使用相同的 String 实例。所以"abc" == "abc"
总是如此,因为它们都是同一个 String 实例。
使用该String.intern()
方法,您可以将您喜欢的任何字符串添加到内部池字符串中,这些字符串将保存在内存中,直到 java 退出。
另一方面, usingnew String("abc")
将在内存中创建一个新的字符串对象,这在逻辑上与"abc"
字面量相同。
"abc" == new String("abc")
将永远是错误的,因为尽管它们在逻辑上是相等的,但它们指的是不同的实例。
围绕字符串文字包装 String 构造函数没有任何价值,它只是不必要地使用了比它需要的更多的内存。
String 是 Java 中不同于其他编程语言的一个类。因此,对于每个类,对象声明和初始化都是
String st1 = new String();
或者
String st2 = new String("Hello");
String st3 = new String("Hello");
在这里,st1
和st2
是st3
不同的对象。
那是:
st1 == st2 // false
st1 == st3 // false
st2 == st3 // false
因为st1
, st2
,st3
引用了 3 个不同的对象,并==
检查内存位置的相等性,因此结果。
但:
st1.equals(st2) // false
st2.equals(st3) // true
这里.equals()
方法检查内容,以及 , 和st1 = ""
的st2 = "hello"
内容st3 = "hello"
。因此结果。
在 String 声明的情况下
String st = "hello";
这里调用class的intern()
方法String
,检查是否"hello"
在intern pool中,如果不在则加入intern pool中,如果intern pool中有hello,则st
指向已有的内存"hello"
。
所以在以下情况下:
String st3 = "hello";
String st4 = "hello";
这里:
st3 == st4 // true
因为st3
和st4
指向相同的内存地址。
还:
st3.equals(st4); // true as usual
在第一种情况下,创建了两个对象。
在第二种情况下,它只是一个。
虽然这两种方式str
都是指"abc"
.
一些反汇编总是很有趣......
$ cat Test.java
public class Test {
public static void main(String... args) {
String abc = "abc";
String def = new String("def");
}
}
$ javap -c -v Test
Compiled from "Test.java"
public class Test extends java.lang.Object
SourceFile: "Test.java"
minor version: 0
major version: 50
Constant pool:
const #1 = Method #7.#16; // java/lang/Object."<init>":()V
const #2 = String #17; // abc
const #3 = class #18; // java/lang/String
const #4 = String #19; // def
const #5 = Method #3.#20; // java/lang/String."<init>":(Ljava/lang/String;)V
const #6 = class #21; // Test
const #7 = class #22; // java/lang/Object
const #8 = Asciz <init>;
...
{
public Test(); ...
public static void main(java.lang.String[]);
Code:
Stack=3, Locals=3, Args_size=1
0: ldc #2; // Load string constant "abc"
2: astore_1 // Store top of stack onto local variable 1
3: new #3; // class java/lang/String
6: dup // duplicate top of stack
7: ldc #4; // Load string constant "def"
9: invokespecial #5; // Invoke constructor
12: astore_2 // Store top of stack onto local variable 2
13: return
}
除了已经发布的答案之外,还可以查看有关 javaranch 的这篇优秀文章。
根据String 类文档,它们是等价的。
文档String(String original)
还说:除非需要原始的显式副本,否则不需要使用此构造函数,因为字符串是不可变的。
寻找其他回应,因为 Java 文档似乎具有误导性 :(
以下是一些比较:
String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
System.out.println(s1 == s2); //true
System.out.println(s1.equals(s2)); //true
System.out.println(s1 == s3); //false
System.out.println(s1.equals(s3)); //true
s3 = s3.intern();
System.out.println(s1 == s3); //true
System.out.println(s1.equals(s3)); //true
当intern()
被调用时,引用被改变。
字符串对象和字符串字面量之间存在细微差别。
String s = "abc"; // creates one String object and one reference variable
在这个简单的例子中,“ abc ”将进入池中,s将引用它。
String s = new String("abc"); // creates two objects,and one reference variable
在这种情况下,因为我们使用了new
关键字,Java 将在普通(非池)内存中创建一个新的 String 对象,s将引用它。此外,文字“ abc ”将被放入池中。
String s = new String("FFFF")
创建 2 个对象:"FFFF"
字符串和String
对象,它们指向"FFFF"
字符串,所以它就像指向指针的指针(引用引用,我不喜欢术语)。
据说你永远不应该使用new String("FFFF")