什么是两者之间的区别?
String str = new String("abc");
并且String str = "abc";
什么是两者之间的区别?
String str = new String("abc");
并且String str = "abc";
new String("...")
时,将会创建一个新的字符串对象。String a = "abc";
String b = "abc";
System.out.println(a == b); // true
在这里,创建了两个不同的对象,它们具有不同的引用:
String c = new String("abc");
String d = new String("abc");
System.out.println(c == d); // false
new String(...)
,并不是因为有人想要这里描述的行为,而是因为他们不知道字符串是不可变的。
因此,你会看到像 b = new String(a); b = b.substring(2);
而不是仅仅 b = a.substring(2)
。可能是因为作者认为substring方法会修改被调用的实例。
另外,虽然 "abc" == "abc" 是正确的,但我会说,以这种方式依赖它而不使用equals(...)的代码是聪明和容易混淆的(静态final“常量”除外)。 - George Hawkinsnew String("...").intern()
... - Yousha Aleayoub字符串字面值 是Java语言的一个概念。以下是一个字符串字面值:
"a String literal"
一个 字符串对象 是 java.lang.String
类的一个实例。
String s1 = "abcde";
String s2 = new String("abcde");
String s3 = "abcde";
这些都是有效的,但有一点区别。 s1
将引用一个interned(内部化)的字符串对象。这意味着字符序列"abcde"
将存储在中央位置,并且每当相同的文字"abcde"
再次出现时,JVM将不会创建新的字符串对象,而是使用缓存的字符串的引用。
s2
保证是新的字符串对象,所以在这种情况下我们有:
s1 == s2 // is false
s1 == s3 // is true
s1.equals(s2) // is true
new String("abc")
一样是一个对象,唯一的区别是它存储在常量池中而不是堆中? - yifei长篇回答可以在这里找到,所以我会给你一个简短的回答。
当你这样做:
String str = "abc";
您正在调用 String 上的 intern()
方法。此方法引用了一个内部的字符串对象池。如果您在调用 intern()
方法时的字符串已经存在于池中,则将该字符串的引用分配给 str
。否则,新的字符串将被放入池中,并将其引用分配给 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
和str2
是对不同的Objects
的引用,它们都没有被interned,因此当您使用==
测试Object
的身份时,您将得到false
。==
检查字符串相等性,而是应该使用.equals()
。由于字符串是不可变的,所以当你执行以下操作时:
String a = "xyz"
在创建字符串时,JVM会在字符串池中搜索是否已经存在一个字符串值"xyz"
。如果是这样,那么'a'
将只是该字符串的引用,并且不会创建新的String对象。
但如果你使用:
String a = new String("xyz")
即使 "xyz"
已经存在于字符串常量池中,你也可以通过这种方式强制 JVM 创建一个新的 String
引用。
如需更多信息,请参阅此处。
"abc"
是一个字符串字面量。
在Java中,这些字面量字符串会被内部池化,并且相同的String实例会在你代码中声明相同的字符串字面量时被重用。因此,"abc" == "abc"
将始终为true,因为它们都是相同的String实例。
使用String.intern()
方法,你可以将任何你喜欢的字符串添加到内部池化的字符串中,这些字符串将一直保留在内存中,直到Java关闭。
另一方面,使用new String("abc")
将在内存中创建一个新的字符串对象,逻辑上与"abc"
字面量相同。"abc" == new String("abc")
将始终为false,因为虽然它们逻辑上相等,但它们指向不同的实例。
将字符串字面量放入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 st = "hello";
String
类的intern()
方法,它会检查"hello"
是否在内部池中,如果没有,则会将其添加到内部池中;如果"hello"
已经存在于内部池中,则st
将指向现有"hello"
的内存。因此,在以下情况下:String st3 = "hello";
String st4 = "hello";
在这里:
st3 == st4 // true
因为st3
和st4
指向相同的内存地址。
另外:
st3.equals(st4); // true as usual
$ 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
}
String(String original)
的文档还说:除非需要原始字符串的显式副本,否则使用此构造函数是不必要的,因为字符串是不可变的。new()
一个字符串是不必要的。@Jon:鉴于你的声誉,我不敢质疑你的答案,但我没有看到克隆的字符串字面量在任何方面与原始字符串“修剪”有任何联系。我想使用new("literal")
的唯一理由是获得一个保证不会与否则相同(相等)的原始字符串==
的字符串。 - Carl Smotricz
所有字符串字面量都会自动实例化为一个字符串对象。
。考试似乎认为这总是正确的,即使字面量被内部化到已经存在的对象中? - djangofan