Java中为什么访问了父类的成员变量而不是子类成员变量?

问题描述

publicclassFather{intnumber=3;Father(){super();show();return;}voidshow(){System.out.println("Fathershow..."+number);}}publicclassSonsextendsFather{intnumber=8;Sons(){super();//此处是分水岭,父类初始化完毕以后,才能轮到子类成员变量的显示初始化System.out.println("Sons'sConstructorrun..."+number);return;}////voidshow(){//System.out.println("Sonsshow..."+super.number+"..."+number);//此处父类成员变量的显示初始化过程和子类一样,因为父类Father的父类是Object,必须先把Object初始化完毕以后,Father类的成员变量才能进行显示初始化//}}publicclassFatherSonsRun{publicstaticvoidmain(String[]args){Sonssons=newSons();//new对象的时候,先在堆内存中分配此对象的内存空间,此对象有一个首地址值,并对此对象中的成员变量进行默认初始化(隐式初始化)sons.show();}}这里,我如果把子类的show方法注释掉,那么将会访问父类的show方法,但是在访问父类show方法里面将会访问的是父类的成员变量,而不是子类的成员变量,有点不理解?我是从内存图的角度去理解的,有点理解不通。运行结果为:Fathershow...3Sons'sConstructorrun...8Fathershow...3因为访问number的话,应该是this.number,访问的应该是图中右边堆内存里的成员变量this.number,应该输出值为0才对,但为什么结果是父类的number成员变量3呢,高手能从内存的角度帮我分析下吗?

解决方案

解决方案二:
我覆盖后的输出结果,我按照内存图的理解,应该是输出Fathershow...0Sons'sConstructorrun...8Fathershow...8才对,就是不能理解从内存角度分析的结果为什么不对,图中的三块内存区域分别是,左上是栈内存,右上是堆内存,下边是方法区
解决方案三:
你在Debug模式下单步执行就知道了,那个intnumber=3是在类的构造方法之前就执行的。所以到了构造方法中这些成员变量已经有值了。当然了,如果你在父中构造方法中调用覆盖的子类的show方法,那么子类中的number这个时候还没有初始化,因此子类的show在被父类的构造方法调用时它得到的this.number就是0而不是8。
解决方案四:
在每一行下断点,然后debug它。以前我也没注意这个初始值的问题,后来是在debug过程中发现初始值的赋值后才进到构造方法中了。
解决方案五:
嗯,这些东西还是自己调试运行理解的会更深刻。可以在各个位置进行输出父类{//父类代码块}构造函数属性值子类{//子类代码块}构造函数属性值看看java对类加载,先运行哪些
解决方案六:
我也有个问题,为什么在初始化Fahter进入构造函数的时候调用的是Sons的show()方法啊?这样的话在开发过程中使用继承会不会出现好多问题啊?
解决方案七:
这本来就是多态的概念,当你打算在构造函数中使用可能被覆盖的方法,这本来就表示,这个被覆盖的方法不应该与状态之间的关联如此密切,(比如,最好是它不要使用要求在构造方法中初始化的成员变量),或者你在访问过程上需要明确的思考是用成员变量名访问它还是用getter/setter方法它,总之,这是设计的决策问题,只要认真思考过,并且对特定的约定之处写在文档中就没有什么疑问,毕竟别人打算使用你的API的第一步应该是看API文档而不是猜测。引用5楼mrliu0905的回复:

我也有个问题,为什么在初始化Fahter进入构造函数的时候调用的是Sons的show()方法啊?这样的话在开发过程中使用继承会不会出现好多问题啊?

解决方案八:
我想问的是,为什么Sonssons=newSons();sons.show();如果show方法没有在子类中覆盖,那么此时sons.show();其实访问的是父类中的show方法,那么访问父类中的show方法时,show方法里面访问的number为什么是父类的成员变量,而不是子类的成员变量呢?因为此时的this指向的对象,其里面存放的成员变量应该是this.number应该等于8,super.number应该等于3。难道我要理解此时new出来的对象类型是Father类型的?
解决方案九:
现在show是父类的,这个number就解释成父类的。这些是在编译时确定使用谁的方法和变量,不是等到运行时。你提到的number解释成this.number是在暗示在运行的时候。引用7楼u010021183的回复:

我想问的是,为什么Sonssons=newSons();sons.show();如果show方法没有在子类中覆盖,那么此时sons.show();其实访问的是父类中的show方法,那么访问父类中的show方法时,show方法里面访问的number为什么是父类的成员变量,而不是子类的成员变量呢?因为此时的this指向的对象,其里面存放的成员变量应该是this.number应该等于8,super.number应该等于3。难道我要理解此时new出来的对象类型是Father类型的?

解决方案十:
那多态的时候,调用了子类覆盖父类的方法,我看到相关文章说,在编译的时候不知道调用谁的成员变量和成员方法,但在运行时才知道调用谁的成员变量和成员方法,和你说的岂不是矛盾吗?
解决方案十一:
代码有个很明显的问题,一个类里面不只能有一个public么
解决方案十二:
那把这句话改一下:用谁的方法就找和谁相关的成员变量。引用9楼u010021183的回复:

那多态的时候,调用了子类覆盖父类的方法,我看到相关文章说,在编译的时候不知道调用谁的成员变量和成员方法,但在运行时才知道调用谁的成员变量和成员方法,和你说的岂不是矛盾吗?

解决方案十三:
Quote: 引用11楼humanity的回复:

那把这句话改一下:用谁的方法就找和谁相关的成员变量。这正是我无法从内存图的角度去理解的内容。
解决方案十四:
在java中只有普通方法(除static和private之外)的调用是多态的,而域的访问是前期绑定而不是动态绑定的。也就是说编译上面的代码后,在内存中son同时拥有两个版本的number,一个从基类继承而来,另一个则为默认成员,当你没有在son中覆盖show方法时,很明显son.show调用的是基类版本的show方法,由于域是前期绑定的,也就是在编译期决定了基类show方法;中的number版本是基类版本的number。显然,在Son中覆盖了show后又是另一回事了
解决方案十五:
引用9楼u010021183的回复:
那多态的时候,调用了子类覆盖父类的方法,我看到相关文章说,在编译的时候不知道调用谁的成员变量和成员方法,但在运行时才知道调用谁的成员变量和成员方法,和你说的岂不是矛盾吗?

成员变量应该是前期绑定的,普通方法(非static和final)才是动态绑定的

时间: 2024-09-13 03:47:31

Java中为什么访问了父类的成员变量而不是子类成员变量?的相关文章

浅谈java中的访问修饰符_java

一. public:所有类都可以访问 protected:所有子类和同包下的类都可以访问 缺省:同包类都可以访问 private:类本身才可以访问 注意点:protected修饰类属性时,例如 复制代码 代码如下: package Parent; public class Parent{     protected int i=5; } package Son; public class Son extends Parent{     public static void main(String

多线程 java 同步 锁-java中多线程访问同步问题

问题描述 java中多线程访问同步问题 public class SyschronizedSample{ private int value; public synchronized int get(){ return value;} public synchronized void set(int value) { this.value=value; } } 以上的代码中,要使得访问value时具有线程安全,所以在set和get方法中都加了synchronized同步语句,如果只在set方法前

java中什么是外围类,是不是object类的子类呢

问题描述 java中什么是外围类,是不是object类的子类呢 外围类是相对于object类来说的吗,和普通类相比有什么区别,外围类的父类是什么类呢 解决方案 是相对于内部类的外部类? 解决方案二: 嵌套类与外围类 解决方案三: 是相对于内部类的外部类?

Java中的访问修饰符详细解析_java

1.类的修饰符分为:可访问控制符和非访问控制符两种. 可访问控制符是:公共类修饰符 public 非访问控制符有:抽象类修饰符 abstract :最终类修饰符 final 1 )公共类修饰符 public : Java 语言中类的可访问控制符只有一个: public 即公共的.每个 Java 程序的主类都必须是 public 类作为公共工具供其它类和程序使用的应定义为 public 类. 2 )抽象类修饰符 abstract :凡是用 abstract 修饰符修饰的类,被称为抽象类.所谓抽象类

谈谈Java中protected访问权限

来谈谈protected访问权限问题.看下面示例1: Test.java class MyObject {} public class Test { public static void main(String[] args) { MyObject obj = new MyObject(); obj.clone(); // Compile error. } } 此时出现上文提到的错误:The method clone from the type Object is not visiuable.

举例详解Java中的访问权限修饰符_java

访问权限符:(1)public: 对于成员来说:任何其他类都可以访问它们,不管在同一个包中还是在另外的包中. 对于类来说:    也是一样.(2)friendly: 对于成员老说:如果一个类的成员没有任何权限修饰,那么它门就是缺省包访问权限,用friendly来表示,注 意friendly不是Java中的关键字,这里是个人喜欢的方式用它表示而已.同一个包内其它类可以访问,但包外 就不可以.对于同一个文件夹下的.没有用package的classes,Java会自动将这些classes初见为隶属于该

浅析Java中的访问控制权限_java

Java中为什么要设计访问权限控制机制呢?主要作用有两点: (1)为了使用户不要触碰那些他们不该触碰的部分,这些部分对于类内部的操作时必要的,但是它并不属于客户端程序员所需接口的一部分. (2)为了让类库设计者可用更改类的内部工作方式,而不必担心会对用户造成重大影响.  Java中的访问权限控制的等级,按照权限从大到小依次为: Public -> protected -> 包访问权限(没有权限修饰词)-> private.  一.包(package) Java中包(package)的概念

Java中一些基础概念的使用详解_java

类的初始化顺序 在Java中,类里面可能包含:静态变量,静态初始化块,成员变量,初始化块,构造函数.在类之间可能存在着继承关系,那么当我们实例化一个对象时,上述各部分的加载顺序是怎样的? 首先来看代码: 复制代码 代码如下: class Parent {     public static StaticVarible staticVarible= new StaticVarible("父类-静态变量1");         public StaticVarible instVaribl

转 Java中的native关键字

一.  什么是Native Method    简单地讲,一个Native Method就是一个java调用非java代码的接口.一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C.这个特征并非java所特有,很多其它的编程语言都有这一机制,比如在C++中,你可以用extern "C"告知C++编译器去调用一个C的函数.    "A native method is a Java method whose implementati