虽然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
}
}
答案 0 :(得分:5)
你想知道为什么我们使用显式类型转换。 这都是关于继承 -
让我清楚这一点 - 假设我们有两个类 A类和 B类。 B类是 A类的子类。这意味着 B类具有 A类的所有功能,这意味着 B类可以执行 A类所能做的任何事情做。 所以,如果
A a = new B();
非常好,因为 B级可以做 A级所能做的事情。 这里引用变量 a 是类A的类型,来自A类的所有方法都是invokable.Now B 的对象(new B();)具有所有 A类的功能(作为继承),因此 A类的所有方法都可以调用。
如果我们改变这样的条件 - >
B b =new A();
不可能,因为可能 B类实现其自身的功能(方法和变量),这些功能不在 A类中。但是这里引用变量的类型为 B , B类的所有功能都是可调用的,但实际对象的类型为 A ,所以错误会发生。
同样的情况是类对象。所有其他类自动继承对象类。
所以当任何具有Class Object类型的引用变量的对象需要显式Cast时,因为这不确定该对象包含的或多或少的功能。
答案 1 :(得分:2)
一旦您将tiger
分配给Object
引用,编译器就不再知道它实际上是Tiger
。它只知道tiger
对象是Object
- 它可能是String
,Integer
,Fruitcake
或Animal
。
这正是它应该如何运作的。
答案 2 :(得分:2)
由于Scream()
未被声明为Object
的公共方法,因此您无法在Object
类型的变量上调用它。编译器只知道 static 类型的变量(引用),因此它无法告诉或验证此引用是否会在运行时指向类型为Tiger
的对象(这将是是动态类型)。这就是编译错误的原因。
您可能会说编译器在上述情况下验证动态类型是微不足道的,这或多或少是正确的。然而,在现实生活中,它通常不那么简单。考虑
Factory factory = new SomeFactory();
Object obj = factory.getProduct(param);
// What is obj's dynamic type?
编译器理论上可以检测到factory
的动态类型是SomeFactory
。然后它应该做的是静态分析SomeFactory.getProduct()
中的代码以检测返回的产品的类型。当然,getProduct
可能会根据其参数返回不同类型的实际产品。因此编译器需要在调用时检测param
的可能值...这可能来自任何数量的源,例如用户输入,配置文件,DB ......但即使这是可以克服的,具体的产品类也可以在运行时由类加载器动态加载,从jar文件中甚至可能在编译时不可用。所以编译器甚至可能不知道这个特定类的存在,更不用说它的公共接口了。
答案 3 :(得分:2)
鉴于声明:Object o = new Tiger();
变量的类型(Object)控制您可用的交互(方法),而值的类型(Tiger)控制为给定交互执行的行为。
通过在此示例中使用Tiger实例的Object引用,您说要使用Tiger的实例作为Object。好吧,一个对象没有方法Scream()
所以它不会给你那个选项。如果您希望能够Scream()
,请将其用作实际知道如何Scream()
如Animal
或Mammal