如果我们可以将 Integer 对象类型转换为 Object 并将 Integer 拆箱为 int,为什么我们不能将相同的 Object 类型拆箱为 int?
Integer i=new Integer(5);
Object p=i;
int s=p;//gives error
编译器不知道Object
类型的东西实际上是一个整数。在您的眼睛中,您可以清楚地看到您正在分配一个整数并将其转换为整数对象。但是,一旦您将其分配给Object
,由于源代码的语义目的,该信息就会丢失。
这与此代码错误的原因相同:
Object o = getSomeObject(); // What exactly does it return? We don't know
int i = o; // How do you know this will work?
函数getSomeObject()
可以返回任何内容。我们不知道它会是一个整数,还是一个字符串,或者一个数组列表......因此,我们必须假设这是一种不安全的转换。如果上述内容对您有意义,那么您可以推断出为什么您无法进行转换。
现在,我认为让您感到困惑的部分是"我清楚地在其中放了一个整数,它会自动装箱到Integer
中,并且应该可以通过拆箱来分配!
。但是,语言规则规定,一旦我们完成了该作业,我们必须将其视为可以是该类型的任何对象。由于我们不能盲目地假设对象是一个整数,因此您需要显式强制转换它。
这也在多态性的层次结构链中发挥作用。如果你有一个父 P,以及一个从 P 延伸的子 C,那么我们知道:
Child c = new Child();
Parent p = c; // Valid, because c is definitely a Parent
但
Parent p = new Parent();
Child c = p; // Can't go down the hierarchy, this is also wrong
在您的示例中也可以看到同样的事情。Integer
是Object
的孩子,这就是为什么我们可以这样做
Integer i = 5;
Object o = i;
同样,我们不能反过来做
Object o = new Object();
Integer i = o; // Not allowed
而且因为对于您的示例,我们需要从Object -> Integer -> int
开始(通过拆箱),所以不允许从Object
到Integer
的第二步。
现在,如果您确实编写了这样的代码
Integer i = new Integer(5);
Object p = i;
int s = (Integer) p;
这会起作用。事实上,运行时的JVM(通过HotSpot)可能会准确地注意到你在做什么,并将上面的代码转换为:
int s = 5;
因为JVM可能足够聪明,可以准确地实现你作为人类所意识到的。
因此,虽然你必须编写语义正确的Java源代码(当等边的右侧是Object
时,不做int i = someObj
),编译器可能足够聪明,可以在你运行程序时为你内联所有源代码。
Upcasting
在案例object
中转换为超类型,而downcasting
在案例int
中转换为子类型。始终允许向上转换,但向下转换涉及类型检查。
Object p=i;
在这里,您正在执行始终允许Upcasting
因为int is an Object
是有意义的。
int s = p;
这里p
object
,您正在尝试将其分配给子类型int
,编译器如何知道p-object
是int
而不是字符串或双精度等。因此,要解决此问题,您必须像这样显式地进行向下转换:
int s = (int) p;
注意:错误的向下转换可能会引发ClassCastException
。