Java——初始化

初始化

1. 使用构造器

在Java中通过使用构造器,类的设计者可以确保每个对象都正确得到初始化。运行时刻可以调用方法和执行某些动作来确定初值。创建对象时,如果类具有构造器,Java会在用户具有使用对象的能力之前自动的调用相应构造器,确保初始化的进行。

“创建”和“初始化”是两个独立的概念,但在Java中创建和初始化捆绑在一起不能分离。

class Type{

int i;

Type(int i){

i=10;

f(i);

System.out.print(i); }

void f(int i){}

}

public class Main{

public static void main(String[] args){

Type t = new Type(10);  // 构造器没有任何返回的东西,但new表达式返回了一个对象的引用
}

}

但是,无法阻止自动个初始化的进行,它将在构造器被调用之前发生。例如上述Type类,i的值先初始化为0,然后是10。初始化的顺序决定于变量被定义的顺序。

 

静态数据的初始化

无论创建多少个对象,静态数据都只占用一份存储空间。

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);
}
public class JavaStaticInit {
    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();
}

输出为:
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)

从上面的输出可以看出,静态数据的初始化在必要时刻才进行,而且只初始化一次,以后不会再初始化。

当 拥有main方法的类JavaStaticInit被加载时,类里面的静态成员table 和cupboard 就会被初始化,new Table()导致Table类被加载,在Table类中又有bowl1和bowl2两个静态成员,会执行初始化这两个静态数据,这又导致Bowl类会被 加载,Bowl类中没有静态数据。然后调用Bowl类的构造方法创建对象Table.bowl1和Table.bowl2,所以先输出“Bowl(1)” 和“Bowl(2)”,然后Tbale类构造器被执行创建JavaStaticInit.table对象,打印“Table()”,构造器中 bowl2.f1(1)的调用打印“f1(1)”,此时JavaStaticInit.table对象初始化完毕,接着初始化 JavaStaticInit.cupboard对象,导致Cupboard类会被加载,Cupboard类在两个静态数据前面先定义了一个非静态数据 bowl3,但还是会在加载类的时候先初始化静态数据bowl4、bowl5,所以先打印“Bowl(4)”和“Bowl(5)”,接着会初始化 bowl3,打印“Bowl(3)”,然后是构造器被执行,打印“Cupboard()”“f1(2)”,cupboard对象初始化完毕。

然后执行main方法......

 

对象的创建过程(以Table为例)实际上可以总结为:

(1)构造器给出了类名,即使没有显示的使用关键字static,构造器实际上也是静态方法。因此当首次创建Type类的对象或者Type类的静态方法/静态域被访问时,Java解释器查找类路径定位Type.class文件。

(2)载入Type.class,所有的静态这时都会执行初始化,并且静态数据只在类首次加载时初始化一次,以后不会再执行初始化。

(3)当用new Type()创建对象时,为Type对象分配足够的存储空间。

(4)执行自动的清零动作,例如,int类型被初始化为0,引用类型被初始化为null。

(5)执行所有非静态数据成员的初始化。

(6)执行构造器初始化(会导致基类的构造器的初始化)。

 

显示静态初始化

Java可以把多个静态初始化动作组织成一个特殊的“静态块”:static{ //init... }

示例:

class Clazz{
    static String s1;
    static String s2 = "string2";
   
    // 静态字句
    static{
        System.out.println("static-block:"+s1);
        System.out.println("static-block:"+s2);
        s1="static_string1";
        s2 = "static_string2";
    }
   
    static void printString(){
        System.out.println("s1: "+s1);
        System.out.println("s2: "+s2);
    }
}
public class JavaStaticInitBlock {
    public static void main(String[] args) {
        Clazz.printString();
    }
}

输出:

static-block:null
static-block:string2
s1: static_string1
s2: static_string2

静态语句块也只执行一次。

 

看下一个例子:


public class JavaStaticInitBlock2 {
    static{
        System.out.println("Static Block");
    }
    static String s1;
    static String s2=f(2);
   
    static {
        System.out.println("static-block:"+s1);
        System.out.println("static-block:"+s2);
        s1="static_string1";
        s2="static_string2";
    }
   
    static String f(int i){
        System.out.println("static method f()");
        return "string"+i;
    }
   
    public static void main(String[] args) {
        System.out.println(JavaStaticInitBlock2.s1);
        System.out.println(JavaStaticInitBlock2.s2);
    }
}

输出:

Static Block
static method f()
static-block:null
static-block:string2
static_string1
static_string2

 

输出看出,static语句块和static域的初始化是按定义顺序进行。

 

非静态实例初始化

Java中有一种叫做实例初始化的类似语法,用来初始化每一个对象的非静态变量。语法格式为:要做的工作放在一对花括号中{ // init...  }。

例如:

class Mug {
    Mug(int maker){
        System.out.println("Mug("+maker+")");
    }
    void f(int maker){
        System.out.println("f("+maker+")");
    }
}
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 class JavaInstantiationBlock {
    public static void main(String[] args) {
        System.out.println("main started...");
        new Mugs();
        System.out.println("new Mugs() completed");
        new Mugs(1);
        System.out.println("new Mugs(1) completed");
    }
}

输出:
main started...
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs()
new Mugs() completed
Mug(1)
Mug(2)
mug1 & mug2 initialized
Mugs(int)
new Mugs(1) completed
这种语法对于支持匿名内部类是必须的,它也使你可以保证无论调用哪一个显示构造器,某些操作都会发生。输出可以看出实例初始化语句块在构造器之前执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值