1

既然这个对象(在标题中说明)可以调用子类中的重写方法,为什么它不能调用子类的其他方法?我需要尽可能详细的答案,例如内存组织、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);
  }
}
4

8 回答 8

4

因为您对对象的接口是您在编写时选择的接口:

A aCObj = new C();

如果您想通过变量访问C属性,请将aCObj其声明为C.

通过将其设置为A,您可以稍后编写:

aCObj = new A();

因此,由于变量可以指向Aa 或 a C,编译器会限制您访问由该A类型公开的接口定义的方法。

您仍然可以访问这些方法C定义,因为这是 OOP(多态性)的要点之一。

于 2013-03-13T17:54:39.500 回答
4

引用变量指向同类型的对象或同类型的子集。

请考虑 Parent 和 Child 是两个类,其中 Parent 是超类,而 Child 继承父类。下图会给你一个详细的解释。 在此处输入图像描述

在上图中,父类引用变量将在子对象中搜索父类对象。它会找到它,因为它在那里。所以会给出输出。如果你在子类中有相同的方法(方法覆盖) 它将执行子类覆盖的方法。

但是对于子类引用变量,在父类对象中是找不到子类对象的。所以在这里,是不可能的。

在此处输入图像描述

希望这可以消除您的困惑。

于 2016-05-28T22:20:10.383 回答
3

如果你编译代码,你会得到编译时错误(不是运行时错误)。这背后的原因是

A aCObj=new C();

aCObj.sayGreetings();/* 编译器在编译时知道 aCobj 是 A 类型的引用。由于编译器认为 aCobj 属于 A 类型,并且 sayGreetings() 方法存在于 A 类中,因此调用此方法时不会出错 */

aCObj.ssa();/* 正如我上面提到的,编译器对运行时一无所知。在运行时 aCobj 将指向 C 类类型的对象,但在编译时编译器只知道 aCobj 是 A 类类型,并且由于 A 类没有名为 ssa() 的方法,因此会出现编译时错误。*/

object 的一个简单规则:在编译时检查赋值运算符的左侧。运行时赋值运算符的右侧。考虑这个陈述:

Parent obj =new Child(); obj.method1(); obj.method2();

无论您想使用 Parent 类型的 obj 引用调用什么方法,这些方法都应该存在于 Parent 类中,因为在编译期间编译器将严格检查 Parent 类中是否存在这些方法,即使它可能存在于 Child 类中。

于 2016-11-08T18:29:33.913 回答
2

编译器根据引用变量的类型决定是否可以调用方法。因此,如果引用变量属于A类,则只能调用A类的方法。

但是编译器也会根据对象的实际类型而不是引用变量的类型来决定调用哪个方法,从而开始对继承树进行自下而上的检查。(它从子类一直向上开始)

所以在这种情况下,当你说aCObj.sayGreetings();编译器首先检查aCObj的引用类型时。AA类有sayGreetings()方法所以没问题。但是实际的对象是a C。所以编译器从子类(C)开始寻找这个方法是否是一直实现到超类 (A)。该方法`sayGreetings()在 C 类中被覆盖。所以它调用C class sayGreetings() method(子类的)。

另一方面,该ssa()方法属于 C 类,并且由于引用变量属于 A 类,因此当您尝试时编译器会出错aCObj.ssa();

这只是多态性。由于 A 类引用变量可以是 A 或 C 对象,编译器将访问限制为仅对作为超类 A 的方法的通用方法的访问。接下来它检查该方法是否在类中实现实际对象(C)。如果不是,它会向上移动到超类(A)并调用超类的方法。但是如果它被实现,它会调用子类(C)的方法

于 2013-09-15T21:03:26.257 回答
0

对象的类型是 A 而不是 C,因此您无法访问实例变量,我认为如果将其公开,则可以。

于 2013-03-13T17:59:02.420 回答
0

因为aCObj被声明为类型A,所以只有在类型 A 中声明的方法是可访问的。编译器不能保证它也是 C 类型。

例如

你可能还有

public class B extends A {
    public void sayGreetings() {
        ...
    }
}

这没有 ssa 方法,但仍然可以分配给声明为 A 类型的对象

于 2013-03-13T17:54:41.107 回答
0

案例 1. 父类的引用变量可以指向其子类的对象.. 案例 2. 指向其子类对象的父类的引用变量可以类型转换为其子类的对象班级。

情况1:父类的引用变量只能调用父类内部定义的方法,也可以调用覆盖父类方法的子类方法,但不能调用独占的方法在儿童班。

情况2:父类的引用变量也可以调用其子类的方法。

这是由于多态性原理。

于 2013-06-20T10:24:57.493 回答
0

这是您所述查询的详细说明:

答案是“多态性”和“静态类型”的交集. 因为 Java 在编译时是静态类型的,所以您可以从编译器中获得某些保证,但您不得不遵守规则作为交换,否则代码将无法编译。在这里,相关保证是子类型(例如 Child)的每个实例都可以用作其超类型(例如 Parent)的实例。例如,您可以保证当您访问employee.getEmployeeDetails 或employee.name 时,方法或字段定义在可以分配给Parent 类型的变量employee 的任何非空对象上。为了保证这一点,编译器在决定您可以访问的内容时仅考虑该静态类型(基本上是变量引用的类型,Parent)。因此,您无法访问在对象的运行时类型 Child 上定义的任何成员。

答案取自以下链接: 为什么我们在 Java 中为子对象分配父引用?

于 2018-06-20T06:22:57.267 回答