2017-05-30 99 views
0

我有三个班。为什么不能在子类中看到父类的方法?

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类?

+2

您的变量'a'可能包含对'A'的另一个子类(如'D')的引用,它没有提供方法'hello()' - 编译器根本不知道。因此,编译器只允许调用为类“A”定义的方法。 –

+0

和'Object o = new String(“123”);'不能使用'o.length();'然而,如果你将o赋给一个String,那么你可以使用String的方法。 –

+1

这听起来像你可能希望你定义'B'通过“扩展”它的功能来改变'A'的定义吗?那是你在想什么?因为,如果是这样,那是不正确的。通过定义'B'和'C',你对'A'什么都不做。相反,“B”和“C”将“A”的定义“复制”或“继承”为起点,然后您在其中定义的任何内容都可以访问“A”的定义。 – dantiston

回答

2

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" 
1

当您将a定义为A类型对象(A a = new C();)时,它只能访问类型为A的成员和方法。要做你想做的事情,可以在A上定义hello(),或者将a定义为BB a = new C();)类型的对象。这是因为编译器正在跟踪它可用的方法。如果由于某种原因,你实际上没有访问实例,但你需要从B访问的东西,但它交给你作为一个A对象,那么你可以将它转换:

if (a instanceof B) (B a).hello(); 
else throw new Exception(); 
1

这是所有关于变量类型。你正在实例化C类,但将结果对象视为A.类的接口不包含'hello'方法,这就是为什么你不能在你的例子中使用它。

为了解决这个问题,就应该把你的方法添加到一个或B.

1

变量的更新类型在声明一个变量为具有超类的类型,你只能访问(公共)方法和通过该变量的超类成员变量。

0

在方法重写,你应该在超级class.In同样的方法这种情况下最超类是A

1

在你的问题中是一个父类B的,B是父类的Ç (即A-> B-> C),并通过A创建C类的对象。所以,首先根据你的程序,它试图在A类中找到hello()方法,因为它是C的超级父类,它没有定义hello()方法,这就是它显示错误的原因。

1

我认为你对多态如何工作有点困惑。你说“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”),因为超类不会从子类继承(这是相反的)。

相关问题