成员初始化
对于方法的局部变量,假如没有初始化(赋值)java编译错误
对于类的数据成员(字段)的基本类型,java自动初始化
public class EurekaApplication {
int i;
long j;
double k;
EurekaApplication m;
public static void main(String[] args) {
new EurekaApplication().inttes();
}
public void inttes(){
System.out.print(i);
System.out.print(j);
System.out.print(k);
System.out.print(m);
}
}
Main是程序的启动入口,而且是静态的 所以不能直接调用非静态方法inttes,因为静态方法和成员属于类,非静态方法和成员属于对象,要调用非静态的必须通过其对象。
Mian方法是入口,所以当其运行时,EurekaApplication 类的其他部分还只是定义,并没有参与运行。如果你要在main方法里面调用inttes(),就要通过inttes()所在的类的对象。
结果0 0 0.0 null
所以说成员变量,java自动初始化 对象(引用)类型默认为 null
指定初始化
定义类成员变量的地方为其赋值 例如 int i=999;
同样的方法为非基本类型赋值
通过方法赋值也可以
int i=f();
int f(){
return 100;
}
构造器初始化
class Counter{
int i;
Counter(){
i=7;
}
}
无法阻止自动初始化的进行,他将在构造器被调用之前发生。首先会被置0,然后变成7.
对于所有基本类型和对象引用。包括在定义时已经指定初值的变量,这种情况都是成立的。
初始化的顺序
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
House h = new House();
h.f();
}
}
class Window {
Window(int marker) {
System.out.println("Window("+marker+")");
}
}
class House{
Window w1 = new Window(1);
House() {
System.out.println("House()");
w3 = new Window(33);
}
Window w2 = new Window(2);
void f() {
System.out.println("f()");
}
Window w3 = new Window(3);
}
测试结果:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,它们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
W3这个引用会被初始化两次:一次在调用构造器前,一次在调用期间(第一次引用的对象将被丢弃,并作为垃圾回收)
这样做的主要目的“使初始化得到保证” 。
静态数据的初始化
无论创建多少个对象,静态数据只占用一份存储区域。Static关键字不能应用于局部变量,方法内,语句块内,他只能作用于域。
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
System.out.println("---------");
new Cuboard();
System.out.println("---------");
new Cuboard();
table.f2(1);
cuboard.f3(1);
}
static Table table = new Table();
static Cuboard cuboard = new Cuboard();
}
class Bow1{
Bow1(int marker) {
System.out.println("Bowl("+marker+")");
}
void f1(int marker) {
System.out.println("f1("+marker+")");
}
}
class Table {
static Bow1 bowl1 = new Bow1(1);
Table(){
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker) {
System.out.println("f2("+marker+")");
}
static Bow1 bowl2 = new Bow1(2);
}
class Cuboard {
Bow1 bowl3 = new Bow1(3);
static Bow1 bowl4 = new Bow1(4);
Cuboard() {
System.out.println("Cuboard()");
bowl4.f1(2);
}
void f3(int marker) {
System.out.println("f3("+marker+")");
}
static Bow1 bowl5 = new Bow1(5);
}
测试结果:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cuboard()
f1(2)
---------
Bowl(3)
Cuboard()
f1(2)
---------
Bowl(3)
Cuboard()
f1(2)
f2(1)
f3(1)
解析当static Table table = new Table();
执行时 Bowl(1) Bowl(2) Table() f1(1)
static Cuboard cuboard = new Cuboard();
Bowl(4) Bowl(5) Bowl(3) Cuboard() f1(2)
当有静态成员变量时,先执行,后执行非静态成员变量
new Cuboard();
Bowl(3) Cuboard() f1(2)
当创建对象时 只执行非静态成员变量 和构造函数里的方法
f2(1) f3(1)
静态初始化只有在必要时刻才会进行。如果不创建Table对象,也不引用Table.b1,那么对静态的Bowl b1永远都不会创建。只有第一个Table对象被创建的时候,他们才会被初始化。此后静态对象不会再次被初始化。
初始化的顺序是先静态对象,而后是非静态对象。要执行main()(静态方法),必须加载EurekaApplication类,然后其静态域table和cubcobard被初始化。
显式的静态初始化
Static { }
上面的代码看起来像个方法。当它实际上只是一段跟在static关键字后面的代码。与其他静态初始化动作一样。这段代码仅执行一次。当首次生成这个类的对象时,
或者首次访问属于哪个类的静态数据成员时(即便从未有生成过哪个类的对象,非静态的执行)
注释2去掉也可执行同样语句,一行或两行不影响执行效果,静态初始化只执行一次
非静态实例初始化
注意区分{ } 代码块的位置
假如位于直接位于类里边 就属于构造代码块,new 对象一次执行一次
假如位于直接位于方法里面,就属于普通代码块,按顺序执行
这种语法对于支持“匿名内部类”的初始化时必须的,使得你可以保证无论调用了哪个显式构造器,这些操作都会发生。 实例初始化(构造代码块)在构造器执行之前执行。
执行顺序 静态代码块 构造代码块 构造器