为什么Java编译器决定是否可以基于“引用”类型调用方法而不是实际的“对象”类型?

时间:2014-08-30 09:46:58

标签: java

我只是想知道为什么Java编译器决定是否可以调用基于"引用"的方法。键入而不是实际"对象"类型?为了解释,我想引用一个例子:

class A {
void methA() {
    System.out.println("Method of Class A.");
} 
}

class B extends A {
void methB() {
    System.out.println("Method of Class B.");
}
public static void main(String arg[]) {
    A ob = new B();
    ob.methB();       // Compile Time Error
}
}

这将产生编译时错误,即methB()中找不到方法class A,尽管对象参考" ob"包含class B的对象,该对象由方法methB()组成。原因是Java Compiler检查Class A(引用类型)中不在Class B(实际对象类型)中的方法。所以,我想知道这背后的原因是什么。为什么Java Compiler在A类中查找方法,为什么不在B类(实际的对象类型)中查找?

4 个答案:

答案 0 :(得分:2)

假设您有一个Animal类和一个扩展的Dog Animal。现在,如果Animal定义了一个名为speak()的方法,Dog定义了一个名为bark()的方法。如果您这样做:

Animal a = new Dog();

这意味着你指着一只狗并说它是一只动物。当您将狗视为动物(而不是狗)时,您只能调用为动物定义的方法,而不是狗。

在编译期间,编译器会检查是否在引用类型中定义了被调用的方法。

答案 1 :(得分:1)

通过将变量声明为A类,您基本上隐藏了它实际上是一个子类型的事实。没有看到类型B的方法是标准行为,这在(严格类型化的)面向对象中是必不可少的。

答案 2 :(得分:1)

很简单,编译器不知道变量的类型。与上面描述的场景不同,它实际上并不是那么明显的对象"类型是。这就是"对象" type是运行时类型:它在运行时已知。

想象一下像这样的方法:

public static void process(A ob) {
    ob.methB(); //how do you know if this is valid?
}

public static void main(String[] args) {
    process(new B()); //would make the above call valid
    process(new A()); //would make the above call invalid
}

简单地说,你允许变量具有使你的调用无效的运行时类型。 可能有效,但如果您依赖methB(),则必须将B作为参数。

回到你的代码示例,这个例子没有任何意义:

A ob = new B();
//why would you declare ob as A if you are storing a B inside it
//this is only useful if you want to store different types of objects in it at some point
//however, that's not the case, because in the next line:
ob.methB(); //you're calling methB()

答案 3 :(得分:0)

你的疑问很好,但它是一种哎呀。您正在为超类分配一个子类对象,因此我只向调用者公开超类的方法。

简单地假设A类作为具有2个方法和B的接口是实现类,其中包含10个方法。但是如果你尝试用接口A为该类创建对象,它将只暴露2个方法。在您的情况下应用相同的逻辑。