继承是java实现多态的一个重要元素之一,本文主要是自我学习了解java继承中父类和子类的关系。下面看父类和子类的源码
父类:
public class Parent {
//公有属性
private int a = 5;
//公有属性b
public int b = 10;
//公有属性c
public int c = 10;
//静态代码块
static {
System.out.println("parent static");
}
//非静态代码块
{
System.out.println("Non-static block from Parent");
}
//构造方法
public Parent(){
System.out.println("Parent init constructor");
}
//获取私有属性a的值
public int getA(){
return a;
}
//公有方法
public void say(){
System.out.println("hello i am parent");
}
}
子类:
public class Son extends Parent {
//子类私有属性
private int a = 6;
//子类覆盖了父类的属性b
public int b = 20;
//子类的静态代码块
static {
System.out.println("Son static");
}
//子类非静态代码块
{
System.out.println("Non-static block from Son");
}
//子类的构造方法
public Son(){
// super();
System.out.println("Son constructor");
}
//子类覆盖了父类的say方法
@Override
public void say() {
System.out.println("I am son");
}
public int getA(){
return a;
}
//子类新定义的方法
public int getH(){
return 5;
}
}
用例1(父类引用指向子类对象)测试执行顺序:
本例主要测试父类和子类中静态代码块、非静态代码块、构造函数的执行顺序
public static void main(String[] args) {
Parent parent = new Son();
}
//输出结果
parent static
Son static
Non-static block from Parent
Parent init constructor
Non-static block from Son
Son constructor
从运行结果可以看出执行顺序:父类静态代码块-子类静态块-父类非静态块-父类构造方法-子类非静态代码块-子类构造方法
因此可以得出结论:对于普通类代码的执行顺序为【静态代码块-非静态代码块-构造方法】;对于父子类继承关系的类, 无论是父类引用指向子类对象还是子类引用指向自身对象代码的执行顺序都为【父类静态代码块-子类静态块-父类非静态块-父类构造方法-子类非静态代码块-子类构造方法】,总之先执行父类的静态代码块然后紧跟着执行子类的静态代码块,其他的保持不变
注意:如果main方法在子类中时即便是父类引用指向父类对象也会执行子类中的静态 代码块,子类中的其他则不执行
用例2(父类引用指向子类对象)测试父子类对象中属性方法的执行情况:
public class Test {
public static void main(String[] args) {
Parent parent = new Son();
parent.say();
System.out.println(parent.getA());
System.out.println(parent.b);
System.out.println(parent.c);
}
}
//测试结果,前面已经分析过一些,主要看后四项
parent static
Son static
Non-static block from Parent
Parent init constructor
Non-static block from Son
Son constructor
I am son
6
10
10
得出结论如下:
1、若子类覆盖了某方法,则父类引用调用子类重新定义的新方法
2、若子类未覆盖某方法,则父类引用调用父类本身的旧方法
3、若子类覆盖了某属性,但父类引用仍调用父类本身的旧属性
4、若子类未覆盖某属性,则父类引用调用父类本身的旧属性
5、父类引用不能访问子类新定义的方法
用例3(子类引用指向自身对象)测试父子类对象中属性方法的执行情况:
public class Test {
public static void main(String[] args) {
Son parent = new Son();
parent.say();
System.out.println(parent.getA());
System.out.println(parent.b);
System.out.println(parent.c);
System.out.println(parent.getH());
}
}
//执行结果
parent static
Son static
Non-static block from Parent
Parent init constructor
Non-static block from Son
Son constructor
I am son
6
20
10
3
得出结论如下:
1、若子类覆盖了某方法,则子类引用调用子类重新定义的新方法
2、若子类未覆盖某方法,则子类引用调用父类本身的旧方法
3、若子类覆盖了某属性,则子类引用调用子类重新定义的新属性
4、若子类未覆盖某属性,则子类引用调用父类本身的旧属性
5、子类引用可以访问子类新定义的方法