由于此对象(标题中所述)可以调用子类中的重写方法,为什么它不能调用子类的其他方法? 我需要尽可能详细的回答,如内存组织,JVM中的内部逻辑等。
下面的代码将让您清楚地了解我的问题。
class A
{
int x=10;
public A()
{
System.out.println("Constructor of class A called!!!");
}
public void sayGreetings()
{
System.out.println("accept hye from class A");
}
}
class C extends A
{
int x=30;//why this is not accessed by stated object.
public C()
{
System.out.println("Constructor of Class C caled!!!");
}
public void sayGreetings()
{
System.out.println("accept hye from class C");
}
public void ssa()
{
System.out.println("Sat Sri Akal ji from class C");
}
}
public class ParentClassTypeObject
{
public static void main(String[] args)
{
C cObj=new C();
cObj.sayGreetings();
cObj.ssa();
A aCObj=new C();//this is let say stated object,main object
aCObj.sayGreetings();/*here we invoked method will be child class's
overriden method.*/
//aCObj.ssa(); //why this line gives error
System.out.println("x="+aCObj.x);
}
}
答案 0 :(得分:4)
因为对象的接口是你写的时选择的那个:
A aCObj = new C();
如果您想通过C
变量访问aCObj
属性,请将其声明为C
。
通过将其设为A
,您可以稍后再写这个:
aCObj = new A();
因此,由于变量可以指向A
或C
,因此编译器会限制您访问由A
类型公开的接口定义的方法。
您仍然可以访问这些方法的C
定义,因为这是OOP(多态)的要点之一。
答案 1 :(得分:3)
引用变量指向相同类型的对象或相同类型的子集。
请考虑父母和子女是两个班级,其中父母是超级班级,儿童继承父母班级。下图将为您提供详细说明。
在上面的图片中,Parent类的Reference变量将在Child Object中搜索Parent Class Object。它会找到它,因为它在那里。它将给出输出。如果你在Child Class中有相同的方法(Method Overriding)它将执行子类重写方法。
但是对于Child Class引用变量,它无法找到Parent Class Object中的子类对象。所以这里不可能。
希望这清楚你的困惑。
答案 2 :(得分:3)
如果编译代码,则会出现编译时错误(不是运行时错误)。这背后的原因是
A aCObj=new C();
aCObj.sayGreetings(); / *编译器知道aCobj是编译时类型A的引用。由于编译器认为aCobj是A类型而且在类A中存在sayGreetings()方法所以在调用此方法时没有错误* /
aCObj.ssa();
/ *正如我上面提到的,编译器不了解运行时。在运行时aCobj将指向类C类型的对象,但是编译编译器时只知道aCobj属于A类,并且由于类A没有这样的方法,称为ssa(),因此会出现编译时错误。 * /
对象的一个简单规则:在编译时检查赋值运算符的左侧。运行时赋值运算符的右侧。 请考虑以下声明:
Parent obj =new Child();
obj.method1();
obj.method2();
无论您想使用父类型的obj引用调用哪种方法,这些方法都应该出现在Parent类中,因为在编译期间,编译器将严格检查父类中存在的那些方法,即使它可能存在于Child类中。
答案 3 :(得分:1)
编译器决定 IF 你可以根据引用变量的类型调用方法。如果引用变量是A类,你只能调用类A的方法。
但也 编译器根据对象的实际类型决定调用 WHICH 方法,而不是从继承树开始自下而上检查的引用变量的类型。(它从子类开始一直向上) )
所以在这种情况下,当你说aCObj.sayGreetings();
时,编译器首先检查aCObj的引用类型是A
。类A有sayGreetings()
方法所以它的确定。但实际的对象是C
。因此编译器从子类(C)开始,以查找此方法是否一直实现到超类(A)。方法`sayGreetings()
在C类中被覆盖。所以它调用C class sayGreetings() method
(子类)。
另一方面,ssa()
方法属于C类,并且由于引用变量属于A类,因此编译器在您尝试aCObj.ssa();
时会出错
它只是多态性。由于A类引用变量可以是A或C对象,因此编译器仅限制对超类A的方法常用的方法的访问。接下来它检查此方法是否在实际对象的类(C)。如果它不是向上移动到超类(A)并调用超类的方法。但是如果它被实现则调用子类的方法(C)
答案 4 :(得分:0)
因为aCObj
被声明为类型A
所以只能访问类型A中声明的方法。编译器不能保证它也是C类型。
E.g。
您可能还有
public class B extends A {
public void sayGreetings() {
...
}
}
这没有ssa方法,但仍可以分配给声明为类型A
的对象答案 5 :(得分:0)
对象属于A类而非C类,因此您无法访问实例变量,我认为如果您将其公开,那么就可以。
答案 6 :(得分:0)
案例1.父类的引用变量可以指向其子类的对象。 情况2.指向其子类的对象的父类的引用变量可以被类型转换为其子类的对象。
在案例1中:父类的引用变量只能调用父类中定义的方法,并且它也可以调用覆盖父类方法的子类的方法。但是不能调用那些方法仅限于儿童班。
在案例2中:父类的引用变量也可以调用其子类的方法。
这是由于多态性的原理。
答案 7 :(得分:0)
这是您陈述的查询的详细说明:
答案是“多态性”与“静态类型”的交集。因为Java在编译时是静态类型的,所以您可以从编译器获得某些保证,但是您必须遵循规则进行交换,否则代码将无法编译。在此,相关的保证是子类型(例如,子)的每个实例都可以用作其父类型(例如,父)的实例。例如,可以保证在访问employee.getEmployeeDetails或employee.name时,该方法或字段是在可以分配给类型为Parent的可变雇员的任何非空对象上定义的。为了保证这一点,编译器在决定可以访问的内容时仅考虑该静态类型(基本上是变量引用的类型Parent)。因此,您无法访问在对象的运行时类型Child上定义的任何成员。
答案已从以下链接获得: Why do we assign a parent reference to the child object in Java?