Java_基础_继承的成员变量

如果子类继承了父类的某些成员变量,则子类就可以访问这些变量,就像这些变量是在子类中声明的一样。然而,现在有这样一个问题:这些成员变量是从父类复制了一份,还是与父类共享同一个变量呢?
我们首先看实例变量。
例:

package deep;

public class FieldSharing {

    public static void main(String[] ary) {
        Water w1 = new Water();
        Water w2 = new Water();
        w1.go();
        System.out.println(w1.des == w2.des);
        w2.print("对象w2的des:");
    }
}

class Liquid {
    protected String des = "des";
}

class Water extends Liquid {
    public void go() {
        System.out.println(super.des == this.des);
        print("修改之前……");
        this.des = "modify this.des";
        print("修改了this.des……");
        super.des = "modify super.des";
        print("修改了super.des……");
    }

    public void print(String msg) {
        System.out.println(msg);
        System.out.println("super.des:" + super.des);
        System.out.println("this.des:" + this.des);
    }
}

运行结果:
true
修改之前……
super.des:des
this.des:des
修改了this.des……
super.des:modify this.des
this.des:modify this.des
修改了super.des……
super.des:modify super.des
this.des:modify super.des
false
对象w2的des:
super.des:des
this.des:des

对于继承的实例变量,如果子类没有隐藏父类的变量,则变量在父类与子类之间是共享的,其实,对于同一个对象而言,this.des与super.des就是同一个变量,两个引用指向相同的String对象,因为String对象使用“==”判断时,只有地址相同才会返回true。因此,不管修改哪一个变量的值,另外一个也会随之改变。不过每创建一个对象,都会为实例变量分配单独的空间,不同的对象,实例变量也是不同的。因而修改对象w1的实例变量不会影响到对象w2的实例变量。
如果子类隐藏了父类中的变量,则父类的变量与子类的变量就是两个不同的变量,即this.des与super.des不再是同一个变量,其中一个变量值的改变自然不会使另外一个变量值也随之改变。例如本例,如果在子类Water中隐藏了父类变量des,声明如下:

package deep;

public class FieldSharing {

    public static void main(String[] ary) {
        Water w1 = new Water();
        Water w2 = new Water();
        w1.go();
        System.out.println(w1.des == w2.des);
        w2.print("对象w2的des:");
    }
}

class Liquid {
    protected String des = "des";
}

class Water extends Liquid {
    protected String des = "Water_des";// 声明

    public void go() {
        System.out.println(super.des == this.des);
        print("修改之前……");
        this.des = "modify this.des";
        print("修改了this.des……");
        super.des = "modify super.des";
        print("修改了super.des……");
    }

    public void print(String msg) {
        System.out.println(msg);
        System.out.println("super.des:" + super.des);
        System.out.println("this.des:" + this.des);
    }
}

运行结果:
false
修改之前……
super.des:des
this.des:Water_des
修改了this.des……
super.des:des
this.des:modify this.des
修改了super.des……
super.des:modify super.des
this.des:modify this.des
false
对象w2的des:
super.des:des
this.des:Water_des

一旦隐藏了父类的实例变量,this.des与super.des就不再是同一个变量了。
例:

package deep;

public class FieldSharing2 {

    public static void main(String[] ary) {
        System.out.println(Gas.des == Hydrogen.des);
        System.out.println(Gas.des == Nitrogen.des);
        System.out.println(Hydrogen.des == Nitrogen.des);
        print("修改之前……");
        Gas.des = "modify Gas.des";
        print("修改Gas.des后……");
        Hydrogen.des = "modify Hydrogen.des";
        print("修改Hydrogen.des后……");
        Nitrogen.des = "modify Nitrogen.des";
        print("修改Nitrogen.des后……");
    }

    public static void print(String msg) {
        System.out.println(msg);
        System.out.println("Gas.des:" + Gas.des);
        System.out.println("Hydrogen.des:" + Hydrogen.des);
        System.out.println("Nitrogen.des:" + Nitrogen.des);
    }
}

class Gas {
    protected static String des = "Gas";
}

class Hydrogen extends Gas {

}

class Nitrogen extends Gas {

}

运行结果:
true
true
true
修改之前……
Gas.des:Gas
Hydrogen.des:Gas
Nitrogen.des:Gas
修改Gas.des后……
Gas.des:modify Gas.des
Hydrogen.des:modify Gas.des
Nitrogen.des:modify Gas.des
修改Hydrogen.des后……
Gas.des:modify Hydrogen.des
Hydrogen.des:modify Hydrogen.des
Nitrogen.des:modify Hydrogen.des
修改Nitrogen.des后……
Gas.des:modify Nitrogen.des
Hydrogen.des:modify Nitrogen.des
Nitrogen.des:modify Nitrogen.des

子类继承父类的静态变量,如果在子类中没有隐藏该变量,则父类与子类中的静态变量是同一变量,其中一个的改变就会导致其他变量也随之改变。也就是说,父类与所有子类共享父类中的静态变量。
如果子类隐藏了父类的静态变量,则子类与父类的静态变量就是不同的变量。
例:

package deep;

public class FieldSharing2 {

    public static void main(String[] ary) {
        System.out.println(Gas.des == Hydrogen.des);
        System.out.println(Gas.des == Nitrogen.des);
        System.out.println(Hydrogen.des == Nitrogen.des);
        print("修改之前……");
        Gas.des = "modify Gas.des";
        print("修改Gas.des后……");
        Hydrogen.des = "modify Hydrogen.des";
        print("修改Hydrogen.des后……");
        Nitrogen.des = "modify Nitrogen.des";
        print("修改Nitrogen.des后……");
    }

    public static void print(String msg) {
        System.out.println(msg);
        System.out.println("Gas.des:" + Gas.des);
        System.out.println("Hydrogen.des:" + Hydrogen.des);
        System.out.println("Nitrogen.des:" + Nitrogen.des);
    }
}

class Gas {
    protected static String des = "Gas";
}

class Hydrogen extends Gas {

}

class Nitrogen extends Gas {
    protected static String des = "Nitrogen_Gas";// 隐藏父类的静态变量
}

运行结果:
true
false
false
修改之前……
Gas.des:Gas
Hydrogen.des:Gas
Nitrogen.des:Nitrogen_Gas
修改Gas.des后……
Gas.des:modify Gas.des
Hydrogen.des:modify Gas.des
Nitrogen.des:Nitrogen_Gas
修改Hydrogen.des后……
Gas.des:modify Hydrogen.des
Hydrogen.des:modify Hydrogen.des
Nitrogen.des:Nitrogen_Gas
修改Nitrogen.des后……
Gas.des:modify Hydrogen.des
Hydrogen.des:modify Hydrogen.des
Nitrogen.des:modify Nitrogen.des

子类Hydrogen没有隐藏父类Gas的静态变量,则Hydrogen.des与Gas.des是同一个变量,其中一个值改变了,另外一个的值也会改变。子类Nitrogen隐藏了父类Gas的静态变量,所以Nitrogen.des与Gas.des不是同一个变量。其中一个的值改变了,另外一个的值不会改变。
相对于实例变量,静态变量的继承更加容易出错。因为实例变量是基于对象的,每个对象都在堆上分配单独的空间来存放实例变量,不同对象之间的实例变量互不干扰。而静态变量是基于类的。由类的所有对象所共享。如果子类继承了父类的静态变量(没有隐藏),则该静态变量还由所有子类(包括子类的对象)所共享。
假设Gas类已存在,而Hydrogen类与Nitrogen类是在以后程序升级中新加入的,并且3个类在不同的编译单元(文件)甚至在不同的包中。程序员A编写Hydrogen类,并在静态初始块中奖des重新赋值:

    static {
        des = "Hydrogen";
    }

同时,程序员B编写Nitrogen类,同样在静态初始化块中将des重新赋值:

    static {
        des = "Nitrogen";
    }

如此一来,在使用这两个类的时候,问题就会产生。在程序运行时,假设Hydrogen类先得到初始化,则将des修改为“Hydrogen”,后来,Nitrogen类也得到初始化,就会将des修改为“Nitrogen”,由于两个类使用的des是同一个变量,这便无意中修改了Hydrogen类的des,当再次使用Hydrogen类的des时,就会得到不正确的结果。
这个问题告诉我们,如果类的静态变量不是private类型的,通常也应该同时将其声明为final,以免发生上面所述的现象。

你可能感兴趣的:(java_基础)