七、Java 如何保证所有变量在使用前都初始化?

局部变量与成员变量的初始化

对于方法体内的局部变量,Java 用一个编译时错误来提醒初始化:

void fun(){
	int x;
	x++;//报错:i not initialized
}

对于类中的成员变量,在声明类的对象时,每个基本类型的变量都会有一个初始值。

public class initClass{
	boolean bool;
	char c;
	byte b;
	short s;
	int i;
	long l;
	float f;
	double d;
	initClass ref;

	void printInitValues(){
		System.out.println("boolean:"+bool);
		System.out.println("char:"+"["+c+"]");
		System.out.println("byte:"+b);
		System.out.println("short:"+s);
		System.out.println("int:"+i);
		System.out.println("long:"+l);
		System.out.println("float:"+f);
		System.out.println("double:"+d);
		System.out.println("initClass:"+ref);
	}	
}
/*Output: boolean:false char:[] byte:0 short:0 int:0 long:0 float:0.0 double:0.0 initClass:null */

对于成员变量,也可以指定初始化值:

public class initClass{
	boolean bool = true;
	char c = 'a';
	byte b = 47;
	short s = 0xff;
	int i = 888;
	long l = 1;
	float f = 3.14f;
	double d = 3.1415926;

	String str = new String("abcfdk");//非基本类型可以用new初始化
	
	int x = fun();//调用函数初始化

	int fun(){
		return 11;
	}
}

用构造方法初始化成员变量

使用构造方法,可以在运行时刻,创建对象时利用构造方法初始化成员变量,非常灵活。

需要注意的是,在构造方法执行前,依旧会先执行自动初始化变量的操作,即下面代码中的int i,首先i初始化为0,接着被构造方法初始化为20

public class init {
    boolean bool;
    char c;
    byte b;
    short s;
    int i;
    long l;
    float f;
    double d;
    init ref;

    public init() {
        this.bool = true;
        this.c = 'x';
        this.b = 1;
        this.s = 3;
        this.i = 20;
        this.l = 999;
        this.f = 5.6f;
        this.d = 7.28374;
        this.ref = new init();
    }
}

静态数据的初始化

类中的静态数据,只有在被需要时,才会主动初始化,并且在整个运行过程中只初始化一次。

public class init {
    int x;
    static {//静态初始化代码块
		x = 10;
	}
    void print(){
        System.out.println(x);
        x++;
    }
    public static void main(String [] args){
        init u = new init();
        u.print();//x = 10

        init x = new init();
        x.print();//x = 11
    }
}

初始化顺序是:先静态变量(是第一次初始化情况下),后非静态变量。

对象创建的过程:

  1. 一个类中除了显示定义的静态域,还有构造方法也是静态方法,当首次创建对象或者首次访问类中的静态域时,Java 解释器必须查找类路径。定位对应的.class文件。
  2. 然后加载.class,执行静态初始化的所有动作。因此静态初始化只在加载.class时进行一次。
  3. new创建对象时,首先在堆上分配足够的空间。
  4. 清空堆上的存储空间,并将类中成员变量初始化为默认值
  5. 执行字段定义时的初始化动作
  6. 执行构造方法。

数组初始化

数组是一种将相同类型的,用一个标识符封装到一起的一个对象序列或者基本类型数据序列

无论是对象数组还是基本类型数组,都有一个固有成员:length,可以获得数组内元素的个数。

public static void main(String [] args){
	int [] a = {1,2,3,4};//存储空间分配由编译器负责,等价于new

	int [] a2;
	a2 = a;//这里只是将a2也指向了a所指向的内存块
}

通过new创建指定大小的数组

int [] a = new int[10];//此时,数组内元素均默认初始化为0

对象数组即便使用了new创建后,依然无法直接使用,因为创建的仅仅是一个对象的引用数组,数组内每个元素并没有指向具体对象,需要赋值具体对象后才能使用。

Integer [] b = {new Integer(1),new Integer(10),3,5};//对象数组初始化
Integer [] c = new Integer[]{new Integer(10),5,8};
Integer [] a = new Integer[10];//创建10个Integer对象的引用数组
for(int i=0; i<a.length; i++){
	a[i] = 0;//自动装箱,赋值具体Integer对象。
}

可变参数列表

int print(int... tem){
	for(int i : tem){
		System.out.println(i);
	}
}

可变参数的出现,可以在调用方法时直接传递多个相同类型的参数,不用再封装到数组里,编译器会将这些参数以数组的形式传递到方法内。若没有传递参数,则传递到方法的数组长度为 0。

可变参数列表在重载函数中的问题

void f(int... i){...}
void f(Long... l){...}

上述代码中,当调用时有参数,则编译器能够找到最匹配的一个方法取执行,但是如果像这样没有参数调用时:f();,编译器该如何选择呢?

对于这个问题,实际上并不应该在重载函数中使用多个可变参数,解决方案有:

  1. 尽量不使用可变参数
  2. 增加其他非可变参数区分

你可能感兴趣的:(《Java编程思想》新知)