今天在看java编程思想的时候,遇到了一个问题,没有想明白,于是放在这里讨论一下,一面自己忘记。
先上代码吧
package test;
import edu.princeton.cs.algs4.StdOut;
class Cycle{
public int x = 1;
static void ride(Cycle c){
System.out.println("" + c);
System.out.println("the number is :" + c.wheels());
}
public int wheels(){
return this.x;
}
}
class Unicycle extends Cycle{
public int x = 2;
public void f(){
StdOut.println(x);
}
}
class Bicycle extends Cycle{
public int x = 3;
}
class Tricycle extends Cycle{
public int x = 4;
}
public class test {
public static void main(String[] args){
Unicycle uc = new Unicycle();
Bicycle bc = new Bicycle();
Tricycle tc = new Tricycle();
Cycle.ride(uc);
Cycle.ride(tc);
Bicycle.ride(bc);
uc.f();
}
}
下面是输出结果
test.Unicycle@15db9742
the number is :1
test.Tricycle@6d06d69c
the number is :1
test.Bicycle@7852e922
the number is :1
2
问题是这样的:
三个子类都继承于Cycle父类,并且覆盖了父类的成员变量x,但是在通过子类对象来调用父类方法的时候,方法中使用的依然是父类自己的成员变量(如上输出的number都是父类的1).于是就想是不是因为成员变量没有覆盖父类的成员变量。于是写了一个子类方法输出了一下,发现成员变量覆盖成功。那么问题是什么呢?或者说,我要如何才能通过多态来调用子类成员变量,而不用重写一遍父类方法?(有点绕,看输出就明白了,我想通过父类的wheels来调用子类的x变量。)
我的理解:
我自己在查了一些别人的问题与解决,发先一些原理。
第一 子类在继承父类的过程中,会把父类的所有方法与成员变量都Copy一边,放在自己的super域(可以通过super关键字主动访问,private不能访问),在子类调用一个方法的时候,会先在自己的this域内搜索是否含有该方法,没有发现,就会向上转型,到super域进行访问,找到该方法后便开始执行,在执行的过程中因为就近原则(看网友这么说的,不知道这个就近原则准不准确),方法中调用的成员变量会是父类的成员变量,于是才会有我现在的结果。
第二 也是别人总结的一个规律“成员变量的调用与调用的引用类型严格一致”即这个成员变量的调用与调用时所用的引用类型一致,下面有一个例子,大家一看一看就明白
class Base2 {
int i = 1;
String s = "Base";
}
class Child2 extends Base2 {
int i = 9;
String s = "Child";
public static void main(String[] args) {
Child2 c1 = new Child2();
Base2 c2 = new Child2();
System.out.println(c1.i);
System.out.println(c1.s);
System.out.println(c2.i);
System.out.println(c2.s);
}
}
以下是输出结果:
9
Child
1
Base
也许在后面学习了其他机制以后就知道怎么做了吧,我隐约记得有个Class类型,支持向下转型。