继承中类以及成员变量初始化的讨论。

1.在讲之前首先应该了解static、final、static final修饰符的含义,这里简单介绍一下。

static:可以修饰变量、方法,被修饰的变量称之为静态变量,其初始化发生在其所在类第一次被装载的时;被修饰的方法同样。
final:可以修改变量、方法和类,被修饰的类或者方法是跟随该类的实力对象的,在该对象被加载到内存当中(调用该类的构造方法时)被初始化,被修饰的变量不可变,方法不可被override(等同于被private修饰的方法),被修饰的类不可被集成,不能是抽象的,并且成员变量和方法都是final(不可变)类型的。
static final :可以修饰变量或者方法。修饰变量是代表着这个变量是静态不可变的,初始化和static相同;被修饰的方法我没有过多的了解,觉得只是为了做一个不可被修改的静态类(感觉这样做没有意义)。
2.初始化顺序

在任何情况发生以前,将父类和子类(可以是多个)被加载到内存当中,会默认把分配给父类和子类的内存空间初始化成二进制的零。
之后根据继承的关系,从父类开始,依次执行初始化方法(调用构造器)进行实例化。
此时,类成员变量会“真正”的被初始化,按照你代码编写的样子。
3。实例

父类

public class Glyph {
private int a = 1; 

Glyph() {
System.out.println("父类构造器");
draw();//调用子类中重写的draw()方法
}

void draw(){
System.out.println("Glyph.draw()");
}
}

子类:

public class RoundGlyph extends Glyph {
private int radius = 1; //定义一个成员变量并赋初值
public RoundGlyph() {
System.out.println("子类构造器");
}

void draw(){
System.out.println("RoundGlyph.draw()="+radius);
}
}

测试:

public class Test {
public static void main(String[] args) {
new RoundGlyph();
}
}

运行结果:

父类构造器
RoundGlyph.draw()=0 //调用子类中重写的draw之后,打印子类的成员变量确实零。
子类构造器

  


4.结果分析

之所以运行的结果
RoundGlyph.draw()=0 而不是
RoundGlyph.draw()=1,是因为在父类构造器中调用子类中重写的方法时,此时子类并没有被“真正”实例化,现在还处于默认实例化的状态,子类的成员变量radius默认初始化为0,所以打印结果为零。
5.static、final、static final修饰的成员变量时的情况。

修改子类代码:---------------------static修饰时

public class RoundGlyph extends Glyph {
private static int radius = 1; //初始化
static{
radius = 2;//初始化
}
public RoundGlyph() {
radius = 3;//初始化
System.out.println("子类构造器");
}

void draw(){
System.out.println("RoundGlyph.draw()="+radius);
}
}

 


运行结果为:

父类构造器
RoundGlyph.draw()=2
子类构造器

    正如前面讲到的,static会在类被装载时就被初始化,也就是说,在子类RoundGlyph被装载时变量radius就已经被初始化了,但为什么是2,重复的初始化不会报错吗? 答案是不会的,初始化时,只会根据你编写的初始化顺序进行,如果重复的对一个变量进行初始化了,后一个结果会覆盖前一个结果,所以是2。

为什么不是3呢? 那是因为此时还子类RoundGlyph还没有被“真正”的实例化,也就是说,在父类的构造方法中调用子类重写的方法时,子类还没有执行构造方法呢。
修改测试代码:

public class Test {
public static void main(String[] args) {
new RoundGlyph().draw();
}
}

运行结果:

父类构造器
RoundGlyph.draw()=2
子类构造器
RoundGlyph.draw()=3

    正如上面所说的,运行结果符合预期。

被final修饰时
子类代码:

public class RoundGlyph extends Glyph {
private final int radius = 1;

public RoundGlyph() {
// radius = 3; //构造器初始化
System.out.println("子类构造器");
}

void draw(){
System.out.println("RoundGlyph.draw()="+radius);
}
}

运行结果:

父类构造器
RoundGlyph.draw()=1
子类构造器

  运行结果为1,为什么又为一了呢?不应该是零吗?

  答案:确实应该是1 !因为radius此时的final类型的,如上面所说,final修饰的变量是不可变的,要么直接赋初值,要                 么在构造器中初始化,无论如何必须初始化!上面的测试是直接赋初值,所以为了保证被final修饰的变量是不可                 变的,而在构造器中又没有初始化的变量,只能在默认初始化时对其进行初始化。

如果将上面子类的修改成:

public class RoundGlyph extends Glyph {
private final int radius;

public RoundGlyph() {
radius = 1; //构造器初始化
System.out.println("子类构造器");
}

void draw(){
System.out.println("RoundGlyph.draw()="+radius);
}
}

运行结果:

父类构造器
RoundGlyph.draw()=0
子类构造器

    这说明如果没对final修饰的变量赋值初始化时,就得在构造方法内对其进行初始化。运行结果和上面不同,也是好理解的了,因为是在构造器中初始化的,所以在没有“真正”初始化之前,radius的值一直等于0。

用static final修饰的变量,跟static修饰时很像,只是初始化有些区别
子类代码:

public class RoundGlyph extends Glyph {
private static final int RADIUS = 1;
// static{
// RADIUS = 1;
// }
public RoundGlyph() {
System.out.println("子类构造器");
}

void draw(){
System.out.println("RoundGlyph.draw()="+RADIUS);
}
}

子类代码2:(大同小异)

public class RoundGlyph extends Glyph {
private static final int RADIUS ;
static{
RADIUS = 1;
}
public RoundGlyph() {
System.out.println("子类构造器");
}

void draw(){
System.out.println("RoundGlyph.draw()="+RADIUS);
}
}

运行结果:

父类构造器
RoundGlyph.draw()=1
子类构造器

  这个就不多赘述了,和static的一样。只不过初始化时static final修饰的变量是不能在构造器中被初始化的,因为static是隶属于类的,不隶属于某一个具体的实例对象,static变量存储在static storage(静态存储空间)中。  

posted @ 2013-06-26 17:06  AaronChun  阅读(1325)  评论(2编辑  收藏  举报