有人可以解释为什么我在运行程序时会得到这个? (简单的Java多态性)

时间:2014-02-22 10:42:28

标签: java polymorphism class-hierarchy

所以,我在Java中有这三个类。 当我运行程序时,我得到:

  

20,
  15,
  10,

我的问题是,为什么我会这样做而不是:

  

15,
  20(不是public int getX();在B类中得到15 + 5 = 20?),
  10

例如?

请你一步一步地向我解释一下这个程序到底发生了什么,因为我对输出(以及序列)非常困惑。

public class A {

    private int x = 15;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public void printX() {
        System.out.println(this.getX());
    }

}

子:

public class B extends A {

    private int x = 5;

    @Override
    public int getX() {
        return super.getX() + x;
    }

    @Override
    public void setX(int x) {
        super.setX(x);
        super.printX();
    }

    @Override
    public void printX() {
        System.out.println(super.getX());
    }

}

public class C {

    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.getX());
        a.setX(10);
        a.printX();
    }

}

6 个答案:

答案 0 :(得分:1)

这是因为您将a实例化为B对象 - A a = new B()。明确的a类型是A并不重要;它比实际类型B更通用(抽象)(因为B继承自A),因此多态性在第一顺序中调用B方法(更具体)。这同样适用于领域。

调用a.getX()BA的{​​{1}}的引用,返回其getX()(超类方法没有引用它的对象在这种情况下调用),然后添加155的{​​{1}}),结果为B

后续调用的行为方式类似。

答案 1 :(得分:0)

我已经给出了一个类似于你的问题的基本例子,你会得到你的答案。这是运行时多态

的概念

Inheritance创建typecompatibility。它允许超类引用引用子类的对象。 (反向不是真的)。​​

引用子类对象的超类引用只能用于访问子类的继承和overrridden方法。使用超类的引用无法访问sub class中新定义的成员。

class A
{
 void f1()//this holds address of object of B
 {
   System.out.println("A f1");
 }
 void f2()
 {
   System.out.println("A f2");
 }
}//A

class B extends A
{
 void f3()//new method
 {
   System.out.println("B f3");
 }
 void f2()//this holds address of object of B
 {
   System.out.println("B f2 starts");
   f3(); //this.f3()
   System.out.println("B f2 ends ");

 }

}//B

class TypeCmptbl
{
 public static void main(String args[])
 {
   A ref; //reference of A
   ref = new B();//Object of B

   //ref.inherited()  allowed
   ref.f1();

   //ref.overridden() allowed
   ref.f2();

  //ref.newMembersOfChild() not allowed
  //ref.f3();

 }//main
}

考虑声明

ref.f2();

这里ref是A类的引用,它有B类对象的地址f2()是一个重写方法。

当编译器检测到这样的语句时,它不会将函数调用与任何定义绑定。它只验证通话。

此类调用的绑定留给运行时环境。在程序运行时,系统识别对象的数据类型,并使用对象类提供的函数定义绑定函数调用。函数调用和函数定义之间的这种类型的绑定称为"runtime polymorphism"

答案 2 :(得分:0)

A a = new B();

因此a的具体类型为B

System.out.println(a.getX());

您在类型B的对象上调用getX()。因此调用以下方法,因为a的具体类型为B,而B已覆盖由A:

定义的getX()方法
public int getX() {
    return super.getX() + x;
}

它添加了B的x(其值为5),结果为super.getX()。 A中的此方法定义为

public int getX() {
    return x;
} 

所以它返回A的x,它被初始化为15。

结果是5 + 15 = 20。

其余的可以用同样的方式解释。请记住,不能以多态方式访问字段。只有方法。因此,在A的代码中,当您看到x时,它始终意味着“字段x在A中的值”。在B的代码中,当您看到x时,它始终意味着“字段x在B中的值”。

答案 3 :(得分:0)

您的问题与java中的运行时多态性有关,即方法在运行时绑定,变量在编译时绑定

在你的例子中

public class C {
public static void main(String[] args) {
    A a=new B();                  
    System.out.println(a.getX());
    a.setX(10);
    a.printX();
}
}

 // reference is of A but the object is of B, so at runtime JVM see that memory is of B so the B's method is called, this is runtime Polymorphism

答案 4 :(得分:0)

当调用以下语句时,将调用类B的getX()。

 System.out.println(a.getX());


  @Override
public int getX() {
   return super.getX() + x;  // this will add 15 from class A + 5 in this method. 
}
the above statement displays 20

当调用以下语句时,     a.setX(10);

@Override
public void setX(int x) {
   super.setX(x);    // observe this method, this prints 15 
   super.printX();   // this prints 10
}

// super.setX(X);它会调用

public void setX(int x) {
   this.x=x;     // 10 <--- 15 so 15 is displayed
 }

这里this.x指的是通过a.setX(10)传递的值。

答案 5 :(得分:0)

当你说:

  

a a = new B();

它意味着A的对象用类B实例化。因此,在内存中,为对象'a'保留一个空格,其中包含B类(而不是A)的所有方法和属性。

因此,当执行第一个print语句时,它执行B类的getX()方法而不是A类的getX()方法。

对于对象'a'调用的其他方法,将调用类B的方法。

这也称为动态绑定,因为JVM在运行时将内存分配给对象'a'而不是编译时。

有关动态绑定的更多详细信息,请检查以下链接:

  

http://www.tutorialspoint.com/java/java_overriding.htm

     

http://www.tutorialspoint.com/java/java_polymorphism.htm

我还建议您在计算机上安装eclipse并在调试模式下运行代码。 这是学习代码的最佳方式。