超类引用子类对象表现出与子类引用子类对象相同的行为

9
以下是Java代码,当在Eclipse上运行时,即使我们替换掉其中的内容,也会得到相同的输出结果。
superclass s=new sub();

与之配合,

sub s= new sub();

请注意我们已经覆盖了方法。 输出是:
changed supermethod in sub class
num is sub class 5

代码:

public class superclass {
    int num=2;
    public static void main(String str[]){
        superclass s=new sub();
        //HERE: nothing changes if we write, sub s=new sub();
        s.supermethod();
        s.method();
    }
    void supermethod(){
        System.out.println("supermethod as in superclass");
    }
    void method(){
        System.out.println("num in superclass "+num);
    }
}
class sub extends superclass{
    int num=5;
    void method(){
        System.out.println("num is sub class "+num);
    }
    void supermethod(){
        System.out.println("changed supermethod in sub class");
    }
}

请指出在这两种方式中创建子类对象的区别。在访问方法和变量时是否会有任何差异?(我们的Java老师说,在两种情况下访问方法和变量将不同)
另外,像main这样的静态方法会发生什么。虽然我知道它是可继承的,但有人可以强调一下它在子类中的行为吗?

你将类型声明为 superclass,但在两个实例中,你实际创建的对象是 sub。当你调用方法时,由于 sub 有这些方法,它们被调用而不是超类。在 superclass 中放置一个你没有在 sub 中重写的方法,然后在这两个示例中调用它以查看差异。 - takendarkk
请在类的命名中使用大写字母:Superclass(或SuperClass)和Sub - Fabian
4个回答

23
在Java中,所有非静态方法都是“虚拟的”,这意味着它们基于底层对象的运行时类型,而不是指向该对象的引用的类型。因此,在声明对象时使用哪种类型并不重要,行为将是相同的。
声明所影响的是编译时可见的方法。如果SubClass有一个SuperClass没有的方法(称为subMethod()),并且您构造对象如下:
SuperClass s = new SubClass();

然后你只能调用在SuperClass中可用的方法。也就是说,尝试调用s.subMethod()将导致编译时错误。但是,正如你已经发现的那样,如果这些方法存在于SuperClass中,但被SubClass覆盖,则将执行被覆盖的方法。

另一方面,静态方法不是虚拟的。运行下面的代码:

public class StaticTest {
    public static void main(String[] args) {
        SuperClass s = new SubClass();
        s.method();  // bad idea - calling static method via an object reference
    }

    public static class SuperClass {
        public static void method() {
            System.out.println("SuperMethod");
        }
    }

    public static class SubClass extends SuperClass {
        public static void method() {
            System.out.println("SubMethod");
        }
    }
}

输出“SuperMethod”。然而,你很少需要关心static方法是非虚拟的,因为你永远不应该像我上面那样通过对象引用调用它们。你应该通过类名来调用它们:

SuperClass.method();

1
@Fabian 好的,答案已经编辑过了。 - matt forsythe

3

我在这里对你的代码进行了改写,做了一些修改。请看看这些变化。

public class superclass {
    int num=2;
    public static void main(String str[]){
        superclass s=new sub();
        //HERE: nothing changes if we write, sub s=new sub();
        s.supermethod();
        s.method();
    }
    ...
    ...
    //This method is not overridden.
    void methodInSuper(){
        System.out.prinln("method not overridden.");
    }
}
class sub extends superclass{
    int num=5;
    ...
    ...
    //This is only in subclass.
    void methodInSub(){
        System.out.println("method only in subclass.");
    }
}

现在,当您创建一个像这样的对象时:

现在,当您创建这样的对象时:

superclass s1=new sub();

然后你可以调用所有被覆盖的方法,如下所示:
s1.supermethod();
s1.method();

在这种情况下,子类的方法将被调用。
您还可以调用未被覆盖的超类方法,例如:
s1.methodInsuper();

但是如果您尝试访问仅在子类中定义的方法,例如:
s1.methodInsub();

如果这样做,将会产生编译时错误。


这是因为s1是父类类型。
如果仍然想在子类中调用方法,则需要将s1强制转换为子类,例如:

Sub s = (Sub) s1;

之后您可以调用子类的方法。
如果您创建一个对象,如下:

Sub s2 = new Sub();

那么你就可以访问子类或超类中定义的任何方法。

早期对象的创建基本上是用于实现“运行时多态性”。
希望你得到了答案。


1
你正在创建 sub 的对象,并将其赋值给 super 的引用。如果你不这样做 1)第一种情况:
superclass s=new sub();   
        s.supermethod();
        s.method();

在上述情况下,将调用子类方法,但这两个方法也应该存在于超类中(如果不存在,则会导致编译时错误)。
第2种情况:-
sub s=new sub();   
    s.supermethod();
    s.method();

在这里,sub的方法也将被介绍,这些方法可能存在于super中,也可能不存在。

0
让我们举个例子:sup是类A对象的引用变量,sub是类B对象的引用变量。假设B扩展了A。那么如果我们写"sup = sub;"或"sup = new B();",这条语句使我们能够获取两个类之间共同的属性。即:B继承的属性...我们使用这个技巧来检查B继承的属性是否被修改。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接