我只是想知道为什么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类(实际的对象类型)中查找?
答案 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个方法。在您的情况下应用相同的逻辑。