可以用构造器来进行初始化,在运行时刻,可以调用方法或执行某些动作来确定初值,但要牢记:无法阻止自动初始化的进行,它将在构造器被调用之前发生。
// 构造器初始化
class Counter{
int i;
Counter(){
i = 7;
}
}
i 首先会被置为0,然后变成7;对于所有基本类型和对象引用,包括在定义时已经指定初值的变量,这种情况都是成立的。因此,编译器不会强制你一定要在构造器的某个地方或在使用之前对元素进行初始化,因为初始化早已得到了保证
初始化顺序
// 初始化顺序
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);
public static void main(String[] args) {
House h = new House();
h.f();
}
}
// Output
Window1
Window2
Window3
House()
Window33
f()
在House类中,几个Window对象的定义穿插在方法各处,但运行结果表示所有的变量都在调用构造器和其他方法之间得到初始化
静态数据的初始化
无论创建多少个对象,静态数据都只占用一份存储区域。static关键字不能应用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且没有对它进行初始化,那么它就会获得基本类型的标准初值;如果它是一个对象引用,那么它的默认初始化值就是null。 如果在定义处进行初始化,采取的方法与非静态数据没什么不同:
class Bowl{
Bowl(int marker){
System.out.println("Bowl " + marker);
}
void f1(int marker){
System.out.println("f1 " + marker);
}
}
class Table{
static Bowl bowl1 = new Bowl(1);
Table(){
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int marker){
System.out.println("f2 " + marker);
}
static Bowl bowl2 = new Bowl(2);
}
class Cupboard{
Bowl bowl3 = 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);
}
class StaticInitialization{
public static void main(String[] args) {
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();
}
由输出可见,静态初始化只有在必要时刻才会进行。如果不创建Table对象,也不引用Table.b1或Table.b2,那么静态的Bowl b1和b2永远都不会被创建。只有在第一个Table对象被创建(或第一次访问静态数据)的事哦呼,它们才会被初始化。并且,此后静态对象不会再次被初始化
初始化的顺序是先静态对象(如果它们尚未因对象创建而被初始化),而后“非静态”对象,从输出结果中可以观察到这一点。
对象的创建过程
假设有个名为Dog的类:
1)即使没有显示地使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Dog的对象时(构造器可以看成静态方法),或者Dog类的静态/静态域首次被访问时,Java解释器必须查找类路径,以定位Dog.class文件
2)然后载入Dog.class,有关静态初始化的所有动作都会执行,因此,静态初始化只在Class对象首次加载的时候进行一次
3)当用new Dog()创建对象的时候,首先将在堆上为Dog对象分配足够的存储空间
4)这块存储空间会被清零,这将自动地将Dog对象中的所有基本类型都设置为默认值(对数字来说就是0,对布尔型和字符型也相同),而引用则被设置为null
5)执行所有出现于字段定义处的初始化动作
6)执行构造器
显示的静态初始化
Java允许将多个静态初始化组织成一个特殊“静态子句”(有时也叫做“静态块”)
public class Spoon{
static int i;
static {
i = 47;
}
}
与其他静态初始化动作一样,这段代码仅执行一次:当首次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员时(即使从未发生过那个类的对象)
非静态实例初始化
Java中也有被称为初始化的类似语法,用来初始化每一个对象的非静态变量。
class Mug{
Mug(int m){
System.out.println("Mug " + m);
}
void f(int m){
System.out.println("f " + m);
}
}
class Mugs{
Mug mug1;
Mug mug2;
{
mug1 = new Mug(1);
mug2 = new Mug(2);
System.out.println("Mug1 & Mug2 initialized");
}
Mugs(){
System.out.println("Mugs");
}
Mugs(int i){
System.out.println("Mugs(int)");
}
public static void main(String[] args) {
System.out.println("Inside main()");
new Mugs();
System.out.println("new Mugs() completed");
new Mugs(1);
System.out.println("new Mugs(1) completed");
}
}
// Output
Inside main()
Mug 1
Mug 2
Mug1 & Mug2 initialized
Mugs
new Mugs() completed
Mug 1
Mug 2
Mug1 & Mug2 initialized
Mugs(int)
new Mugs(1) completed
上面的代码看起来它与静态初始化子句一摸一样,只是少了static关键字。这种语法对于支持“匿名内部类”的初始化是必须的,但是它也使得你可以保证无论调用了哪个显式构造器,某些操作都会发生。从输出可以看到实例化子句是在两个构造器之前执行的