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
}
}
答案 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.
简单易懂,让我们举一个更贴近现实世界的例子。
Apple,Mango和Kiwi是水果。如果我们将它们表示为java类,我们可以说Apple,Mango和Kiwi类,都来自Fruit类。
对于声明类似ClassA obj = new ....
之类的代码,我们暂时忽略...
并查看ClassA
,其参数obj
的声明类型。现在可以在ClassA
上调用obj
中的所有公共方法。
假设Fruit.java
有一个返回public String getTaste()
的方法sweet
。所有子类都从其超类继承getTaste
方法。可以调用getTaste
:Mango,Kiwo,Apple。
假设Mango.java
开发人员决定在其中添加名为convertToMangoShake()
的其他方法。
请注意,它只是芒果,可以准备转换为芒果奶昔。
芒果以外的任何水果都无法准备好转换成芒果奶昔。 Apple和Kiwi无法为转变为芒果奶昔做好准备。要求kiwo准备好转换为芒果奶昔的任何此类行动将是错误
现在,如果您说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
。它继承了超类中的所有行为,并且可以覆盖行为以使其不同或添加新行为。
不允许这样做,因为子类通常会定义其他行为。如果您可以将超类对象分配给子类引用,那么当您尝试访问实际不存在的类成员时,您将在运行时遇到问题。
有两种方法可以引用子类对象。两者都有一些优点/缺点:
示例:
public static void main(String[] args) {
// using superclass reference
// first approach
Superclass sub1 = new Subclass();
// using subclass reference( )
// second approach
Subclass sub2 = new Subclass();
}