类的初始化顺序是老生长谈的问题。但是它仍然是面试中常见的,也可以说是不可缺少的题目。因为在项目开发过程中,经常会因为这个出现BUG,且这样的BUG一般很难查。
从C语言转用java语言的人常常会这样写代码:
他们总是喜欢在声明的时候初始化,我在学java之初,也有人告诉我这样写,说这是好习惯。后面的工作中,发现这是很大的错误,我们的项目中,因为这种写法,出现了很多BUG。看一下下面这个简单的例子:
在这段代码,其实是一个小的框架思想,initAttrs方法是用来初始化成员属性用的,为什么不用B类的构造方法去做呢?因为如果有很多初始化的事情要做,全部都放在构造器中做,就会显得很复杂,不利于维护。团队开发时,也不太方便。且如果放在构造器中来写,子类继承时,将不能重写其代码。写成这样,子类仅需要关注自己要初始化的东西就好了。
这段代码运行的结果出乎一般人的意料。大多数人会回答结果是:
[color=red][size=large]aaa[/size][/color]
但是结果却是:
[color=red][size=large]null[/size][/color]
为什么会这样呢?这就需要细说一下类的初始化顺序和方法的重写了。
先从简单的讲起。方法的多态有两种,一种是重载,一种是重写。重载没有什么好说的,两个方法有一样的名字,参数和返回值有些差异(其实这里面有点小小的问题,我会在别的文章再说)。重写就不一样了,重写是方法的参数必须是一样的,但返回值可以不一样,子类方法的返回值要和父类方法返回值一样或是其子类,重写必须存在于父类和子类之间,子类重写父类的方法。这时,用子类对象去访问该方法,永远调用到的是子类的方法,即使是强行转化为父类的引用,就像父类的方法不存在一样。看下面的例子:
未完,待续
从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("--------------------------------");
}
}
未完,待续