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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24384547/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 11:53:13  来源:igfitidea点击:

In java , can we pass superclass Object to subclass reference?

javainheritancereferencepolymorphism

提问by Rajul Konkar

In java, can we pass superclass Object to subclass reference ?

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

I know that it is a weird question/practically not viable, but I want to understand the logic behind this Why is it not allowed in 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
    }
}

What would have happened if Java allowed compilation of line 1? Where would the problem arise?

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

Any inputs/link are welcomes.

欢迎任何输入/链接。

采纳答案by Konstantin Yovkov

If your SalesPerson sales = new Employee();statement was allowed to compile, this would have broken the principles of Polymorphism, which is one of the features that the language has.

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

Also, you should get familiar with that does compile time typeand runtime typemean:

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

The compile-time typeof a variable is the type it is declared as, while the runtime typeis the type of the actual object the variable points to. For example:

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

Employee sales = new SalesPerson();  

The compile-time type of salesis Employee, and the runtime type will be SalesPerson. The compile-time type defines which methods can be called, while the runtime type defines what happens during the actual call.

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

Let's suppose for a moment that this statement was valid:

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

SalesPerson sales = new Employee();

As I said, the compile-time type defines which methods can be called, so met2()would have been eligible for calling. Meanwhile, the Employeeclass doesn't have a met2()and so the actual call would have been impossible.

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

回答by Alexander Rühl

If you inherit from a class, you always specialize the common behavior of the super class.

如果你从一个类继承,你总是特化超类的常见行为。

In your example, the SalesPersonis a special Employee. It inherits all behavior from the super class and can override behavior to make it different or add new behavior.

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

If you, as it is allowed, initialize a variable of the super type with an instance of the sub type like Employee e = new SalesPerson(), then you can use all common behavior on that variable.

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

If instead, you were possible to do the other way round, there might be several uninitialized members in the class.

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

You find this very often when using the Java Collection API, where for example you can use the common Listclass on operations like iterating through it, but when initializing it, you use for example the sub class ArrayList.

在使用 Java Collection API 时,您经常会发现这一点,例如,您可以List在诸如迭代之类的操作上使用公共类,但是在初始化它时,您会使用例如子类ArrayList

回答by awksp

No. It makes zero sense to allow that.

不。允许这样做是零意义的。

The reason is because subclasses generally define additionalbehavior. If you could assign a superclass object to a subclass reference, you would run into problems at runtime when you try to access class members that don't actually exist.

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

For example, if this were allowed:

例如,如果允许这样做:

String s = new Object();

You would run into some pretty bad problems. What happens if you try to call a Stringmethod? Would the runtime crash? Or perhaps a no-op would be performed? Should this even compile?

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

If the runtime were to crash, you could use runtime checks to make sure the objects you receive will actually contain the methods you want. But then you're basically implementing guarantees that the Java type system already provides at compile-time. So really that "feature" cost you nothing but a bunch of type-checking code that you shouldn't have had to write in the first place.

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

If no-ops were executed instead of nonexistent methods, it would be extremely difficult to ensure that your programs would run as written when the members you want to access don't exist, as any reference could really be an Objectat any point. This might be easy to handle when you are working on your own and control all your code, but when you have to deal with other code those guarantees essentially vanish.

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

If you want the compiler to do the checking, assuming compiler writers don't hunt you down and give you a stern talking-to -- well, you're back to "normal" behavior once more. So again, it's just a lot of work for zero benefit.

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



Long story short: No, it's not allowed, because it makes zero sense to do so, and if a language designer tried to allow that they would be locked up before they could do any more harm.

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