java 类的初始化顺序和多态

类的初始化顺序是老生长谈的问题。但是它仍然是面试中常见的,也可以说是不可缺少的题目。因为在项目开发过程中,经常会因为这个出现BUG,且这样的BUG一般很难查。

从C语言转用java语言的人常常会这样写代码:

public class Sample {

private String str = null; // str = "";

private boolean flag = false;

public String getStr() {
return str;
}

public void setStr(String str) {
this.str = str;
}

public boolean isFlag() {
return flag;
}

public void setFlag(boolean flag) {
this.flag = flag;
}

// Other code
// ........
}

他们总是喜欢在声明的时候初始化,我在学java之初,也有人告诉我这样写,说这是好习惯。后面的工作中,发现这是很大的错误,我们的项目中,因为这种写法,出现了很多BUG。看一下下面这个简单的例子:

class A {

public A() {
initAttrs();
}

public void initAttrs() {
System.out.println("initAttrs in A");
}
}

class B extends A {

public String s = null;

public B() {
super();
}

public void initAttrs() {
s = "aaa";
}
}

public class InheritProblem {

public static void main(String[] args) {
B b = new B();
System.out.println(b.s);
}
}

在这段代码,其实是一个小的框架思想,initAttrs方法是用来初始化成员属性用的,为什么不用B类的构造方法去做呢?因为如果有很多初始化的事情要做,全部都放在构造器中做,就会显得很复杂,不利于维护。团队开发时,也不太方便。且如果放在构造器中来写,子类继承时,将不能重写其代码。写成这样,子类仅需要关注自己要初始化的东西就好了。
这段代码运行的结果出乎一般人的意料。大多数人会回答结果是:
[color=red][size=large]aaa[/size][/color]

但是结果却是:
[color=red][size=large]null[/size][/color]

为什么会这样呢?这就需要细说一下类的初始化顺序和方法的重写了。
先从简单的讲起。方法的多态有两种,一种是重载,一种是重写。重载没有什么好说的,两个方法有一样的名字,参数和返回值有些差异(其实这里面有点小小的问题,我会在别的文章再说)。重写就不一样了,重写是方法的参数必须是一样的,但返回值可以不一样,子类方法的返回值要和父类方法返回值一样或是其子类,重写必须存在于父类和子类之间,子类重写父类的方法。这时,用子类对象去访问该方法,永远调用到的是子类的方法,即使是强行转化为父类的引用,就像父类的方法不存在一样。看下面的例子:

class A {
public String str;

public A() {
str = "a";
}

public String getAStr() {
return str;
}

public String print() {
return "A Print";
}
}

class B extends A {
public String str;

public B() {
str = "b";
}

public String getBStr() {
return str;
}

public String print() {
return "B Print";
}
}

public class InheritProblem {

public static void main(String[] args) {
A a = new B();
System.out.println("a.str=" + a.str);
System.out.println("a.getAStr()=" + a.getAStr());
System.out.println("a.print()=" + a.print());
System.out.println("--------------------------------");
B b = new B();
System.out.println("b.str=" + b.str);
System.out.println("b.getAStr()=" + b.getAStr());
System.out.println("b.getBStr()=" + b.getBStr());
System.out.println("b.print()=" + b.print());
System.out.println("--------------------------------");
A c = b;
System.out.println("c.str=" + c.str);
System.out.println("c.getAStr()=" + c.getAStr());
System.out.println("c.print()=" + c.print());
System.out.println("--------------------------------");
}
}

未完,待续
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值