这个采访问题的共同商定答案是代码创建了两个对象。但我不这么认为;我写了一些代码来确认。
public class StringTest {
public static void main(String[] args) {
String s1 = "a";
String s2 = "a";
String s3 = new String("a");
System.out.println("s1: "+s1.hashCode());
System.out.println("s2: "+s2.hashCode());
System.out.println("s3: "+s3.hashCode());
}
}
输出结果为:
这是否意味着只创建了一个对象?
重申:我的问题是以下代码创建了多少个对象:
String s = new String("xyz")
而不是StringTest
代码。
受@Don Branson的启发,我调试了以下代码:
public class test {
public static void main(String[] args) {
String s = new String("abc");
}
}
结果是:
s的id为84,“abc”的id为82.这究竟是什么意思?
答案 0 :(得分:19)
首先,这个问题确实在这里提到了这个问题: Is String Literal Pool a collection of references to the String Object, Or a collection of Objects
所以,这是每个人在这个问题上的指南。
...
String s = new String(“xyz”)
有两种方法可以看到这个:
(1)代码行执行时会发生什么 - 它在程序中运行的字面时刻?
(2)声明创建了多少Objects
的净效应是什么?
a)当JVM加载包含此行代码的"xyz"
时,会创建并实现String
class
。
"xyz"
已经在实习池中,则该文字可能不会生成新的String
对象。 b)创建新的String s
后,内部char[]
是实习"xyz"
字符串的副本。
c)这意味着,当行执行时,只创建了一个额外的对象。
事实是,只要加载了类并且在运行此代码段之前,就会创建"xyz"
对象。
......下一个场景......
"a"
)String s1 = "a";
String s2 = "a";
String s3 = new String("a");
a)s1和s2只是被引用,而不是对象,并且它们在内存中指向相同的String
。
b)“a”是实体并且是复合对象:一个char[]
对象和String
对象本身。它由内存中的两个对象组成。
c)s3,new String("a")
再生一个对象。新String("a")
不会复制“a”的char[]
,它只会在内部引用它。这是方法签名:
public String2(String original) {
this.value = original.value;
this.hash = original.hash;
}
一个实习String
("a")
等于2 Objects
。一个new String("a")
等于另一个对象。代码的净效应是三个对象。
答案 1 :(得分:8)
将为此创建两个对象:
String s = new String("abc");
一个在堆中,另一个在"字符串常量池" (SCP)。引用s
将始终指向s
,并且SCP区域中不允许GC,因此SCP上的所有对象将在JVM关闭时自动销毁。
例如:
这里通过使用堆对象引用,我们通过调用intern()
获得相应的SCP对象引用String s1 = new String("abc");
String s2 = s1.intern(); // SCP object reference
System.out.println(s1==s2); // false
String s3 = "abc";
System.out.println(s2==s3); //True s3 reference to SCP object here
答案 2 :(得分:4)
有两种方法可以在Java中创建字符串对象:
使用new运算符,即
String s1 = new String("abc");
使用字符串文字,即
String s2 = "abc";
现在字符串分配在时间和内存上都很昂贵,因此JVM(Java虚拟机)执行一些任务。什么任务?
请参阅,无论何时使用new
运算符,都会创建对象,并且JVM不会查找字符串池。它只是要创建对象,但是当您使用字符串文字创建字符串对象时,JVM将执行查找字符串池的任务
即,当你写
时String s2 = "abc";
JVM将查找字符串池并检查" abc"已存在或不存在。如果它存在,则将引用返回到已存在的字符串" abc"并且没有创建新对象,如果它不存在,则创建一个对象。
所以在你的情况下 (a)中
String s1 = new String("abc");
new
,因此创建了对象(b)中
String s2 = "abc";
(c)中
String s2 = "abc";
您也可以使用以下代码查看:
class String_Check
{
public static void main(String[] n)
{
String s1 = new String("abc");
String s2 = "abc";
String s3 = "abc";
if (s1==s2)
System.out.println("s1==s2");
if(s1==s3)
System.out.println("s1==s3");
if(s2==s3)
System.out.println("s2==s3");
}
}
我希望这会有所帮助......请注意==
用于查看对象是否相等,并使用equals(Object)
方法查看内容是否相等。
答案 3 :(得分:2)
有很多随机答案,所以我有信心我的面试官也不太确定:) :)
我做了很多研究,发现哈希码不是内存地址,调试时的变量没有给出内存地址。因此,这些参数可能会造成混淆。
答案 4 :(得分:2)
String s = new String(" xyz");
上面一行将创建两个对象,一个在堆中,另一个在String常量池中。
现在如果我们这样做
String s = new String("xyz");
String s1 ="xyz";
以上两个语句将创建两个对象。
第一行String s = new String("xyz");
将创建两个如上所述的对象
在第一行中,当String s = "xyz";
执行时,如果存在相同的内容对象,则检查字符串常量池,因为第一行在字符串常量池中使用" xyz"它返回相同的引用,不会创建其他对象。
如果我们将这四条线放在一起,如下所述。
String s2 = new String("xyz");
String s3 ="xyz";
String s4 = new String("xyz");
String s5 ="xyz";
如果我们执行上述行,我们将有三个对象。
关于intern()
方法的奖金
当在String对象上调用intern()方法时,它看起来像 池中此String对象包含的字符串,如果是字符串 在那里发现然后返回池中的字符串。否则,这个 String对象被添加到池中以及对此String的引用 返回对象。
public class TestString {
public static void main(String[] args) {
String s1 = "Test";
String s2 = "Test";
String s3 = new String("Test");
final String s4 = s3.intern();
System.out.println(s1 == s2);
System.out.println(s2 == s3);
System.out.println(s3 == s4);
System.out.println(s1 == s3);
System.out.println(s1 == s4);
System.out.println(s1.equals(s2));
System.out.println(s2.equals(s3));
System.out.println(s3.equals(s4));
System.out.println(s1.equals(s4));
System.out.println(s1.equals(s3));
}
}

