一,成员变量(实例变量和类变量)初始化方式(5种)
1、成员变量有默认值---具体略
2、显式赋值
public class Student{
public static final String COUNTRY = "中华人民共和国";
private static String school = "尚硅谷";
private String name;
private char gender = '男';
}
//显式赋值,一般都是赋常量值
3、代码块
如果成员变量想要初始化的值不是一个硬编码的常量值,而是需要通过复杂的计算或读取文件、或读取运行环境信息等方式才能获取的一些值(就是要写多行代码),该怎么办呢?
静态初始化块:为静态变量初始化
【修饰符】 class 类名{
static{
静态初始化
}
}
静态初始化块:在类初始化时由类加载器调用执行,每一个类的静态初始化只会执行一次,早于实例对象的创建。
实例初始化:为实例变量初始化
【修饰符】 class 类名{
{
实例初始化块
}
}
实例初始化块:每次new实例对象时自动执行,每new一个对象,执行一次。
4、构造器
我们发现,显式赋值和实例初始化块为每一个实例对象的实例变量初始化的都是相同的值,那么我们如果想要不同的实例对象初始化为不同的值,怎么办呢?此时我们可以考虑使用构造器,在new对象时由对象的创建者决定为当前对象的实例变量赋什么值。
注意:构造器只为实例变量初始化,不为静态类变量初始化
为实例变量初始化,再new对象时由对象的创建者决定为当前对象的实例变量赋什么值。
二,类初始化
1、类初始化的目的:为类中的静态变量进行赋值。
2、实际上,类初始化的过程时在调用一个<clinit>()方法,而这个方法是编译器自动生成的。编译器会将如下两部分的所有代码,按顺序合并到类初始化<clinit>()方法体中。
(1)静态类成员变量的显式赋值语句
(2)静态代码块中的语句
3、整个类初始化只会进行一次,如果子类初始化时,发现父类没有初始化,那么会先初始化父类。
public class Test{
public static void main(String[] args){
Son.test();
System.out.println("-----------------------------");
Son.test();
}
}
class Father{
private static int a = getNumber();
static{
System.out.println("Father(1)");
}
private static int b = getNumber();
static{
System.out.println("Father(2)");
}
public static int getNumber(){
System.out.println("Father:getNumber()");
return 1;
}
}
class Son extends Father{
private static int a = getNumber();
static{
System.out.println("Son(1)");
}
private static int b = getNumber();
static{
System.out.println("Son(2)");
}
public static int getNumber(){
System.out.println("Son:getNumber()");
return 1;
}
public static void test(){
System.out.println("Son:test()");
}
}
/*
运行结果:
Father:getNumber()
Father(1)
Father:getNumber()
Father(2)
Son:getNumber()
Son(1)
Son:getNumber()
Son(2)
Son:test()
-----------------------------
Son:test()
*/
结论:
每一个类都有一个类初始化方法<clinit>()方法,然后子类初始化时,如果发现父类加载和没有初始化,会先加载和初始化父类,然后再加载和初始化子类。一个类,只会初始化一次。
三,对象/实例初始化
1、实例初始化的目的:为类中非静态成员变量赋值
2、实际上我们编写的代码在编译时,会自动处理代码,整理出一个<clinit>()的类初始化方法,还会整理出一个或多个的<init>(...)实例初始化方法。一个类有几个实例初始化方法,由这个类就有几个构造器决定。
实例初始化方法的方法体,由四部分构成:
(1)super()或super(实参列表) 这里选择哪个,看原来构造器首行是哪句,没写,默认就是super()
(2)非静态实例变量的显示赋值语句
(3)非静态代码块
(4)对应构造器中的代码
特别说明:其中(2)和(3)是按顺序合并的,(1)一定在最前面(4)一定在最后面
3、执行特点:
-
创建对象时,才会执行,
-
调用哪个构造器,就是指定它对应的实例初始化方法
-
创建子类对象时,父类对应的实例初始化会被先执行,执行父类哪个实例初始化方法,看用super()还是super(实参列表)
四,类初始化与实例初始化的关系
1,类初始化肯定优先于实例初始化。
2,类初始化只做一次。实例初始化是每次创建对象都要进行。