string对象和string之间的区别
有什么区别
String str = new String("abc");
和
String str = "abc";
当你使用一个string时,string可以被拦截 ,但是当你使用new String("...")
你会得到一个新的string对象。
在这个例子中,两个string文字都引用同一个对象:
String a = "abc"; String b = "abc"; System.out.println(a == b); // true
这里创build了2个不同的对象,它们有不同的引用:
String c = new String("abc"); String d = new String("abc"); System.out.println(c == d); // false
一般来说,应尽可能使用string文字符号。 它更容易阅读,并使编译器有机会优化您的代码。
一个string文字是一个Java语言的概念。 这是一个string文字:
"a String literal"
一个String对象是java.lang.String
类的一个单独的实例。
String s1 = "abcde"; String s2 = new String("abcde"); String s3 = "abcde";
所有这些都是有效的,但是有一点差别。 s1
将引用一个实际的string对象。 这意味着字符序列"abcde"
将存储在中心位置,并且每当再次使用相同的字面值"abcde"
时,JVM将不会创build新的String对象,而是使用caching的 String的引用。
s2
保证是一个新的String对象 ,所以在这种情况下我们有:
s1 == s2 // is false s1 == s3 // is true s1.equals(s2) // is true
在这里可以find很长的答案,所以我会给你一个短的答案。
当你这样做:
String str = "abc";
您正在调用String上的intern()
方法。 这个方法引用一个 String
对象的内部池 。 如果您调用intern()
的string已经驻留在池中,那么将该String
的引用赋值给str
。 如果没有,那么新的String
被放置在池中,然后对它的引用被分配给str
。
给出以下代码:
String str = "abc"; String str2 = "abc"; boolean identity = str == str2;
当你通过执行==
检查对象的身份(你真的在问:这两个引用指向同一个对象吗?),你会得到true
。
但是,你不需要 intern()
Strings
。 您可以通过执行以下操作在堆上的新Object
上强制创build:
String str = new String("abc"); String str2 = new String("abc"); boolean identity = str == str2;
在这种情况下, str
和str2
是对不同Objects
引用,这两个Objects
都没有被执行 ,所以当你使用==
testingObject
标识时,你将会得到false
。
在良好的编码实践方面:不要使用==
来检查string是否相等,而是使用.equals()
。
由于string是不可变的,当你这样做的时候:
String a = "xyz"
在创buildstring时,JVM在string池中search是否已经存在string值"xyz"
,如果是这样'a'
话,那么'a'
只是该string的引用,并且不会创build新的string对象。
但是如果你说:
String a = new String("xyz")
您强制JVM创build一个新的String
引用,即使"xyz"
在其池中。
欲了解更多信息,请阅读。
"abc"
是一个文字string。
在Java中,这些文字string在内部汇集,并且使用相同的string"abc"
实例,您可以在代码中声明string字面值。 所以"abc" == "abc"
将始终为真,因为它们都是相同的String实例。
使用String.intern()
方法,您可以将任何string添加到内部共用string中,这些string将保留在内存中,直到java退出。
另一方面,使用new String("abc")
将在内存中创build一个新的string对象,这在逻辑上与"abc"
字面值相同。 "abc" == new String("abc")
将始终为false,因为尽pipe它们在逻辑上相同,但它们指的是不同的实例。
围绕string包装一个String构造函数是没有价值的,它只是不必要地使用了比需要更多的内存。
string是Java中与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";
在这里,调用String
类的intern()
方法,并检查"hello"
是否在intern池中,如果没有,则将其添加到intern池中,如果intern池中存在“hello”, st
将指向记忆现有的"hello"
。
所以在下列情况下:
String st3 = "hello"; String st4 = "hello";
这里:
st3 == st4 // true
因为st3
和st4
指向相同的内存地址。
也:
st3.equals(st4); // true as usual
在第一种情况下,创build了两个对象。
在第二种情况下,这只是一个。
尽pipe两种方式都是指"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)
文档还说: 除非需要显式拷贝原始文件,否则不需要使用这个构造函数,因为string是不可变的。
寻找其他答案,因为看起来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对象和string之间存在细微差别。
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将在普通(非池)内存中创build一个新的String对象, s将引用它。 另外,文字“ abc ”将被放置在池中。
String s = new String("FFFF")
创build2个对象: "FFFF"
string和String
对象,它们指向"FFFF"
string,所以它就像指向指针的指针(引用引用,我不热衷于术语)。
据说你不应该使用new String("FFFF")