首页 > 试题广场 >

有以下代码片段: String str1=”hello”;

[单选题]

有以下代码片段:

String str1="hello";

String str2="he"+ new String("llo");

System.out.println(str1==str2);
请问输出的结果是:

  • true
  • 都不对
  • null
  • false
D。
如果是
String str1 = "hello";
String str2 = "hello";
那么str1 == str2为true,而str2中有新申请的地址空间,两个字符串所指的地址不同,所以str1 == str2为false。
发表于 2017-03-14 20:02:14 回复(3)
更多回答

1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。

2)String类底层是char数组来保存字符串的。

对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象


字符串常量池

在class文件中有一部分来存储编译期间生成的字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池

JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池

工作原理

当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。

实现前提

字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。


String str1 = "hello";

这里的str1指的是方法区中的字符串常量池中的“hello”,编译时期就知道的;

String str2 = "he" + new String("llo");

这里的str2必须在运行时才知道str2是什么,所以它是指向的是堆里定义的字符串“hello”,所以这两个引用是不一样的。

如果用str1.equal(str2),那么返回的是true;因为String类重写了equals()方法

编译器没那么智能,它不知道"he" + new String("llo")的内容是什么,所以才不敢贸然把"hello"这个对象的引用赋给str2.

如果语句改为:"he"+"llo"这样就是true了。

new String("zz")实际上创建了2个String对象,就是使用“zz”通过双引号创建的(在字符串常量池),另一个是通过new创建的(在堆里)。只不过他们的创建的时期不同,一个是编译期,一个是运行期。

String s = "a"+"b"+"c";

语句中,“a”,"b", "c"都是常量,编译时就直接存储他们的字面值,而不是他们的引用,在编译时就直接将它们连接的结果提取出来变成"abc"了。


csdn:https://blog.csdn.net/u013309870

编辑于 2019-01-15 22:14:43 回复(36)
答案:D
String str1="hello";    这样创建字符串是存在于常量池中
String str2=new String("hello");    str2存在于堆中,
==是验证两个对象是否是一个(内存地址是否相同)
用+拼接字符串时会创建一个新对象再返回。
发表于 2016-12-05 20:37:15 回复(7)
String str1="hello";
String str2="he"+ new String("llo");
String str3="hello";
String str4=new String("Hello");
String str5="hel"+"lo";
        
System.out.println(str1==str2);
System.out.println(str1==str3);
System.out.println(str1==str4);
System.out.println(str1==str5);
这个代码的运行结果是
false
true
false
true
发表于 2018-05-05 19:44:48 回复(2)
“hello”存放在 常量池
new String("llo") 存放在 堆 中;
==  比较的是地址,所以很明显不相等;;
发表于 2017-01-20 21:53:55 回复(1)
String str2="he"+ new String("llo");//这个不能被优化,编译期new没有发生,无法从现在判断未来
String str2="he"+ “llo”  //这个会被编译器优化,这个可以判断出未来的值 就是hello
发表于 2018-03-06 14:31:40 回复(0)
JVM指令 :
String str2="he"+ new String("llo");
相当于new StringBuilder().append("he").append("llo").toString();
而在运行到toString()时,又new String("hello",...),在堆中,因此返回false;


编辑于 2021-06-23 21:29:13 回复(1)
String str1 = "hello";
//在字符串常量池中创建一个字符串

String str2 = "he" + new String("llo");
// new String("llo");在堆中创建一个对象,内容为"llo"
 "he" + new String("llo");在堆中创建一个对象,内容为"hello"

== 判断的是内存中的地址 
jdk7之后字符串常量池转移到了堆中
编辑于 2018-06-02 00:23:56 回复(0)
直接声明的在常量池中,new的在堆中
发表于 2023-07-17 19:28:55 回复(0)
=号比的是引用地址equals比的是内容
发表于 2021-04-22 18:52:40 回复(0)
对于本问题的思考补充:
1、String s = "a" + "b" + "c";       ——此语句共创建了几个对象, 
    最多创建了一个 ,对于   String s = "a" + "b" + "c" ;     赋值符号右边的"a"、"b"、"c"都是常量 ,对于常量,编译时就直接存储它们的字面值而不是它们的引用 ,在编译时就直接将它们连接的结果提取出来变成了"abc" ,该语句在class文件中就相当于String s = "abc" 。
    然后当JVM执行到这一句的时候, 就在String pool里找 ,如果没有这个字符串,就会在字符串常量池产生一个 "abc" 字符串。如果存在,则不会创建新的字符串。

2、对于  String str = "aaa" ;  String str = new String("aaa")  这两句的分析。
    1)第一种   String str = "aaa" ;   是采用字面值创建,采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"aaa"这个对象,如果不存在,则在字符串池中创建"aaa"这个对象,然后将池中"aaa"这个对象的引用地址返回给字符串常量str,这样str会指向池中"aaa"这个字符串对象;如果存在,则不创建任何对象,直接将池中"aaa"这个对象的地址返回,赋给字符串常量。
    2)采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"aaa"这个字符串对象,如果有,则不在池中再去创建"aaa"这个对象了,直接在堆中创建一个"aaa"字符串对象,然后将堆中的这个"aaa"对象的地址返回赋给引用str3,这样,str3就指向了堆中创建的这个"aaa"字符串对象;如果没有,则首先在字符串池中创建一个"aaa"字符串对象,然后再在堆中创建一个"aaa"字符串对象,然后将堆中这个"aaa"字符串对象的地址返回赋给str3引用,这样,str3指向了堆中创建的这个"aaa"字符串对象,此时相当于创建了2个对象,一个在字符串常量池,一个在堆中。
