对于方法体内的局部变量,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
}
}
初始化顺序是:先静态变量(是第一次初始化情况下),后非静态变量。
对象创建的过程:
.class
文件。.class
,执行静态初始化的所有动作。因此静态初始化只在加载.class
时进行一次。new
创建对象时,首先在堆上分配足够的空间。数组是一种将相同类型的,用一个标识符封装到一起的一个对象序列或者基本类型数据序列。
无论是对象数组还是基本类型数组,都有一个固有成员: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();
,编译器该如何选择呢?
对于这个问题,实际上并不应该在重载函数中使用多个可变参数,解决方案有: