今天在学习java的面向对象时,无意间发现一个问题。

public class testEquals{
    public static void main(String[] args){
    Child cd1 = new Child();
    cd1.f();

    }
}

class Father{
    public int value;  

    public void f(){
        value = 100;
        System.out.println("classFatherValueIs:"+value);
    }
}

class Child extends Father{
    public int value;   //请看这里
    public void f(){
        super.f();
        value = 200;
        System.out.println("classChildValueIs:"+value);  //输出
        System.out.println(value);
        System.out.println(super.value+"super.value");
    }

}

/**
result:
classFatherValueIs:100
classChildValueIs:200
200
100super.value
**/

当Child类在继承Father类时,子类有重新声明value变量,在Child.f()内对value变量的值进行修改并不会改变父类Father.f()的值。

断点debug:父类子类均有自己的值

java继承可以调用父类的父类方法吗_java继承可以调用父类的父类方法吗

而当我将子类的value变量声明去掉后,情况变得和想象中就不太一样了,以往我所认知的继承应该是将非private的成员统统复制过来,并于父类互补干扰。但实际并不是这个样子。

当去掉子类的类型声明

package cn.sxt.oop;

public class testEquals{
    public static void main(String[] args){
    Child cd1 = new Child();
    cd1.f();

    }
}

class Father{
    public int value;

    public void f(){
        value = 100;
        System.out.println("classFatherValueIs:"+value);
    }
}

class Child extends Father{

    public void f(){
        super.f();
        value = 200;
        System.out.println("classChildValueIs:"+value);
        System.out.println(value);
        System.out.println(super.value+"super.value");
    }

}

/**
result:
classFatherValueIs:100
classChildValueIs:200
200
200super.value

父类的value值随着子类一起改变了。虽然没有显示的在子类中声明value变量,但通过继承,应该是互不干扰才是,为什么在子类定义value,父类的值也改变了。

断点debug:此时父类的value也受到了子类的影响变成了200

java继承可以调用父类的父类方法吗_System_02


子类究竟时如何被实例化出来的?

以上面child类为例,Child的父类是Father类,而father类继承所有类的老子Object类。也就是说实例化一个Child类,首先要生成一个Object类,father类继承Object类中被特别定义的成员,并根据要求生成Father实例,Child类再继承Father实例生成child对象。也就是说如果想单独生成Child类,Father于Object类也再咱们不知情的情况下生成了。

java继承可以调用父类的父类方法吗_System_03

大胆推测一下:

继承并不是单纯的复制父类代码。在子类中没有对父类的相同的成员名进行单独定义时,子类继承来的成员其实只是对父类成员的引用。当单独去进行声明,即使没有重新去定义逻辑,也相当于覆盖了继承来的属性或方法。

如果继承是单纯的复制代码,那么子类所占的内存需要和父类一样打,甚至更大。所以相同的部分向上引用应该就是一个很好的办法。

后来在科普看到了类似的解答,和我猜的大致差不多:

继承是复制还是共用?例如 Dog类继承Animal类,在Dog中的属性修改,Animal中的属性也会一起改变吗?如果用Dog和Animal分别实例化对象,dog和animal,这两者的属性是公用还是各占内存,毫无关系?另外要对子类继承的属性赋值,通过super(),最终跳到父类构造器,此时,是不是创建了一个父类对象?
1、共用更恰当,因为父类的一些私有方法和私有属性是不会被继承的,继承之后,子类可以共用父类的公有属性和公有方法,,
2、Dog中如果没有重新定义父类已有的同名属性,则修改公有属性就是修改父类的公有属性,即父类的属性会一起改变,,
3、如果两者都实例化,肯定是两个不同的对象,内存地址不可能共用的,就算是Dog实例化多次也是只是多个不同的对象,内存地址是不一样的,,
4、super其实就是一个区分标志,不会新建对象的,,,super()只是调用父类的无参构造方法,因为子类也有无参构造方法,,只要是子类要调用在父类中有同名同参的方法或者同名的属性,都要用到super来区分,,

关于这部分的资料感觉还是蛮少的,所以这个想法是否正确也不能保证。

还有一个很有意思的东西

package cn.sxt.oop;

public class A {
    int i = 12;
}

class B extends A {
    int i = -6;
    public static void main(String[] args) {
        A xx = new B();
        System.out.println(xx.i);
    }
}

/**
result:
12
**/

B实例的i值是A类的i值,有点懵