public class TestWhile{ //1
public static void main(String[] args)//2
{
Integer i=0;//3
Integer j=0;//4
// Integer i=new Integer(0);//5
// Integer j=new Integer(0);//6
while(i<=j & i>=j & i!=j)//7
{ //8
System.out.println("0000");//9
} }}
那一行是拆箱?while循环里的条件看似不成立,可为什么可以运行(去掉第5、6行的注释后)?
public static void main(String[] args)//2
{
Integer i=0;//3
Integer j=0;//4
// Integer i=new Integer(0);//5
// Integer j=new Integer(0);//6
while(i<=j & i>=j & i!=j)//7
{ //8
System.out.println("0000");//9
} }}
那一行是拆箱?while循环里的条件看似不成立,可为什么可以运行(去掉第5、6行的注释后)?
解决方案 »
- 关于构造方法
- 如何在在读取文件时定位及删除行?
- 高手指教,一个关于table的疑问!!!
- 在JAVA web start中,在文本条 文本框中输入中文时,弹出的输入框又笨又大又是双层的,难看死了
- 我没错Sketch.java uses or overrides a deprecated API.!为啥里????
- 关于java程序的打包问题....请指教!!!
- 关于tomcat很急的怪问题?
- 关于JFileChooser()的一个问题............
- 我想请问一下用JBilder或其它JAVA开发工具是不是都要自己用布局管理器来控制界面呢?(在线等待100分)
- 一个新手问题,在线等待,多谢帮助!
- java MenuItem 怎样增加Icon图像呢?
- 关于一条简单的sql语句。。。。
while(i.intValue()<=j.intValue() & i.intValue()>=j.intValue() & i.intValue()!=j.intValue())while条件不成立的原因是:
i 是 0,j 也是0
i<=j 是 true
i>=j 是 true
i!=j 是 false
true & true & false 是 false,所以条件不成立
因为 i, j 被定义成了 Integer,所以是对象
但程序可以运行,只是while条件不成立而已,不输出 0000
while(i<=j & i>=j & i!=j) 这句是拆箱
分析的很详细,还要注意& 与 &&的区别
Integer i=new Integer(0);
Integer j=new Integer(0);
while (i <= j & i >= j & i != j){
System.out.println("0000");
}i <= j true
i >= j true
这两句是自动拆箱
i != j true
这句比较的是对象,i,j是两个不同的对象。
所以这个条件是true的。语句自然可以执行
记得在java解惑这本书看到过这个题
7行i<=j 和 i>=j 是拆箱成int比大小,都为true;i!=j 则是判断i和j是否指向同一对象,显然i、j是指向两个对象,i!=j也为true。while循环条件成立,9行会得到执行
public class Test { //1 public static void main(String[] args)//2
{
Integer i = 0;//3
Integer j = 0;//4
// Integer i=new Integer(0);//5
// Integer j=new Integer(0);//6
while (i <= j & i >= j & i != j)//7
{ //8
System.out.println("0000");//9
} }
}这种情况下,循环不能运行。
对于Integer类型,<,<=,>,>=操作将导致拆箱操作,也就是调用Integer的intValue()方法得到相应的基本类型值,然后比较。
==,!=比较变量的值。 Integer i = 0;//3
Integer j = 0;//4
这两句使用装箱操作,也就是调用Integer.valueOf(int i);注意,不是使用new。Integer中,valueOf(int i)的方法体为: public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
//预先创建的Integer对象,-128~+127
private static class IntegerCache {
private IntegerCache(){} static final Integer cache[] = new Integer[-(-128) + 127 + 1]; static {
for(int i = 0; i < cache.length; i++)
cache[i] = new Integer(i - 128);
}
}所以,i和j引用的是同一个对象。
综上,i<=j & i>=j & i!=j中,
i<=j 和 i>=j都成立,而i!=j不成立,因为i和j引用的是同一个对象。故此,循环不会执行。注释掉3,4两句,使用5,6两句时,i和j引用的不是同一个对象,所以i!=j成立。i<=j & i>=j & i!=j成立,循环条件总是成立的,while (i <= j & i >= j & i != j)成为无穷循环,不断输出。
循环者的诅咒
请提供一个对i的声明,将下面的循环转变为一个无限循环:
while (i <= j && j <= i && i != j) {
}
噢,不,不要再给我看起来不可能的循环了!如果i <= j 并且 j <= i,i不是肯定等于j吗?这一属性对实数肯定有效。事实上,它是如此地重要,以至于它有这样的定义:实数上的≤关系是反对称的。Java的<=操作符在5.0版之前是反对称的,但是这从5.0版之后就不再是了。
直到5.0版之前,Java的数字比较操作符(<、<=、>和>=)要求它们的两个操作数都是原始数字类型的(byte、char、short、int、long、float和double)[JLS 15.20.1]。但是在5.0版中,规范作出了修改,新规范描述道:每一个操作数的类型必须可以转换成原始数字类型[JLS 15.20.1,5.1.8]。问题难就难在这里了。
在5.0版中,自动包装(autoboxing)和自动反包装(auto-unboxing)被添加到了Java语言中。如果你对它们并不了解,请查看:http://java.sun.com/j2se/5.0/docs/guide/language/autoboxing.html [Boxing]。<=操作符在原始数字类型集上仍然是反对称的,但是现在它还被应用到了被包装的数字类型上。(被包装的数字类型有:Byte、Character、Short、Integer、Long、Float和Double。)<=操作符在这些类型的操作数上不是反对称的,因为Java的判等操作符(==和!=)在作用于对象引用时,执行的是引用ID的比较,而不是值的比较。
让我们更具体一些,下面的声明赋予表达式(i <= j && j <= i && i != j)的值为true,从而将这个循环变成了一个无限循环:
Integer i = new Integer(0);
Integer j = new Integer(0);
前两个子表达式(i <= j 和j <= i)在i和j上执行解包转换[JLS 5.1.8],并且在数字上比较所产生的int数值。i和j都表示0,所以这两个子表达式都被计算为true。第三个子表达式(i != j)在对象引用i和j上执行标识比较,因为它们都初始化为一个新的Integer实例,因此,第三个子表达式同样也被计算为true,循环也就永远地环绕下去了。
你可能会感到奇怪,为什么语言规范没有修改为:当判等操作符作用于被包装的数字类型时,它们执行的是值比较。答案很简单:兼容性。当一种语言被广泛使用之后,以违反现有规范的方式去改变现有程序的行为是让人无法接受的。下面的程序过去总是保证可以打印false,因此它必须继续保持此特征:
public class ReferenceComparison {
public static void main(String[] args) {
System.out.println(
new Integer(0) == new Integer(0));
}
}
判等操作符在其两个操作数中只有一个是被包装的数字类型,而另一个是原始类型时,执行的确实是数值比较。因为这在5.0版之前是非法的,所有在这里没有任何兼容性的问题。让我们更具体一些,下面的程序在1.4版中是非法的,而在5.0版中将打印true:
public class ValueComparison {
public static void main(String[] args) {
System.out.println(
new Integer(0) == 0);
}
}
总之,当两个操作数都是被包装的数字类型时,数值比较操作符和判等操作符的行为存在着根本的差异:数值比较操作符执行的是值比较,而判等操作符执行的是引用标识的比较。
对语言设计者来说,如果判等操作符一直执行的都是数值比较(谜题13),那么生活可能就要简单得多、快乐得多。也许真正的教训应该是:语言设计者应该拥有高质量的水晶球,以预测语言的未来,并且做出相应的设计决策。严肃一点地讲,语言设计者应该考虑语言可能会如何演化,并且应该努力去最小化在演化之路上的各种制约影响。