//Output
true
false
false
false
true
true
true
true
true
true

通过在新的字符串对象上应用实习方法来查看实习生的魔力。
实习生在这里应用,以便检查是否"测试"是否可以在字符串常量池中使用,因为"测试"在String常量池中可用,它将返回相同的对象,因此s3
具有与s1
和s2
相同的引用,并将所有结果都设为true
public class TestString {
public static void main(String[] args) {
String s1 = "Test";
String s2 = "Test";
String s3 = new String("Test").intern();
final String s4 = s3.intern();
System.out.println(s1 == s2);
System.out.println(s2 == s3);
System.out.println(s3 == s4);
System.out.println(s1 == s3);
System.out.println(s1 == s4);
System.out.println(s1.equals(s2));
System.out.println(s2.equals(s3));
System.out.println(s3.equals(s4));
System.out.println(s1.equals(s4));
System.out.println(s1.equals(s3));
}
}

true
true
true
true
true
true
true
true
true
true

答案 5 :(得分:2)
如果执行return personal.GetSubfolders (false).Where (x => X.Name != "Calendar" && x.Name != "Contacts").ToList ();
,则将创建两个对象。一个对象将在字符串文字池中创建,另一个将在堆区域中创建。
但是,如果我们已经有相同的字符串文字对象,则仅创建一个对象。
像
String s = new String("Brajesh");
答案 6 :(得分:1)
创建2或3个对象,具体取决于编译器的智能程度。
然而,您的测试是垃圾,因为hashCode
的{{1}}是基于String
的内容,而不是基于他们的身份。如果您想检查身份,则应使用String
或System.identityHashCode
比较。
允许编译器和运行时(非强制)尽可能优化字符串创建。因此,他们通过对您拥有的三个字符串使用单个文字来优化文字字符串。
无论如何,==
运算符必须返回 new 对象(即新分配的对象)。
如果使用静态方法new
,则可以在运行时进行字符串优化。但我不知道当前的JRE是否实际应用了任何缓存(检查哈希表可能比分配新的String.valueOf
更昂贵)
答案 7 :(得分:0)
2 个物体由:
String s = new String("xyz");
第一次在堆内存(字符串池)中创建新的字符串对象
第二次将 "xyz"
放入字符串常量池
答案 8 :(得分:0)
java.lang.String
会覆盖hashCode()
方法,以便该值取决于字符串的内容。
因此,hashCode()
不会告诉您有关实例数量的任何信息。它可以是相同的字符串,也可以是没有单字节共享的另一个实例。 equals()
相同。这解释了你的输出。
使用System.identityHashCode(..)进行此类研究。
答案 9 :(得分:0)
如果new String()创建2个对象(一个在堆中,一个在字符串池中),那么.intern方法的用途是什么?
在String对象上调用的intern()方法查找字符串 如果找到字符串,则此String对象包含在池中 然后从池中返回字符串。不然这样 将String对象添加到池中,并对此String进行引用 对象被返回。
答案 10 :(得分:0)
String s1="Pune";
String s2="Mumbai";
String s3="Pune";
String s4=new String("Mumbai");
System.out.println("S1 :"+s1.hashCode()); //S1 :2499228
System.out.println("S2 :"+s2.hashCode()); //S2 :-1979126203
System.out.println("S3 :"+s3.hashCode()); //S3 :2499228
System.out.println("S4 :"+s4.hashCode()); //S4 :-1979126203
System.out.println(s2==s4); // false
正如我们在上面的程序中看到的,我们分别获得了s2和s4的类似哈希码,尽管我们使用==运算符得到了错误。 ==运算符用于参考比较。
在" String s4 = new String(" Mumbai")"创建了两个对象,一个在堆内存中,一个在堆栈内存中。因此,s2与堆内存中创建的s4进行比较,而不是堆栈内存。
答案 11 :(得分:0)
与新的String(“ <>”)被调用后发生的确切情况相混淆,我找到了这个线程。您对哈希码比较的理解在技术上并不正确。
int hashCode()在String类中已被覆盖,并且它根据String文字的内容返回一个值。
String s1 = new String(“ Hello”); 字符串s2 =新的String(“ Hello”);
因此s1.hashCode()= s2.hashCode()= anyStringOfContent_“ Hello” .hashCode()
**/** Cache the hash code for the string */
private int hash; // Default to 0
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
**h = 31 * h + val[i];**
}
hash = h;
}
return h;
}**
现在仅要解释为什么这样做,您实际上可以阅读Kathy Sierra的书,该书很好地解释了开发人员以这种方式进行操作的方法(基本上,所有返回true的对象都应返回相同的equals()方法的值) )。
答案 12 :(得分:0)
public String(String original) {
int size = original.count;
char[] originalValue = original.value;
char[] v;
if (originalValue.length > size) {
// The array representing the String is bigger than the new
// String itself. Perhaps this constructor is being called
// in order to trim the baggage, so make a copy of the array.
int off = original.offset;
v = Arrays.copyOfRange(originalValue, off, off+size);
} else {
// The array representing the String is the same
// size as the String, so no point in making a copy.
v = originalValue;
}
this.offset = 0;
this.count = size;
this.value = v;
}
如果我们看到代码,我们可以看到它只会创建一个char []并且每次都会被复制,同时内容被实例化,是的,它会将数据存储在String Constant Pool中。 1)将取自SCP String s1 =&#34; a&#34;字符串s2 =&#34; a&#34 ;; 2)创建一个新对象String s3 = new String(&#34; a&#34;);好奇心,新对象字符串s2 =新字符串(&#34; a&#34;);在以上所有代码中相同的char []将被复制.i:e char [] value You can check here
答案 13 :(得分:0)
如果在调试模式下在eclipse中运行以下代码,我们将了解如何使用String string = new String("manoj");
创建多少个对象,内部将在String类构造函数中创建String str = "manoj"
。
将鼠标悬停在参考上之后,只需检查 id 即可,如下面的屏幕截图所示。
ScreenShot
public static void main(String[] args)
{
String str = "atul";
String string = new String("manoj");
String string2 = "manoj";
System.out.println(str == string);
}
答案 14 :(得分:-1)
我在Eclipse调试器中运行它。在该上下文中,创建了两个对象,一个具有id 17,另一个具有22:
答案 15 :(得分:-1)
@Giulio,你是对的。 String s3 = new String(“abc”);在堆中创建两个对象,其中一个在参考s3中,另一个在SCP中(没有参考)。 现在String s2 =“abc”;不会在SCP中创建任何新对象,因为SCP中已存在“abc”。
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = s3.intern();
System.out.println("s1: "+System.identityHashCode(s1));
System.out.println("s2: "+System.identityHashCode(s2));
System.out.println("s3: "+System.identityHashCode(s3));
System.out.println("s4: "+System.identityHashCode(s4));
O / P:s1:366712642, s2:366712642, s3:1829164700, s4:366712642
由于我没有资格发表评论,我在这里写了。
答案 16 :(得分:-2)
String s = new String(“ xyz”);
以上代码中创建了多少个对象?
以上代码中仅创建了一个对象,该对象位于堆内存中。
不是两个对象.....
如果创建了两个对象,则一个对象位于堆内存(新运算符)中,而另一个对象位于字符串常量池(字符串文字)中(如果您使用字符串文字在值以下存储)
字符串s1 =“ xyz”;
它不会在字符串常量池中返回对象 s 的引用。它将在字符串常量池中以 s1 创建新对象。
如何?
我们可以通过使用==运算符(s == s1)来检查引用类型来进行检查。 如果 s 已存储在String Constant Pool中,则它为true,在这种情况下输出为false。
所以结论是上面的代码创建了一个对象。
答案 17 :(得分:-2)
Java中有一个名为字符串池的概念。字符串池(字符串实习池)是Java堆中的特殊存储区域。创建字符串并且池中已存在该字符串时,将返回现有字符串的引用,而不是创建新对象并返回其引用。
所以String s = new String(“xyz”)
它将创建两个对象。
第一个对象将在Java永久堆内存中创建,作为我们传递的参数的一部分 - &#34; XYZ&#34;。它将在String Literal Pool中创建。
第二个对象将在Java堆内存中创建 - 它将作为new
运算符的一部分创建。
答案 18 :(得分:-3)
有一种方法可以使用new
关键字(String s1=new String("Rajesh")
)找到创建的对象数。
public class Rajesh {
public static void main(String[] args){
String s1=new String("Rajesh");
System.out.println(s1+s1.intern());
}
}
输出:
RajeshRajesh //s1=Rajesh+s2.intern()=Rajesh
注意:我们知道intern方法总是命中堆内存的字符串常量池。
答案 19 :(得分:-3)
我使用hashcode()
方法查找创建的字符串对象的数量。
hashcode()
方法将存储在引用变量中的数据摘要为单个哈希值。
<强> CASE1:强>
String s="
Fred";
System.out.println(s.hashCode());
s=s+"47";
System.out.println(s.hashCode());
s=s.substring(2,5);
System.out.println(s.hashCode());
s=s.toUpperCase();
System.out.println(s.hashCode());
s=s.toString();
System.out.println(s.hashCode());
输出为:
Fred--2198155 //1st object ---------------- String s="Fred"
Fred47--2112428622 //2nd object ---------------- s=s+"47"
ed4--100213 //3rd object ---------------- s=s.substring(2,5)
ED4--68469 //4th object ---------------- s=s.toUpperCase()
ED4--68469 //this is retrieved from the string constant pool -------- s=s.toString();
总共创建了4个对象。
案例2:
String s="FRED";
System.out.println(s.hashCode());
s=s+"47";
System.out.println(s.hashCode());
s=s.substring(2,5);
System.out.println(s.hashCode());
s=s.toUpperCase();
System.out.println(s.hashCode());
s=s.toString();
System.out.println(s.hashCode());
输出为:
FRED--2166379 //1st object ---------------- String s="Fred"
FRED47--2081891886 //2nd object ---------------- s=s+"47"
ED4--68469 //3rd object ---------------- s=s.substring(2,5)
ED4--68469 //this is retrieved from the string constant pool ------- s=s.toUpperCase()
ED4--68469 //this is retrieved from the string constant pool -------- s=s.toString()
总共创建了3个对象。
答案 20 :(得分:-3)
仅仅因为所有哈希码都相同并不意味着您正在查看同一个对象。创建了两个对象。让我们打破这个。
String s = new String(“xyz”);
在“new String(”xyz“)'部分中,地址返回到新字符串”xyz“。当你说'String s ='时,这会将返回的地址分配给这个对象,以便它们指向同一个地方,但是新的字符串和字符串s是两个单独的对象。