最近我的老师在谈论使用不同的构造函数来实例化对象。但我真的很困惑。为此,我想了解为什么会出现以下编译错误。
class SuperClass {
void superClass(){
System.out.println("superClass");
}
}
class SubClass extends SuperClass {
void subClass(){
System.out.println("subClass");
}
}
class Call {
public static void main(String args[]){
SuperClass s = new SubClass();
s.superClass();
}
}
当我编译并运行下面的代码时,我得到了输出
superClass
但是当我尝试通过 s
对象调用 subClass()
时,出现以下错误。
damn.java:17: cannot find symbol
symbol : method subClass()
location: class SuperClass
s.subClass();
^
1 error
好的,根据这个,我可以假设即使我用不同的构造函数实例化对象,也只有指定的对象类型被加载到 RAM。
但是,当我在这里使用覆盖时,
class SuperClass {
void superClass(){
System.out.println("superClass");
}
}
class SubClass extends SuperClass {
void superClass(){
System.out.println("subClass");
}
}
class Call {
public static void main(String args[]){
SuperClass s = new SubClass();
s.superClass();
}
}
我调用了子类中的方法。这让我对此感到非常困惑。任何人都可以向我解释当我使用不同的构造函数实例化对象时这里发生了什么。
最佳答案
在运行时,JVM 知道您的 s
变量是一个“子类”,因此可以调用正确的(覆盖的)方法。
你遇到的问题是在编译时。编译器会尝试验证您的程序以确保您没有犯任何错误。除了您告诉它的类型外,它不知道变量的类型。
// the Java compiler remembers that there is a variable called 's' and that
// it has the type 'SuperClass'. Note that the compiler does not check the
// actual type of the instance. It just checks to see if the assignment is
// is valid. Since the right side is of type 'SubClass' and the left side
// has the type 'SuperClass' which is a parent of 'SubClass' this assignment
// is valid for the compiler. But it ONLY remembers that 's' is of type
// 'SuperClass' since that is what you told it about 's'.
SuperClass s = new SubClass();
// Here the compiler sees 's' and looks up its type. The type of 's' is
// 'SuperClass' as remembered earlier. javac will no go and look up the
// definition of 'SuperClass' and finds out that 'SuperClass' does not
// have a method with the name 'subClass' so you get a compiler error.
s.subClass();
编译器这样做的原因是,您告诉编译器“s”是父类(super class)类型。因此,对任何扩展 SuperClass 的赋值都是对“s”的有效赋值。从理论上讲,您可以将父类(super class)分配给“s”。如果编译器不执行此检查,您将能够编写代码,在可能没有这些方法的对象上调用方法,这将导致运行时错误。在运行时随机出现这样的错误比编译器只检查所有赋值和调用要糟糕得多,因为您可以立即修复这些错误,而且运行时错误有时很难找到和修复。
正如其他人所指出的,您稍后可以通过强制转换告诉编译器您的“s”实际上是一个“子类”:
((SubClass) s).subClass();
有了这个,您基本上就可以告诉编译器:“我知道 s 实际上是一个‘子类’,所以请在这一部分中将其视为一个子类”。如果你对此有某种错误,并且你的's'在运行时实际上是一个'SuperClass',你将得到一个'ClassCastException',这是一个运行时错误,因为此时JVM不知道该做什么。
关于java - 使用不同构造函数的对象实例化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30320735/