1、类的成员变量、静态代码块、构造代码块、局部代码块、构造方法、成员方法的初始化过程
静态代码块是在类中方法外成员位置出现,用了static修饰;一般用于给类进行初始化。静态代码块在这个类第一次被调用或实例化的时候就会被执行。 静态代码块只会执行一次,一般会用来初始化一些值,并且在所有对象中全局共享。构造代码块在类中方法外成员位置出现;可以把多个构造方法*同的代码放到一起,每次调用构造都执行,并且在构造方法前执行,对对象进行初始化。局部代码块在方法中出现,局部位置;限定变量的生命周期,及早释放,提高内存利用率。
初始化过程:静态代码块(只执行一次)->构造代码块(每次调用构造方法都执行)->构造方法。执行顺序与代码块所在的具体位置无关。
局部代码块的初始化顺序由具体位置决定。
class Parent{
static{
int a = 1000;
System.out.println("静态代码块1:"+a);
}
{
int x = 100;
System.out.println("构造代码块1:"+x);
}
public Parent(){
System.out.println("构造函数1");
}
public Parent(int a){
System.out.println("构造函数2:"+a);
}
{
int y = 200;
System.out.println("构造代码块2:"+y);
}
static{
int b = 2000;
System.out.println("静态代码块2:"+b);
}
}
public class test{
public static void main(String[] args){
{
int x = 10;
System.out.println("局部代码块1:"+x);
}
System.out.println("演示1================");
Parent p1 = new Parent();
System.out.println("演示2================");
Parent p2 = new Parent();
System.out.println("演示3================");
Parent p3 = new Parent(1);
{
int y = 20;
System.out.println("局部代码块2:"+y);
}
}
}
运行结果:
局部代码块1:10
演示1============
静态代码块1:1000
静态代码块2:2000
构造代码块1:100
构造代码块2:200
构造函数1
演示2============
构造代码块1:100
构造代码块2:200
构造函数1
演示3============
构造代码块1:100
构造代码块2:200
构造函数2:1
局部代码块2:20
这里没有将成员变量和成员方法加入分析,但是我们可以知道,静态代码块在类加载的时候就已经初始化了,而成员变量是要在创建对象的时候才会根据构造方法进行分配内存,初始化赋值,所以如果你在静态代码块中打印成员变量或者成员变量赋值的话就会显示出错,显示要将变量类型改为static,而在构造代码块和构造方法中都能正常使用。
初始化过程:静态代码块(只执行一次)->成员变量(每次创建对象都会初始化赋值)->构造代码块(每次调用构造方法都执行)->构造方法(每次创建对象都会调用相匹配的构造方法)->成员方法(对象调用的时候运行)。
2、有继承关系的父类和子类的成员变量、构造方法、成员方法的初始化过程
在创建子类对象的时候会去调用子类的构造方法,其实子类的构造方法的第一条执行语句是super();即会自动去调用父类的无参构造方法,也就是说会自动去检测子类所继承的父类,并对父类的成员变量进行初始化操作。初始化完父类的成员变量、构造方法后,就初始化子类的成员变量和构造方法。因为子类会继承父类的非私有成员变量和成员方法(这里我把成员变量和成员方法都定义为默认访问权限),所以子类中如果定义了相同的成员变量,在初始化的时候就会被覆盖,而成员方法在调用的时候如果父类有子类没有,就执行父类的方法,如果父类没有子类有就执行子类的方法,如果父类有子类也有的话,那子类的成员方法就是复写了父类的成员方法,那最终执行就是子类的成员方法。
初始化过程:父类的成员变量->父类构造方法->子类成员变量->子类构造方法->父类/子类成员方法。
class Parent{
int age = 40;
String name = "Parent";
int num = 321;
public Parent(){
System.out.println("Parent构造函数");
System.out.println("Name:"+name+";Age:"+age+";Num:"+num);
show(); //在执行这句的时候因为子类覆盖了父类的show,所以执行的是子类的show();
}
public void show(){
System.out.println("I am Parent");
}
public void play(){
System.out.println("Parent Play");
}
}
class Child extends Parent{
int age = 15;
String name = "Child";
public Child(){
//第一步:super();执行父类
//第二步:显示初始化
//第三步:非静态构造代码块初始化(如果有的话)
System.out.println("Child构造函数,");
System.out.println("Name:"+name+";Age:"+age+";Num:"+num);
}
public void show(){
System.out.println("I am Child");
}
public void study(){
System.out.println("Child study");
}
}
public class test{
public static void main(String[] args){
Child child = new Child();
child.show();
child.play();
child.study();
}
}
运行结果:
Parent构造函
Name:Parent;
I am Child
Child构造函数
Name:Child;A
I am Child
Parent Play
Child study
3、有继承关系的父类和子类的成员变量、静态代码块、构造代码块、构造方法,成员方法的初始化过程
因为如果有继承关系的子类和父类,在创建子类对象的时候会自动的去调用父类的构造方法,对父类的数据进行初始化。但是如果父类和子类都有静态代码块的话,那会先执行父类的静态代码块,接着执行子类的静态代码块,因为静态代码块不需要创建对象才能执行,所以在加载类的时候首先运行静态代码块,然后接着运行父类的构造代码块和父类的构造方法,最后才是运行子类的构造代码块和子类的构造方法。
初始化过程:父类静态代码块->子类静态代码块->父类构造代码块->父类构造方法->子类构造代码块->子类构造方法
class Parent{
static
{
System.out.println("Parent静态代码块");
}
{
System.out.println("Parent构造代码块");
}
public Parent(){
System.out.println("Parent构造函数");
}
}
class Child extends Parent{
static
{
System.out.println("Child静态代码块");
}
{
System.out.println("Child构造代码块");
}
public Child(){
//第一步:super();执行父类
//第二步:显示初始化
//第三步:非静态构造代码块初始化(如果有的话)
System.out.println("Child构造函数,");
}
}
public class test{
public static void main(String[] args){
Child child = new Child();
System.out.println("===================");
Child child2 = new Child();
}
}
运行结果:
Parent静态代码块
Child静态代码块
Parent构造代码块
Parent构造函数
Child构造代码块
Child构造函数,
=============-
Parent构造代码块
Parent构造函数
Child构造代码块
Child构造函数,