最近看到这么个问题,大约就是父类子类中好多成员、方法,有的静态有的非静态,实例化一个或者多态调用的时候具体怎么个执行顺序,本以为自己知道的,结果越绕越糊涂,在此记录学习过程。
如果实例化一个子类对象
Chlid mChlid = new Chlid();
执行顺序如下
1、父类静态变量和静态代码块(先声明的先执行);
因为有继承关系,所以先加载父类,加载过程中执行了静态变量和静态代码块
2、子类静态变量和静态代码块(先声明的先执行);
其次才加载子类,执行子类的静态变量和静态代码块
3、父类的变量和代码块(先声明的先执行);
构造方法前先声明所有非静态成员
4、父类的构造函数;
子类构造方法中必须显示或隐式调用父类构造方法
5、子类的变量和代码块(先声明的先执行);
6、子类的构造函数。
父静子静,父非静父构,子非静子构
父类
public class Parent {
static int age = 30;
Temp mTemp = new Temp("FF");
String name = "Pappy";
static {
Log.d("FF", "静态代码块");
}
public Parent() {
Log.d("FF", "构造器");
}
void speak(){
Log.d("FF", "我是"+ name);
}
static void describe(){
Log.d("FF", "我" + age + "了");
}
}
子类
public class Chlid extends Parent {
static int age = 17;
Temp mTemp = new Temp("CC");//为体现非静态成员
String name = "Baby";
static {
Log.d("CC", "静态代码块");
}
public Chlid() {
Log.d("CC", "构造器");
}
@Override
void speak() {
Log.d("CC", "我是"+ name);
}
static void describe(){
Log.d("CC", "我" + age + "了");
}
}
temp
public class Temp {
public Temp(String temp) {
Log.e(temp, "非静态成员");
}
}
测试类
public class TestFC {
Chlid mChlid = new Chlid();
Parent mParent = new Parent();
Parent mPC = new Chlid();
//报错ClassCastException
// Chlid mCP = (Chlid) new Parent();
public void start1(){
Log.e("Test","**********");
Log.e("Test","父引-父象");
mParent.speak();
mParent.describe();
}
public void start2(){
Log.e("Test","**********");
Log.e("Test","子引-子象");
mChlid.speak();
mChlid.describe();
}
public void start3(){
Log.e("Test","**********");
Log.e("Test","父引-子象");
mPC.speak();
mPC.describe();
}
}
调用测试
TestFC testFC = new TestFC();
testFC.start1();
testFC.start2();
testFC.start3();
log结果
以上测试用例基本都涵盖这方面所有内容了,现在来分析
1.因为TestFC先声明实例化Child,从log前几段可以看出,执行顺序确实是"父静子静,父非静父构,子非静子构",之后因为已经加载了两个类,因此静态代码块都不执行了,但是只要执行子类构造方法,必先调用父类构造方法。
2.多态问题看最后一组log可以看出,父类引用指向子类对象时,调用非静态成员是子类自己的,因为对象就是子类,但是静态成员却还是父类的,其中如果把子类中的静态方法去掉,第二组log"子引-子象"中会显示"我30了"。因此又得出一个结论“静态方法可以继承,但不能重写”