【问题标题】:In java , can we pass superclass Object to subclass reference?在 java 中,我们可以将超类 Object 传递给子类引用吗?
【发布时间】:2014-08-14 14:13:18
【问题描述】:

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

我知道这是一个奇怪的问题/实际上不可行, 但我想了解这背后的逻辑 为什么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 行会发生什么? 哪里会出问题?

欢迎任何输入/链接。

【问题讨论】:

  • 这没有意义。如果允许,您可能会拥有您希望存在但实际上并不存在的字段/方法。如果允许的话,我认为语言设计者可能已经被锁在他们无法造成更多伤害的地方。
  • 你预计会发生什么?

标签: java inheritance reference polymorphism


【解决方案1】:

没有。允许这样做是零意义的。

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

例如,如果允许这样做:

String s = new Object();

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

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

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

如果您希望编译器进行检查,假设编译器编写者不会追捕您并给您严厉的谈话——好吧,您又回到了“正常”行为。再说一遍,这只是零收益的大量工作。


长话短说:不,这是不允许的,因为这样做是零意义的,如果语言设计者试图允许他们在造成更多伤害之前被锁定。

【讨论】:

    【解决方案2】:

    如果您的SalesPerson sales = new Employee(); 语句被允许编译,这将违反Polymorphism 的原则,这是该语言的特性之一。

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

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

    Employee sales = new SalesPerson();  
    

    sales 的编译时类型为Employee,运行时类型为SalesPerson。 编译时类型定义了可以调用的方法,而运行时类型定义了实际调用期间发生的情况。

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

    SalesPerson sales = new Employee();
    

    正如我所说,编译时类型定义了可以调用的方法,因此met2() 本来可以调用。同时,Employee 类没有met2(),因此实际调用是不可能的。

    【讨论】:

    • Employee e= new SalesPerson(); 怎么样? e.met2();我认为这是可能的,但如何?编译时没有met2() 方法。它不应该抛出错误吗?
    • @RajSharma 不允许。它会在编译时出错,因为 Employee 中没有 met2() 方法
    【解决方案3】:

    如果你从一个类继承,你总是专门化超类的共同行为。

    在您的示例中,SalesPerson 是一个特殊的Employee。它从超类继承所有行为,并且可以覆盖行为以使其不同或添加新行为。

    如果您在允许的情况下使用子类型的实例(如Employee e = new SalesPerson())初始化超类型变量,那么您可以对该变量使用所有常见行为。

    如果相反,您可以反过来做,那么类中可能有几个未初始化的成员。

    您在使用 Java 集合 API 时经常会发现这种情况,例如,您可以在迭代等操作中使用常见的 List 类,但在初始化它时,您使用例如子类 ArrayList

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-04-27
      • 1970-01-01
      • 2020-10-26
      • 2013-06-11
      • 2013-10-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多