一、 父类的初始化
子类(派生类)创建一个对象时,就包含了对父类(基类)对象的创建,从外部看,父类的对象就已经被封装到子类的对象中。因此,父类能够正确的初始化,通过子类在创建子类对象,调用子类构造方法时,java编译器会自动对父类构造方法的调用。例如:
1、无参构造方法的调用
class A {
A(){
System.out.println("A.A()");
}
}
class B extends A{
B(){
System.out.println("B.B()");
}
}
public class C extends B{
C() {
System.out.println("C.C()");
}
public static void main(String[] args) {
C c = new C();
}
}
结果:
A.A()
B.B()
C.C()
Note:
(1)、注意调用的顺序,根父类最先调用,其次才是它的子类。
(2)、即使子类C没有创建无参构造方法,编译器也会默认生成C类的构造方法,并完成对A类、B类构造方法的调用。
2、有参构造方法的调用
class A {
A(int i){
System.out.println("A.A()");
}
}
class B extends A{
B(int i){
super(i); //如果此处没有对父类的显示调用,就会提示出错:Implicit super constructor A() is undefined. Must explicitly invoke another constructor
System.out.println("B.B()");
}
}
public class C extends B{
C() {
super(1); //同理,如果没有显示调用父类,提示:Implicit super constructor B() is undefined. Must explicitly invoke another constructor
System.out.println("C.C()");
}
public static void main(String[] args) {
C c = new C();
}
}
结果:
A.A()
B.B()
C.C()
Note:对有参构造方法的调用时,必须通过super()显示的调用父类构造方法。
二、上溯造型(upcasting)
上溯造型:源于继承关系图,基类在顶部,派生类向下发展。它是一种安全的类型转换:从派生类到基类的转变。一个方法的参数是基类句柄,若派生类对象调用此方法时的参数为派生类句柄,则传入的参数自动转化为基类句柄,并执行方法体。但是,如果该方法体中有覆盖,则不会出现向基类的转变。code:
class Animal{
public void speak() {
System.out.println("Animal.speak()");
}
// public static void upcasting(Animal animal) { //该方法也可以加到基类,效果一样
// animal.speak();
// }
}
class Dog extends Animal{
public void eat() {
System.out.println("Dog.eat()");
}
// public void speak() { //若子类重写该方法,则不会出现类型的转变:结果为:Animal.speak()
// System.out.println("Dog.speak()"); Dog.speak()
// } Dog.speak()
}
public class Test {
public static void upcasting(Animal animal) {
animal.speak();
}
public static void main(String[] args) {
Animal animal = new Animal();
upcasting(animal);
Dog dog1 = new Dog();
upcasting(dog1);
Animal dog2 = new Dog();
upcasting(dog2);
}
}
结果:
Animal.speak()
Animal.speak()
Animal.speak()
Note:上溯造型可以理解为:派生类通过继承后本身就包含了基类的所有元素,也属于基类的一种,可以直接访问从基类继承的现有成员,但是属于派生类特有的方法却不能通得到转变。
三、继承的初始化
一个继承类的初始化顺序:
1、首先,将继承类的父类、上一级父类(如果有的话)等依次装载,最后是继承类,这个过程中,执行的是根父类static成员的初始化,然后是下一级的static成员初始化,以此类推,最后是继承类的static成员。
2、所有相关类装载完后,根据创建的继承类对象,首先将基本数据类型设为默认值,对象句柄设为null,然后调用根父类的构造方法完成初始化,其次是下一级,以此类推,最后是继承类的构造方法调用。
3、构造方法调用完后,然后按照程序中本来的顺序继续执行初始化。
for example:
class Insect {
int i = 9;
int j;
Insect() {
prt("i = " + i + ", j = " + j);
j = 39;
}
static int x1 =
prt("static Insect.x1 initialized");
static int prt(String s) {
System.out.println(s);
return 47;
}
}
public class Beetle extends Insect {
int k = prt("Beetle.k initialized");
Beetle() {
prt("k = " + k);
prt("j = " + j);
}
static int x2 =
prt("static Beetle.x2 initialized");
static int prt(String s) {
System.out.println(s);
return 63;
}
public static void main(String[] args) {
prt("Beetle constructor");
Beetle b = new Beetle();
}
}
结果:
static Insect.x1 initialized
static Beetle.x2 initialized
Beetle constructor
i = 9, j = 0
Beetle.k initialized
k = 63
j = 39