可以用构造器来进行初始化,但是无法阻止自动初始化的进行,因为自动初始化会在构造器被调用之前发生。因此,假如使用一下代码:
Public class Counter{
int I;
Counter(){i=7;}
}
那么i首先会被置为默认值0,然后再变成7。对于所有基本类型(都有初始值)和对象的引用(初始值是null),包括在定义时已经指定初始值的变量,这种情况都是成立的。
1. 初始化顺序
在类的内部,变量定义的先后顺序决定了初始化的顺序。需要注意的是,即使变量定义和方法定义混杂在一起(如非必要,这真是个糟糕的编程习惯,好在我有世界第一好用ide--IDEA),它们仍让会在任何方法(包括构造器)被调用之前得到初始化。
2.静态数据的初始化
无论创建多少个对象,静态数据都指占用一份存储区域。同样,《think in JAVA》上有一个很经典的例子!大早上coding这个,表示已经晕的不行不行的。
package com.tree.jvm;
/**
* Created by Administrator on 2016/12/7.
*/
class Bowl{
Bowl(int maker){
System.out.println("Bowl("+maker+")");
}
void f1(int maker){
System.out.println("f1("+maker+")");
}
}
class Table{
static Bowl bowl1 = new Bowl(1);
public Table() {
System.out.println("Table()");
bowl2.f1(1);
}
void f2(int maker){
System.out.println("f2("+maker+")");
}
static Bowl bowl2 = new Bowl(2);
}
class Cupboard{
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
public Cupboard() {
System.out.println("Cupboard()");
bowl4.f1(2);
}
void f3(int maker){
System.out.println("f3("+maker+")");
}
static Bowl bowl5 = new Bowl(5);
}
public class StaticInitialization {
public static void main(String[] args) {
System.out.println("createing new Cupboard() in main");
new Cupboard();
System.out.println("createing new Cupboard() in main again");
new Cupboard();
table.f2(1);
cupboard.f3(1);
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
}
Bowl类使得看到类的创建,而Table类和Cupboard类在它们的类定义中加入了Bowl类型的静态数据变量。Attention,Cupboard类先定义了一个Bowl类型的非静态数据成员(Bowl bowl3 = new Bowl(3))。
从输出结果中,可以得到以下信息:
一.程序首先对静态变量table进行初始化:
(1)首先初始化Table类中的静态变量bow1,bow2;
(2)这引发了Bowl类初始化,打印输出Bowl(1),Bowl(2);
(3)执行Table的构造器,打印输出Table(),和f1();
二.对静态变量cupboard进行初始化:
(1)首先初始化静态变量bowl4,bowl5;
(2)再初始化非静态变量bow3—注意此处不是按照定于顺序进行初始化,而是先静态后非静态;
(3)执行Cupboard的构造器,打印输出Cupboard()和f1(2);
三.执行main方法
由此可见,静态初始化只有在必要的时候才会进行。如果不创建Table对象,也不应用Table.bowl1和Table.bowl2,那么静态的Bowl bowl1和bowl2就永远不会被创建。只有在第一个Table对象被创建(或者第一次访问静态数据)的时候,它们才会被初始化。此后,静态对象不会再次被初始化。可以从上例看出, new了两次Cupboard
的静态数据是一样的。
初始化的顺序是先静态对象(如果它们尚未因前面的对象创建而被初始化),而后乃是非静态的对象。
从上例的输出结果中也可以看出这一点。要执行main()(静态方法),必须加载StaticInitialization类,乃后其静态域中的table和cupboard被初始化,这引发了它们对应的类也被加载,并且由于它们都包含静态的Bowl对象,因此Bowl随后也被加载。这样,在这个特殊的程序中所有的类在main()方法开始之前都被加载了。但是实际情况通常不是这样的。
总结一下类的创建过程,假设要创建一个类,姑且命名为Tree()吧:
1. 即使没有显示的使用static关键字,构造器实际上也是静态方法。因此,当首次创建类型为Tree的对象时(构造器可以看成静态方法),或者首次访问Tree的静态方法/静态域时,JAVA解释器必须查找其路径,以定位Tree.class文件。
2. 然后载入Tree.class(创建一个class对象),有关静态初始化的所有动作都会被执行。因此,静态初始化只在首次加载的时候进行一次。
3. 当用new Tree()创建对象的时候,首先会在堆内存上为Tree对象分配足够的内存空间。
4. 这块空间会被清楚,将Tree对象中的所有基本类型数据都设置为默认值。
5. 执行所有出现在字段定义处的初始化动作。
6. 执行构造器。(可能会涉及到很多动作,尤其是涉及到继承问题时)。