在运行时,类型转换是否会更改声明/引用类型?

5

首先,让我明确一下我所说的声明类型是什么意思。 假设SuperBoss是Boss类的超类。

SuperBoss mrBond = new Boss();

SuperBoss是声明类型,而Boss是实际类型。

个人认为由于以下运行时异常,声明类型在运行时被更改:

SuperBoss mrWayne = new SuperBoss();
((Boss)mrWayne).randomMethod(); 

//Exception: java.lang.ClassCastException: SuperBoss cannot be cast to Boss

我知道这似乎微不足道,但我将在下个季度担任辅导员,我不想教给学生们错误的东西。而且这个季度我的教授和她的助手在这个问题上意见不一。我的教授认为,在运行时,强制类型转换确实会完全改变单个语句的声明类型。而助教强烈认为,在运行时,强制类型转换仅被检查,但实际上并没有改变声明类型。

2个回答

3
我的教授认为,在运行时,强制类型转换确实会完全改变单个语句的声明类型。而助教则坚信在运行时,类型转换只是被检查了一下,但实际上并没有真正改变声明类型。
事实上,我认为从某种意义上来说,他们都是对的。没有矛盾之处……只要你能理解他们实际在说什么。
mrWayne的声明类型并没有改变。((Boss)mrWayne) 的声明类型确实“改变”了。或者至少,它与 mrWayne 的声明类型不同。
这里的真正问题是,某人正在使用不精确的术语……而且人们之间没有交流好。
好的,看看这个例子:
public class Test {
   public static void method(Object t) {
       system.out.println("Its an object");
   }
   public static void method(Test t) {
       system.out.println("Its a test");
   }
   public static void main(String[] args) {
       Test t = new Test();
       method(t);
       method((Object) t);
   }
}

这应该输出:
Its a test
Its an object

因为 (Object) t声明 类型是 Object,而不是 Test。而且是 声明 类型(而不是运行时类型)决定了在特定调用中使用哪个 method 的两个重载版本。

明白了吗?

这完全取决于你所说的是什么,变量的声明类型还是表达式的声明类型。


请解释一下,因为我不明白“强制类型转换确实完全改变了声明的类型”和“实际上并没有改变声明的类型”这两句话是如何不相矛盾的。 - Kacy Raye
请再次阅读我写的内容。特别是第二段。你理解那个吗? - Stephen C
那么你的意思是变量的声明类型不会因为强制转换而改变? - Kacy Raye
是的... 表达式的声明类型确实会改变。教授和助教在谈论不同的事情!(或者至少,我认为是这样。只有当我直接与他们交谈时,我才能确定... 而不是你加上你的总结/解释他们所说的话... 这可能会歪曲他们各自的陈述。) - Stephen C
太棒了,感谢你提供的有力论据。这一切都很合理。 - Kacy Raye

2
“声明类型”是您向编译器声明的类型。它在程序编译后不会改变。
“运行时类型”是分配给变量的实际对象的类型。只有在分配新对象时才会更改。(对于给定对象,它永远不会改变,没有任何对象实例可以更改其类)。
强制转换将两者连接起来:它检查运行时类型,然后允许您声明该类型。如果检查失败,程序将中止(带有RuntimeException)。当您具有比编译器更多的类型信息时,您需要这样做。然后,您可以向编译器“声明”所讨论的对象确实是一个“Boss”,而不仅仅是“SuperBoss”(否则编译器最好能保证的)。

我的教授认为强制转换确实会在运行时完全更改单个语句的声明类型。

强制转换在编译时“声明”了更具体的类型。但它还包括运行时检查以使其安全。

助教强烈认为,在运行时,强制转换只是被检查了一下,实际上并没有更改声明类型。

检查发生在运行时,但在代码中使用强制转换允许您在编译时进行更具体的类型声明。
((Boss)mrWayne).randomMethod(); 

发生了两件事情:

  • 编译时:您声明这是一个Boss。否则,您无法调用该方法。

  • 运行时:JVM检查该对象是否真的是一个Boss。


好的,我已经读了大约三遍了。 你能检查一下我的理解是否正确吗? 由于强制转换,声明类型现在是Boss。 因此,在运行时,声明类型也是Boss,这使得JVM抛出异常。 - Kacy Raye
如果强制类型转换失败,即实际类型与声明类型不匹配,JVM会抛出异常。 - Thilo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接