在java中,我们可以将超类Object传递给子类引用吗?
在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行会发生什么? 问题出在哪里?
欢迎任何输入/链接。
如果您的SalesPerson sales = new Employee();
声明被允许编译,这将破坏多态性的原理,这是该语言具有的function之一。
另外,你应该熟悉编译时类型和运行时类型的意思:
变量的编译时类型是它声明的类型,而运行时类型是变量指向的实际对象的类型。 例如:
Employee sales = new SalesPerson();
编译时的sales
类型是Employee
,运行时类型是SalesPerson
。 编译时类型定义了可以调用的方法,而运行时类型定义了实际调用期间发生的情况。
让我们假设这句话有效:
SalesPerson sales = new Employee();
正如我所说,编译时类型定义了可以调用哪些方法,因此met2()
可以进行调用。 同时, Employee
类没有met2()
,因此实际的调用是不可能的。
不,允许这样做是没有道理的。
原因是子类通常定义其他行为。 如果您可以将超类对象分配给子类引用,那么当您尝试访问实际不存在的类成员时,您将在运行时遇到问题。
例如,如果允许这样做:
String s = new Object();
你会遇到一些非常糟糕的问题。 如果尝试调用String
方法会发生什么? 运行时会崩溃吗? 或者也许会进行无操作? 这应该编译吗?
如果运行时崩溃,您可以使用运行时检查来确保您收到的对象实际上包含您想要的方法。 但是,您基本上实现了Java类型系统在编译时已经提供的保证。 所以,真正的“function”只需花费你一大堆类型检查代码,你不应该首先编写它们。
如果执行no-ops而不是不存在的方法,那么当你想要访问的成员不存在时,确保你的程序按照写入运行是极其困难的,因为任何引用在任何时候都可能真的是一个Object
。 当您自己编写并控制所有代码时,这可能很容易处理,但是当您必须处理其他代码时,这些保证基本上就会消失。
如果你想让编译器进行检查,假设编译器编写者没有追捕你并且给你一个严厉的谈话 – 那么,你再次回到“正常”的行为。 再说一遍,这只是零利益的大量工作。
简而言之:不,这是不允许的,因为这样做是没有道理的,如果语言设计师试图允许他们在他们可以做任何更多伤害之前被锁定。
如果从类inheritance,则始终专注于超类的常见行为。
在您的示例中, SalesPerson
是一个特殊的Employee
。 它inheritance了超类的所有行为,并且可以覆盖行为以使其不同或添加新行为。
如果您允许,使用子类型的实例(如Employee e = new SalesPerson()
初始化超类型的变量,则可以使用该变量上的所有常见行为。
相反,如果你可以反过来做,那么在课堂上可能会有几个未初始化的成员。
您在使用Java Collection API时经常会发现这种情况,例如,您可以在迭代它的操作上使用公共List
类,但在初始化时,您可以使用例如子类ArrayList
。