在java中,我们可以将超类对象传递给子类引用吗?

2022-09-04 06:06:51

在java中,我们可以将超类对象传递给子类引用吗?

我知道这是一个奇怪的问题/实际上不可行,但我想了解为什么Java中不允许这样做背后的逻辑。

class Employee {
    public void met1(){
        System.out.println("met1");
    }
}


class SalesPerson extends Employee 
{
    @Override
    public void met1(){
    System.out.println("new met1");
    }


    public void met2(){
        System.out.println("met2");
    }

}

public class ReferenceTest {
    public static void main(String[] args) {

        SalesPerson sales = new Employee(); // line 1

        sales.met1();  // line 2

        sales.met2();  // line 3
    }
}

如果 Java 允许编译第 1 行,会发生什么情况?问题出在哪里?

欢迎任何输入/链接。


答案 1

如果你的语句被允许编译,这将破坏多态性的原则,这是该语言具有的特征之一。SalesPerson sales = new Employee();

另外,您应该熟悉编译时类型运行时类型的含义:

变量的编译时类型是它被声明为的类型,而运行时类型是变量指向的实际对象的类型。例如:

Employee sales = new SalesPerson();  

的编译时类型为 ,运行时类型将为 。编译时类型定义可以调用哪些方法,而运行时类型定义在实际调用期间发生的情况。salesEmployeeSalesPerson

让我们假设这个陈述是有效的:

SalesPerson sales = new Employee();

正如我所说,编译时类型定义了可以调用哪些方法,因此有资格调用。同时,该类没有 a,因此实际的调用是不可能的。met2()Employeemet2()


答案 2

哈哈允许这样做毫无意义。

原因是因为子类通常定义其他行为。如果可以将超类对象分配给子类引用,则在运行时尝试访问实际上不存在的类成员时会遇到问题。

例如,如果允许这样做:

String s = new Object();

你会遇到一些非常糟糕的问题。如果尝试调用方法,会发生什么情况?运行时会崩溃吗?或者也许会执行无操作?这甚至应该编译吗?String

如果运行时崩溃,可以使用运行时检查来确保接收的对象实际上包含所需的方法。但是,您基本上实现了Java类型系统在编译时已经提供的保证。所以实际上,这个“功能”只花费你一堆类型检查代码,你本来就不应该写这些代码。

如果执行了 no-ops 而不是不存在的方法,那么当要访问的成员不存在时,很难确保程序按所写的方式运行,因为任何引用在任何时候都可能是 。当您自己工作并控制所有代码时,这可能很容易处理,但是当您必须处理其他代码时,这些保证基本上消失了。Object

如果你想让编译器进行检查,假设编译器编写者不会追捕你并给你一个严厉的谈话 - 好吧,你再次回到了“正常”行为。所以再一次,这只是大量的工作,零收益。


长话短说:不,这是不允许的,因为这样做毫无意义,如果语言设计师试图允许他们在造成更多伤害之前被关起来。


推荐