为什么在用作其他对象类型时必须转换对象类型的引用变量

虽然Java中的所有类都是Object类的子类,但与其他对象类型不同,但是如果没有强制转换,则不能将Object类型的引用变量赋值给任何其他引用类型。

例如:

public class Inheritance { public static class Animal { public void Scream() { System.out.println("I'm an animal"); } } public static class Mammal extends Animal{ public void Scream(){ System.out.println("I'm a mammal"); } } public static class Tiger extends Mammal{ public void Scream(){ System.out.println("I'm a tiger"); } } public static void main (String[] args){ Animal tiger = new Tiger(); tiger.Scream(); //true Object tiger = new Tiger(); tiger.Scream(); //false Object tiger = new Tiger(); ((Animal) tiger).Scream(); //true } } 

你想知道为什么我们使用显式类型转换。 这都是关于inheritance –

让我明白这一点 – 假设我们有两个A B类B类是A类的子类。 这意味着B类具有A 类的所有function,这意味着B 可以执行A 可以执行的任何操作。 因此,如果

  A a = new B(); 

完全没问题,因为B 可以做A级可以做的事情。 这里引用变量a类型为A类,来自A类的所有方法都是invokable.Now B的对象(new B();)具有A类的所有function(作为inheritance)所以A类的所有方法都是将是可以调用的。

如果我们改变这样的条件 – >

  B b =new A(); 

不可能,因为可能是B类实现其自身的function(方法和变量),这些function不属于A类 。 但是这里引用变量是B 类,B类的所有function都是可调用的,但实际的对象是A类,所以会出现Error。

同样的情况是类对象 。所有其他类自动inheritance对象类。

所以当任何具有Class Object类型的引用变量的对象需要显式Cast时,因为这不确定该对象包含的或多或少的function。

一旦你将tiger分配给Object引用,编译器就不再知道它实际上是Tiger 。 它只知道tiger对象是一个Object – 它可能是一个StringIntegerFruitcakeAnimal

这正是它应该如何工作的。

鉴于声明: Object o = new Tiger();

变量(Object)的类型控制可用的交互(方法),而值的类型(Tiger)控制为给定交互执行的行为。

通过在此示例中使用Tiger实例的Object引用,您说您要使用Tiger的实例作为Object。 好吧,一个对象没有方法Scream()所以它不会给你那个选项。 如果你想能够使用Scream() ,请将它用作实际知道如何像AnimalMammal一样的Scream()的类型

顺便说一下,方法应该以小写字母开头

由于Scream()未声明为Object的公共方法,因此无法在Object类型的变量上调用它。 编译器只知道变量的静态类型(引用),因此它无法告诉或validation此引用将在运行时指向Tiger类型的对象(这将是其动态类型)。 这就是您收到编译错误的原因。

您可能会说编译器在上面的情况下validation动态类型是微不足道的,这或多或少是正确的。 然而,在现实生活中,它通常不那么简单。 考虑

 Factory factory = new SomeFactory(); Object obj = factory.getProduct(param); // What is obj's dynamic type? 

理论上编译器可以检测出factory的动态类型是SomeFactory 。 然后,它应该做的是静态分析SomeFactory.getProduct()的代码,以检测返回的产品的类型。 当然, getProduct可能会根据其参数返回不同类型的实际产品。 所以编译器需要在调用时检测param的可能值…这可能来自任意数量的源,例如用户输入,配置文件,DB ……但即使这是可以克服的,具体的产品类可以由类加载器在运行时由jar文件动态加载,该文件在编译时甚至可能不可用。 因此编译器甚至可能不知道这个特定类的存在 ,更不用说它的公共接口了。