public class Solution {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
ArrayList <String> list = new ArrayList<>();
for(;;)
{
String a = reader.readLine();
if(a.equals("结束")) // a = " 结束 " why can't ?
{ break;}
list.add(a);
}
for( String ohh : list)
{
System.out.println(ohh);
}
//在此编写你的代码
}
}
为什么 == 不可以
正在讨论
评论 (2)
- 受欢迎
- 新
- 旧
你必须先登录才能发表评论
老杨
25 二月 2022, 13:42
按照上面的代码修改,可以发现==也可以完成操作。
这里需要强调一个字符串常量池的概念,而并不是单纯的通过==和equals的比较判断问题。
诚然,==是等值判断,也就是内存地址的判断,equals是等价判断,也就是内容的判断,但是这种判断是建立在对象与对象间的关系中。
之所以之前的代码不可以通过==完成判断,其主要原因是从屏幕上读取的内容没有写入常量池造成的。
内存中分为堆内存,栈内存,公共内存等几个部分,通常对象变量写入栈内存,对象变量指向的具体内容写入堆内存,其他的均写入了公共内存。String本身是一个类,所有的通过“”包裹的字符串其本身都是一个String类的匿名对象。
而String类的实例化分为两种方式:直接赋值和new创建。
直接赋值顾名思义:
String str1 = "hello"
String str2 = "hello"
此时,str1和str2都是得到了hello这个值,而这种赋值方式会自动写入公共内存区域的字符串常量池,也就是说当str1的hello定义的时候,字符串常量池中就存放了一个hello,当str2定义赋值为hello的时候,首先先去字符串常量池查看有没有hello这个值,有了的话就直接将这个hello传递给str2,所以此时的str1和str2其内容与地址都相同,那么==和equals都可以判断为true。
new创建则相反,new是开辟堆内存的一种方式。
String str1 = new String("hello");
String str2 = new String("hello");
这种赋值方式是先在栈内存中分别开辟了两个空间,存储了两个变量:str1和str2。
然后分别在堆内存中开辟了两个空间存储了两个hello,这里已经说得很明确了,内存空间不一样,所以==的返回值就是false,而equals判断的就是两个hello的内容是否相等。
===============================以上是题外的判断分析===============================
回到这个案例,这个案例中有一个点就是所有的String都是通过BufferedReader从屏幕上输入得到的,而结束是一个匿名对象,首先要知道“结束”这个字符串已经在池中了。但是BufferedReader读取的内容是不会写入字符串常量池的,你可以认为不在池中的字符串,就一定是写入了堆内存,此时就必须通过equals比较其内容,而不能比较其内存地址。但是如果通过intern方法可以手动让字符串入池,一旦入池,就不但可以比较内容,也可以比较地址了。
题外话:BufferedReader读取的是行的内容,任何一个行内容,即便没有任何的值,也会有一个换行符”\n“,因此这个例题不会出现空字符串的问题。而equals方法有可能出现空指向异常,也就是通过空字符串调用equals方法时出现空调用。所以一般情况下建议将存在的字符串放在前面调用equals方法,括号里面放不确定的字符串,避免空调用引起的空指向异常。
+2
汪志强
25 二月 2022, 10:47
=在java是赋值,==在进行比较的时候,基本数据类型是比较其值,应用数据类型比较的其物理地址值,java中所有的类都是继承于Object这个超类的,Object类里面的equals方法是和==等价,但是String类里面的equals方法,重写了equals方法,equals()方法其实是比较两个字符串的内容,所以这里用a = " 结束 "是对a进行赋值,a是一个字符串,a = =" 结束 "是比较这a和结束的物理地址值,所以不行,a是一个字符串,equals方法才是比较值。
0