String s = new String(“xyz”)。 执行这行代码后,有多少个对象被创建?
这个采访问题的共同商定答案是代码创建了两个对象。 但我不这么认为; 我写了一些代码来确认。
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.这究竟是什么意思?
除了您使用的JVM / JRE之外,还有哪些错误。 更好的是不要担心像这样的事情。 有关任何更正/关注,请参阅评论部分。
首先,这个问题确实在这里解决了这个问题: String Literal Pool是对String对象的引用的集合,还是对象的集合
所以,这是每个人在这个问题上的指南。
…
给定以下代码行: String s = new String(“xyz”)
有两种方式可以看到这个:
(1)当代码行执行时会发生什么 – 它在程序中运行的字面时刻?
(2)声明创建了多少个Objects
的净效果是什么?
回答:
1) 执行此操作后,将创建一个附加对象。
a)当JVM加载包含这行代码的class
时,创建并实现"xyz"
String
。
- 如果
"xyz"
已经在其他代码的实习池中,那么文字可能不会产生新的String
对象。
b)当创建新的String s
,内部char[]
是实习的"xyz"
字符串的副本。
c)这意味着,当行执行时 ,只创建了一个附加对象。
事实上,只要加载了类并且在运行此代码段之前,就会创建"xyz"
对象。
……下一个场景……
2)代码创建了三个对象( 包括实习"a"
)
String s1 = "a"; String s2 = "a"; String s3 = new String("a");
a)s1和s2只是被引用,而不是对象,它们指向内存中的相同String
。
b)“a”是interned并且是一个复合对象:一个char[]
对象和String
对象本身。 它由内存中的两个对象组成。
c)s3, new String("a")
产生一个对象。 新的String("a")
不复制String("a")
的char[]
,它只在内部引用它。 这是方法签名:
public String2(String original) { this.value = original.value; this.hash = original.hash; }
一个实习String
("a")
等于2个Objects
。 一个new String("a")
等于另一个对象。 代码的净效果是三个对象。
将为此创建两个对象:
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
有两种方法可以在Java中创建字符串对象:
-
使用new运算符,即
String s1 = new String("abc");
-
使用字符串文字,即
String s2 = "abc";
现在,字符串分配在时间和内存上都很昂贵,因此JVM(Java虚拟机)执行一些任务。 什么任务?
请参阅,无论何时使用new
运算符,都会创建对象,并且JVM不会查找字符串池。 它只是创建对象,但是当您使用字符串文字创建字符串对象时,JVM将执行查找字符串池的任务
即,当你写作
String s2 = "abc";
JVM将查找字符串池并检查“abc”是否已存在。 如果存在,则将引用返回到已存在的字符串“abc”,并且不创建新对象,如果它不存在,则创建对象。
所以在你的情况下(一)
String s1 = new String("abc");
- 由于使用了
new
,因此创建了对象
(b)中
String s2 = "abc";
- 使用字符串文字创建一个对象,并且“abc”不在字符串池中,因此创建了该对象。
(C)
String s2 = "abc";
- 再次使用字符串文字和“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)
方法查看内容是否相等。
-
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";
如果我们执行上面的行,我们将有三个对象。
- 第一个和前面提到的将在堆中创建两个对象,在String常量轮询中创建另一个。
- 当第二行执行时,它检查字符串常量轮询
并找到“xyz”所以它返回相同的对象,所以直到第二行我们有两个对象。 - 当第三行执行时,它将在堆中创建一个新对象,因为new运算符在堆中创建对象,因此直到第三行将有3个对象。
- 当第四行执行时,它检查字符串常量轮询
并找到“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)); } }
如果我们执行String s = new String("Brajesh");
,应创建两个对象。 将在字符串文字池中创建一个对象,在堆区域中创建另一个对象。 但是如果我们已经有相同的字符串文字对象,那么只创建一个对象。 喜欢
String s1 ="Brajesh"; String s = new String("Brajesh");//it will create only one object in heap area
除此之外,还在char区域中创建了另一个对象,即char []的对象。 我附上了堆内存的快照。
根据编译器的智能程度创建2或3个对象。
然而,你的测试是垃圾,因为String
的hashCode
是基于String
的内容,而不是它们的身份。 如果要检查标识,则应使用System.identityHashCode
或仅使用==
比较。
允许编译器和运行时(非强制)尽可能优化字符串创建。 因此,他们通过使用您拥有的三个字符串的单个文字来优化文字字符串。 无论如何, new
运算符必须返回一个新对象(即新分配的对象)。 如果使用静态方法String.valueOf
则可以在运行时进行字符串优化。 但我不知道当前的JRE是否实际应用了任何缓存(检查哈希表可能比仅分配新的String
更昂贵)
java.lang.String
重写hashCode()
方法,以便该值取决于字符串的内容 。
因此, hashCode()
不会告诉您有关实例数量的任何信息。 它可以是相同的字符串,也可以是没有单字节共享的另一个实例。 关于equals()
。 这解释了你的输出。
使用System.identityHashCode(..)进行此类研究。
也许消息来源与你同在 。
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进行比较,而不是与堆栈内存进行比较。
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 =“a”String s2 =“a”; 2)创建一个新对象String s3 = new String(“a”); 好奇心,新对象字符串s2 =新字符串(“a”); 在以上所有代码中, 相同的char []将被复制.i:e char [] value 您可以在此处查看
如果我们在调试模式下在eclipse中运行下面的代码,我们将了解使用String string = new String("manoj");
创建了多少个对象String string = new String("manoj");
在内部,它将在String类构造函数中创建String str = "manoj"
。 只需在hover在参考上后检查ID ,如下面的屏幕截图所示。 截图
public static void main(String[] args) { String str = "atul"; String string = new String("manoj"); String string2 = "manoj"; System.out.println(str == string); }
我在Eclipse调试器中运行它。 在该上下文中,创建了两个对象,一个具有id 17,另一个具有22:
@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
由于我没有资格评论,我在这里写了。
Java中有一个名为字符串池的概念。 字符串池(字符串实习池)是Java堆中的特殊存储区域。 创建字符串并且池中已存在该字符串时,将返回现有字符串的引用,而不是创建新对象并返回其引用。
所以String s = new String(“xyz”)
它将创建两个对象。
-
第一个对象将在Java永久堆内存中创建,作为我们传递的参数的一部分 – “XYZ”。 它将在String Literal Pool中创建。
-
第二个对象将在Java堆内存中创建 – 它将作为
new
运算符的一部分创建。
仅因为所有哈希码都相同并不意味着您正在查看同一个对象。 创建了两个对象。 让我们打破这个。
String s = new String(“xyz”);
在“new String(”xyz“)’部分中,地址返回到新字符串”xyz“。 当你说’String s =’时,这会将返回的地址分配给这个对象,这样它们就指向同一个地方,但是新的字符串和字符串s是两个单独的对象。
我使用hashcode()
方法查找创建的字符串对象的数量。 hashcode()
方法将存储在引用变量中的数据摘要化为单个散列值。
情况1:
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个对象。
有一种方法可以找到使用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
注意:正如我们所知,实习方法始终会命中堆内存的字符串常量池。