1.和c中不同的是,在c语言中允许
int i;
printf("%d",i++);
这样使用,尽管这样是不正确的,没有对i值进行初始化。
在Java中,会强制要求程序员为i赋一个值,这样会让程序员更容易找出程序中的错误。
2.但是并不是在所有情况下,java都会这样要求我们,java会为类的每个基础类型成员赋一个初始值。
新建这样一个测试类,然后在main中调用这个类中的方法,打印出所有未经初始化(这里指我们没有进行初始化)基础类型成员的值。
public class InitialValues {
boolean t;
char c;
byte b;
int i;
long l;
float f;
double d;
InitialValues initialValues;
public void printInitialValues(){
System.out.println("boolean "+t);
System.out.println("char [" +c+"]");
System.out.println("byte " +b);
System.out.println("int " +i);
System.out.println("long " +l);
System.out.println("float "+f);
System.out.println("double "+d);
System.out.println("InitialValues "+initialValues);
}
public class Main {
public static void main(String[] args) {
new InitialValues().printInitialValues();
}
}
可以得到这样的结果,可以看到并没有报错,而且都被赋予了初始值,在类中定义一个对象引用,如果不将它初始化,此引用就会获得一个null值:
boolean false
char [ ]
byte 0
int 0
long 0
float 0.0
double 0.0
InitialValues null
3.初始化的顺序
在java类中,尽管让变量定义散布在方法定义之间,变量定义还是会优先于方法定义(包括构造器方法)被执行
public class Window {
Window(int marker){
System.out.println("Window(" + marker +")");
}
public 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);
}
public class Main {
public static void main(String[] args) {
new House().f();
}
}
结果:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
在House类中,我们让Window对象的定义散布在各处,证明他们全都会在构造器或其他方法调用之前得到初始化。
4.静态数据的初始化
无论创建多少个对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量,因此它只能作用于域。
public class Bowl {
Bowl(int marker){
System.out.println("Bowl(" + marker +")");
}
void f1(int marker){
System.out.println("f1("+marker+")");
}
}
public class Table {
static Bowl bowl = new Bowl(1);
Table(){
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker){
System.out.println("f2(" + marker + ")");
}
Bowl bowl2 = new Bowl(2);
}
public class Cupboard {
Bowl bow3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard(){
System.out.println("Cupboard()");
bowl4.f1(2);
}
void f3(int marker){
System.out.println("f3(" + marker + ")");
}
static Bowl bowl5 = new Bowl(5);
}
public class Main {
public static void main(String[] args) {
// write your code here
// new InitialValues().printInitialValues();
// new House().f();
System.out.println("Creating new Cupboard() in main");
new Cupboard();
System.out.println("Creating new Cupboard() in main");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
}
结果:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
静态初始化只有在必要的时刻才会进行,如果不创建Table 对象,也不引用Table.b1或Table.b2,那么静态的Bow1 b1和b2永远都不会被创建。只有在第一个Table对象被创建(或者第一次访问静态数据)的时候,它们才会被初始化。此后,静态对象不会再次被初始化。
初始化的顺序是先静态对象,而后是“非静态”对象,在结果中标紫的地方可以看到。
总结一下对象的创建过程,假设有个名为Dog的类:
1.即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成静态方法),或者Dog类的静态方法/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件。
2.然后载入Dog.class,有关静态初始化的所有动作都会执行。因此,静态初始化只在Class对象首次加载的时候进行一次。
3.当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间。
4.这块存储空间会被清零,这就自动地将Dog对象中的所有基本类型数据都设置成了默认值。
5.执行所有出现于字段定义处的初始化动作。
6.执行构造器。