繁体   English   中英

Java中构造函数内部的多态性

[英]Polymorphism inside constructors in Java

码:

class A{

    A()  {
        test();
    }
    void test(){
        System.out.println("from A");
    }
}

class B extends A {

    void test() {

        System.out.println("from B");

    }

}

class C {

    public static void main(String args []){

        A a = new B();

        a.test();
    }
}

输出:

from B 
from B

为什么这样打印?

这是非常糟糕的代码。 发生的事情是在子类B重写了void test()

new B(); 创建一个B类实例。 您引用将其强制转换为A的事实与此无关。 但即使尚未构造子类 ,Java运行时也会从父类A的构造函数中调用该子类中的方法。

使用此(反)模式时要格外小心! (请注意,在C ++中,您会得到未定义的行为)。

在运行时期间,从实际实例对象调用该方法。 B

A a = new B();
a.test();

在上面的代码中,您已实例化了对象B ,而不是A 您刚刚分配了A类型的引用变量。 在内部,它仅指B的实例。 在编译期间,它只检查该方法是否实际存在于A引用中并允许它进行编译。 在运行期间,实际上在真实对象上调用该方法,即由引用A引用A B

这是面向对象多态性最重要的概念之一。 通过使用类B扩展A,您将创建一个更具体的实现,使用新方法(例如test()方法)覆盖其某些方法,并可能向其添加内容(成员和方法)。

无论何时覆盖一个类,都将调用子类的方法,而不管它们“正在行动”哪个类。

当你将一个对象转换为另一个类时(比如你的情况B到A),你只是说我想把它看作是A类的引用。这对于接受A类对象作为参数的方法很有用。

考虑这个例子:

具有方法float computeSalary() Employee (超类float computeSalary()

Technician extends Employee ,它覆盖了方法float computeSalary()

Manager extends Employee ,它覆盖方法float computeSalary()

SalaryGenerator类有一个方法generateMonthlyPay(Employee e) ,它调用Employee超类的computeSalary() ,但是将调用特定的子类方法,因为每个方法都有不同的计算月薪的方法。

在运行时调用多态方法时,Java使用特殊的数据结构来决定需要调用哪个类的方法。 在构造对象时, 在任何用户提供的构造函数和初始化程序代码执行之前设置此结构。

当你创建A a = new B()数据结构,上面写着“当test()被调用时,你需要调用A.test()B.test() ”的构造函数之前准备A输入。 由于这个结构是为B类准备的,它指向B.test() ,即使调用代码在A的构造函数中。 这就是为什么你看到"from B"打印两次。

但请注意,虽然从技术上讲,您的代码将按照您的要求执行,但从逻辑上讲,这是一个非常糟糕的决定。 这段代码不好的原因与初始化序列有关:想象一个test()方法依赖于在构造函数中初始化的B私有字段,如下所示:

class B extends A {
    private final String greeting;
    public B() {
        greeting = "Hello";
    }
    void test() {
        System.out.println(greeting + " from B");
    }
}

人们期望看到"Hello from B"正在印刷。 但是,您只能在第二次调用中看到它:在第一次调用时, greeting仍为null

这就是为什么你应该避免从构造函数中调用方法覆盖:它打破了方法的假设,即对象已经完全初始化,有时会产生相当不幸的后果。

虽然引用类型是A,但它的对象类型是B,这意味着它指向B中的实现。因此,从B得到打印。

使用时创建对象a,A a = new B()

构造函数从基类调用到派生类..这里基类构造函数调用test(),但由于过度骑行的概念,它在派生类中调用test()。

所以你最初得到“来自B”。

a.test()再次调用over rided派生类test()。 所以再次从B打印出来

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM