为什么不能在子类中看到父类的方法?
我有三个班。为什么不能在子类中看到父类的方法?
A类
public class A {
}
B类
public class B extends A {
public void hello(){
System.out.println("hello");
}
}
C类
public class C extends B {
}
类检验
public class Test {
public static void main(String[] args) {
A a = new C();
a.hello(); // The method hello() is undefined for type A
}
}
上面的代码将无法编译,因为它报告读取错误“的方法你好()是不确定的A型”
我的问题是,因为“A”是一个C
对象,为什么不a.hello()
使用在B
的父类中的hello()
方法?
如果我添加一个hello方法A
类,最后才上面的代码使用hello()
从B级,可是为什么我要加hello()
到A
级才能使用的方法,从B
类?
A
是您的层次结构中的顶级课程。它只能看到在其中定义的那些方法。 A
无法访问由其子类定义的方法。当然,您可以将C
分配给变量A
,然后您可以在任何可以使用A
的地方使用它,但现在C
将仅限于A
具有的方法。
当你考虑它时它是有道理的。当你定义一个类型(A
)时,你期望它的行为符合你的定义(不包括任何关于C
字段和方法的内容)。你不希望它突然拥有所有可能定义的子类(例如,想象一下,有一百人以各种方式扩展你的班级 - 高级班将变得非常臃肿和广泛)。
这就是为什么子类扩展父类的原因 - 它们添加了不在父类中定义的附加功能(也可能不应该)。但是,父母本身并没有意识到附加功能,也无法使用它。每个类只能使用它定义的或其父代定义的内容。因此,当您将C
分配给父类型时,您只会获得A
知道的那些方法(但使用C
的实现方式)。
考虑:
public class Animal {
public void walk() {
System.out.println("Walking");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("Woof");
}
@Override
public void walk() {
System.out.println("Doggy walk");
}
public static void main(String[] args) {
Dog dog = new Dog();
Animal animal = new Animal();
Animal animalDog = new Dog();
dog.walk(); // "Doggy walk"
dog.bark(); // "Woof"
animal.walk(); // "Walking"
animal.bark(); // Error: bark() is not defined in the Animal class
animalDog.walk(); // "Doggy walk"
animalDog.bark(); // Error - Animal class has no bark()
}
}
因为我们分配给Dog
类型Animal
,它只能使用在Animal
类中定义的方法。但请注意,该行为将是您在Dog
类中为同一方法定义的行为。
如果必须使用的方法和你没有它分配给了该方法的类型某种原因,你应该相应方法进行投放,例如:
((Dog) animalDog).bark(); // "Woof"
当您将a
定义为A
类型对象(A a = new C();
)时,它只能访问类型为A
的成员和方法。要做你想做的事情,可以在A
上定义hello()
,或者将a
定义为B
(B a = new C();
)类型的对象。这是因为编译器正在跟踪它可用的方法。如果由于某种原因,你实际上没有访问实例,但你需要从B
访问的东西,但它交给你作为一个A
对象,那么你可以将它转换:
if (a instanceof B) (B a).hello();
else throw new Exception();
这是所有关于变量类型。你正在实例化C类,但将结果对象视为A.类的接口不包含'hello'方法,这就是为什么你不能在你的例子中使用它。
为了解决这个问题,就应该把你的方法添加到一个或B.
变量的更新类型在声明一个变量为具有超类的类型,你只能访问(公共)方法和通过该变量的超类成员变量。
在方法重写,你应该在超级class.In同样的方法这种情况下最超类是A
在你的问题中是一个父类B的,B是父类的Ç (即A-> B-> C),并通过A创建C类的对象。所以,首先根据你的程序,它试图在A类中找到hello()方法,因为它是C的超级父类,它没有定义hello()方法,这就是它显示错误的原因。
我认为你对多态如何工作有点困惑。你说“a”是一个“c”对象,这是许多初学者误导的假设。所以这里有一个例子来说明发生了什么:
假设你有一个“动物”类,它由一个单独的“狗”类扩展,因为狗是一种动物。因此,我们可以这样写:
Animal someAnimal = new Dog();
上面的语句可以改写为:
Dog someDog = new Dog();
Animal someAnimal = someDog;
这表明一个Dog对象可以存储为一个Animal对象。为什么?因为狗是一种动物。你不能这样做
Dog someDog = new Animal();
因为动物并不一定是狗。
这点回到你原来的断言。您的“一”是不是“C”的对象,因为你从来没有写过这样的:
C a = new A(); // sidenote : this will give you error, as you are saying the analogous Animal is a Dog
其结果是,超类(即“A”)不能访问从子类的方法(在这种情况下,是“B”),因为超类不会从子类继承(这是相反的)。
您的变量'a'可能包含对'A'的另一个子类(如'D')的引用,它没有提供方法'hello()' - 编译器根本不知道。因此,编译器只允许调用为类“A”定义的方法。 –
和'Object o = new String(“123”);'不能使用'o.length();'然而,如果你将o赋给一个String,那么你可以使用String的方法。 –
这听起来像你可能希望你定义'B'通过“扩展”它的功能来改变'A'的定义吗?那是你在想什么?因为,如果是这样,那是不正确的。通过定义'B'和'C',你对'A'什么都不做。相反,“B”和“C”将“A”的定义“复制”或“继承”为起点,然后您在其中定义的任何内容都可以访问“A”的定义。 – dantiston