发表于 2020-04-02 14:48:12 回复(1)
这道题选D但其中知识不简单
发表于 2019-09-16 15:09:30 回复(0)
今天看了Java疯狂讲义最后一章类加载器的内容,结合这一题有一个大胆的想法。就是string类是final的,那么字符串就在编译前确定内容,即“宏变量”,而那个new string()必须在类加载后才知道内容,导致无法确定变量内容。不知道是不是这样
发表于 2018-04-18 01:10:48 回复(0)
1、String str1 = “hello” 在常量池中
2、new String("llo") 是运行时在堆空间创建的,“he”+new String("llo")是在堆中
发表于 2017-10-16 16:55:10 回复(0)
1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。 2)String类底层是char数组来保存字符串的。 对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象 字符串常量池 在class文件中有一部分来存储编译期间生成的字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。 实现前提 字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。 String str1 = "hello"; 这里的str1指的是方法区中的字符串常量池中的“hello”,编译时期就知道的; String str2 = "he" + new String("llo"); 这里的str2必须在运行时才知道str2是什么,所以它是指向的是堆里定义的字符串“hello”,所以这两个引用是不一样的。 如果用str1.equal(str2),那么返回的是true;因为String类重写了equals()方法。 编译器没那么智能,它不知道"he" + new String("llo")的内容是什么,所以才不敢贸然把"hello"这个对象的引用赋给str2. 如果语句改为:"he"+"llo"这样就是true了。 new String("zz")实际上创建了2个String对象,就是使用“zz”通过双引号创建的(在字符串常量池),另一个是通过new创建的(在堆里)。只不过他们的创建的时期不同,一个是编译期,一个是运行期。 String s = "a"+"b"+"c"; 语句中,“a”,"b", "c"都是常量,编译时就直接存储他们的字面值,而不是他们的引用,在编译时就直接将它们连接的结果提取出来变成"abc"了。
发表于 2017-10-13 19:20:51 回复(0)
String str1 = "hello";
    String str2="he"+ new String("llo");
    System.out.println(str1==str2);//false

    String str3 = "hello";
    String str4 = "he" + "llo";
    System.out.println(str3==str4);//true

我对上面的结果的认识为,str4拼接的时候,因为此时的“he”以及“llo”是存在于常量池里面的两个对象,所以会在常量池里面寻找一个“hello”的对象,然后让str4指向它。但是在str1和str2的情况下str2的“llo”是在堆里面被new了出来的新对象,和str1拼接的时候会重新生成一个“hello”对象,所以这两个对象是不会一样的。如果说错希望大神指正,谢谢。
编辑于 2017-08-21 14:58:21 回复(0)
1)String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。在Java中,被final修饰的类是不允许被继承的,并且该类中的成员方法都默认为final方法。 2)String类底层是char数组来保存字符串的。 对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象 字符串常量池 在class文件中有一部分来存储编译期间生成的字面常量以及符号引用,这部分叫做class文件常量池,在运行期间对应着方法区的运行时常量池。 JVM为了减少字符串对象的重复创建,其维护了一个特殊的内存,这段内存被成为字符串常量池或者字符串字面量池 工作原理 当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。 实现前提 字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。 String str1 = "hello"; 这里的str1指的是方法区中的字符串常量池中的“hello”,编译时期就知道的; String str2 = "he" + new String("llo"); 这里的str2必须在运行时才知道str2是什么,所以它是指向的是堆里定义的字符串“hello”,所以这两个引用是不一样的。 如果用str1.equal(str2),那么返回的是true;因为String类重写了equals()方法。 编译器没那么智能,它不知道"he" + new String("llo")的内容是什么,所以才不敢贸然把"hello"这个对象的引用赋给str2. 如果语句改为:"he"+"llo"这样就是true了。 new String("zz")实际上创建了2个String对象,就是使用“zz”通过双引号创建的(在字符串常量池),另一个是通过new创建的(在堆里)。只不过他们的创建的时期不同,一个是编译期,一个是运行期。 String s = "a"+"b"+"c"; 语句中,“a”,"b", "c"都是常量,编译时就直接存储他们的字面值,而不是他们的引用,在编译时就直接将它们连接的结果提取出来变成"abc"了。
发表于 2023-03-14 08:52:47 回复(0)
选D
String str1="hello"; 创建的字符串存储在常量池中;而String str2=new String("hello");    存在于堆中。两个值的地址不一样,而“”==“”比较内存地址值,str1和str地址不同,所以为答案false。
发表于 2022-07-21 09:38:34 回复(0)
答案是错的 运行后会报错。
发表于 2022-06-24 09:35:41 回复(0)
String base="hello"; String str1="he"; String str2="llo"; String str3=str1+str2; String str4="he"+"llo"; String str5="he"+new String("llo"); System.out.println(base==str3); // false:用变量名相加会创建对象来接收 System.out.println(base==str4); // true:用“”相加编译器会做优化,不会创建新的对象 System.out.println(base==str5); // false:会创建新的对象来接收
发表于 2023-04-04 17:05:34 回复(0)