为什么声明类型为Subclass的引用不能引用超类的Object?

时间:2017-06-11 08:01:57

标签: java

Hello无法理解为什么子类变量不能像下面的代码那样引用超类对象。

class Superclass{
}

class Subclass extends Superclass{  
}

public class DemoClass {

    public static void main(String[] args) {

        Superclass obj = new Subclass();   //Valid
        Subclass obj2 = new Superclass();  //Invalid

    }

}

6 个答案:

答案 0 :(得分:2)

Subclass的实例始终也是Superclass的实例,因此您可以指定

Superclass obj = new Subclass();

另一方面,并​​非Superclass的所有实例都是Subclass的实例,因此您无法将Superclass实例分配给Subclass变量。

Superclass的某些实例也是Subclass的实例,因此您可以将Superclass实例投射到Subclass以进行分配:

    Superclass obj = new Subclass();
    Subclass obj2 = (Subclass) obj;

但是,在您的示例(Subclass obj2 = new Superclass();)中,您尝试将 Subclass的实例分配给Subclass变量,因此即使用铸造不起作用。

答案 1 :(得分:2)

您可以拥有一个子类对象并将其“一般”视为超类对象,但您不能拥有通用超类对象并将其视为更具体的子类对象,因为它不是子类对象。 假设在你的子类中有一个方法,让我们称之为foo(),这在你的超类中是不存在的:如果你被允许在子类类型中存储超类对象,编译器将如何理解你不能在该对象上使用方法foo()?

public class Superclass {

}

public class Subclass extends Superclass {
    void foo() {
        //...
    }
}

public class MainClass {
    public static void main(String...s) {
        Subclass obj = new SuperClass();
        obj.foo(); //THIS
    }
}

答案 2 :(得分:2)

因为OOP不能以这种方式工作。
具有子类类型的变量不能引用其超类的对象:

Subclass obj2 = new Superclass();

因为超类的任何实例都不是特定子类的实例。

但反过来是可能的:

Superclass obj = new Subclass();

因为任何子类实例最终都是超类的实例。

要理解为什么你不能做第一个赋值(将父实例赋值给用子类类型声明的变量),假设这个代码有效:

Animal animal = new Dog(); 
Cat cat = animal; // should not be legal

您为Dog变量分配了Cat,因为animal变量引用了Dog个实例。这毫无意义。

答案 3 :(得分:0)

子类是基类的扩展基类不知道,也不能表现得像Sub class

Parent p = new Child() // Child knows and behaves like parent and can override some behavior too

Child c = new Parent() // author of Parent class has no idea as how Child will be implemented 
  // and what extra behaviors will be added in child. 
 // If any behavior of parent is invoked on c, the object of Parent class will not know how to perform it.

简单易懂,让我们举一个更贴近现实世界的例子。

  1. Apple,Mango和Kiwi是水果。如果我们将它们表示为java类,我们可以说Apple,Mango和Kiwi类,都来自Fruit类。

  2. 对于声明类似ClassA obj = new ....之类的代码,我们暂时忽略...并查看ClassA,其参数obj的声明类型。现在可以在ClassA上调用obj中的所有公共方法。

  3. 假设Fruit.java有一个返回public String getTaste()的方法sweet。所有子类都从其超类继承getTaste方法。可以调用getTaste:Mango,Kiwo,Apple。

  4. 假设Mango.java开发人员决定在其中添加名为convertToMangoShake()的其他方法。

  5. 请注意,它只是芒果,可以准备转换为芒果奶昔。

    芒果以外的任何水果都无法准备好转换成芒果奶昔。 Apple和Kiwi无法为转变为芒果奶昔做好准备。要求kiwo准备好转换为芒果奶昔的任何此类行动将是错误

  6. 现在,如果您说Mango mango = new Fruit(),现在调用方法convertToMangoShake()就像mango.convertToMangoShake()一样,则会因为不知道此方法而引发错误。

答案 4 :(得分:0)

我相信这可能有助于您理解。我将尝试用简单的英语而不是代码来回答这个问题。

这里的实际差异在于 SubClass,是SuperClass 的更专业版本。从技术上讲,它应该能够做更多的事情,或存储一些额外的属性

在这方面,如果你试图将SubClass描述为SuperClass,那么这不再适用,因为SuperClass将不能用于相同的目的。 SuperClass以及属性中都缺少函数。

因此,如果可以将SubClass描述为SuperClass,实际上它不再是SubClass。这就像是在动态覆盖对象类型的契约,这违反了语言的限制。

相反,SubClass拥有SuperClass的所有功能和属性,因此它可以充当SubClass和SuperClass(除非您明确覆盖功能)。这是一个源自继承的财产。

在你的例子中,SubClass和SuperClass没有真正的区别。在这种情况下,没有实际的方法来拥有SubClass。如果您计划在未来扩展功能并且希望区分这两者,则可能与设计决策有关。但即使它们是相同的,你也需要通过使用extend关键字来理解它,就像说“嘿,这个类中还有更多东西”,这就是前面讨论过的约束。

答案 5 :(得分:0)

当你从一个类继承时,你总是专注于超类的常见行为。

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

不允许这样做,因为子类通常会定义其他行为。如果您可以将超类对象分配给子类引用,那么当您尝试访问实际不存在的类成员时,您将在运行时遇到问题。

有两种方法可以引用子类对象。两者都有一些优点/缺点:

  1. 第一种方法(使用超类引用引用):超类的引用变量可用于引用从该超类派生的任何子类对象。如果这些方法存在于SuperClass中,但被SubClass覆盖,则它将是将被执行的重写方法。
  2. 第二种方法(使用子类引用引用):子类引用可用于引用其对象。
  3. 示例:

    public static void main(String[] args) {
               // using superclass reference
               // first approach
                Superclass sub1 = new Subclass();
    
               // using subclass reference( )
               // second approach
               Subclass sub2 = new Subclass();
    }