在JAVA中,若某个主数据类型属于一个类成员,那么即使不显示初始化,也可以获得一个默认值。
如下表格:
主类型 默认值 Boolean false Char '\u0000' (null) byte (byte) 0 short (short) 0 int 0 long 0L float 0.0f double 0.0d
一旦将变量作为类成员使用,就要注意由Java分配的默认值,这样做的目的是为了保证主类型成员变量得到初始化,有效遏制编程错误。但是在“局部”变量中,则并不会按照上表所示进行分配默认值。例如:
import java.util.*;
public class Project1 {
public static void main(String[] args) {
// TODO Auto-generated method stub
class Dateonly{
int x;
float a;
void func(){
int x; //此处编译报错
System.out.println(x);
}
}
Dateonly d = new Dateonly();
d.func();
}
}
对于func函数中的“局部”变量x来说,此时x会得到一些随机值,不会自动初始化为0,我们必须在正式使用x前分配一个适当的值,如果忘记,编译器会报错,所以,在func函数中的x必须初始化。
对于主数据类型来说,类Dateonly中的x和a均会初始化为上表所示内容。
在C++中并不会得到编译器发出的警告,但JAVA中明确了这一错误。
在一个类中,初始化的顺序由变量在类中的顺序有关,即使变量定义分布在方法定义的中间,或者说在构建器内部或之间或外部或结尾,编译器都会在调用任何方法及构建器之前去初始化一遍每个变量。接下来看一段代码:
import java.util.*;
class Tag{
Tag(int marker){
System.out.println("Tag("+marker+")");
}
}
class Card{
Tag t1 = new Tag(1);
Card(){
System.out.println("Card()");
t3 = new Tag(33);
}
Tag t2 = new Tag(2);
void f(){
System.out.println("f()");
}
Tag t3 = new Tag(3);
}
public class Project9 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Card t =new Card();
t.f();
}
}
程序运行结果为:
根据结果可以看到,主函数在未调用构建器之前,变量仍会进行一次编译器默认的初始化,进行创建Card对象t时首先对变量进行一次初始化,再进行对象的创建,其中t3句柄初始化了两次,从表面上看这样的初始化效率低下,但却能够保证足够的安全性。
那么对于static静态数据的初始化问题来说,同样的事情仍然会发生,若是主数据类型,则初始化一个上述表格值;若指向的是一个对象的句柄,一般会得到“NULL”。若想在定义的同时进行初始化操作,由于static只有一个存储区域,无论创建多少个对象,都会遇到何时对其初始化的问题。下面给出一段代码:
import java.util.*;
class Bowl{
Bowl(int marker){
System.out.println("Bowl("+marker+")");
}
void f(int marker){
System.out.println("f("+marker+")");
}
}
class Table{
static Bowl b1 = new Bowl(1);
Table(){
System.out.println("Table()");
b2.f(1);
}
void f2(int marker){
System.out.println("f2("+marker+")");
}
static Bowl b2 = new Bowl(2);
}
class Cupboard{
Bowl b3 = new Bowl(3);
static Bowl b4 = new Bowl(4);
Cupboard(){
System.out.println("Cupboard()");
b4.f(2);
}
void f3(int marker){
System.out.println("f3("+marker+")");
}
static Bowl b5 = new Bowl(5);
}
public class Project10 {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Creating new Cupboard() in main");
new Cupboard();
t2.f2(1);
t3.f3(1);
}
static Table t2 = new Table();
static Cupboard t3 = new Cupboard();
}
此程序运行结果为:
可以看到的是,在主函数运行时期,首先进行static的初始化操作,创建Table对象t2时,先对Table中的两个static变量进行初始化,之后调用Table的构建器创建t2,值得注意的是在Cupboard对象t3创建过程中,先创建了一个非static的Bowl b3。static的初始化只有在必要的时候才会进行,如果不创建一个Table对象,而且永远不引用Table.b1或Table.b2,那么static Bowl b1和b2永远不会创建,然而在创建了第一个Table对象之后(或者发生第一次static访问的时候),它们才会创建,初始化的顺序是static对象,接着是非static对象。(这一点在运行结果中可以看出)
有的时候,static初始化工作还可以放到一个特殊的“static构建从句”中,也可以叫做静态块,类似于:
class Project{
static int i;
static {
i=4;
}
}
与其他static一样,此段代码只执行一次,下面给出一段程序:
import java.util.*;
class Cup{
Cup(int marker){
System.out.println("Cup("+marker+")");
}
void f(int marker){
System.out.println("f("+marker+")");
}
}
class Cups{
static Cup c1;
static Cup c2;
static{
c1 = new Cup(1);
c2 = new Cup(2);
}
Cups(){
System.out.println("Cups()");
}
}
public class ExplicitStatic {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Inside main()");
Cups.c1.f(99); //1
}
//static Cups x = new Cups(); //2
//static Cups y = new Cups(); //2
}
此段程序运行结果为:
若1,2两处均注释掉,static初始化进程永不发生,程序运行结果为:
进行如上操作的目的,就是为了验证之前提到的static初始化只会在必要的时候进行。。。
那么当内含继承关系时,对基类子对象的正确初始化也至关重要,JAVA会在构建器中调用基类的构建器来进行初始化,而基类构建器具有执行基类初始化所需的所有知识和能力。JAVA会在导出类的构建器中插入对基类构建器的调用,看如下代码段:
package access;
import java.util.*;
class Art{
Art(){
System.out.println("Art constructor");
}
}
class Drawing extends Art{
Drawing (){
System.out.println("Drawing constructor");
}
}
public class Cartoon extends Drawing{
public Cartoon(){
System.out.println("Cartoon constructor");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Cartoon x = new Cartoon();
System.out.println();
Drawing y = new Drawing();
System.out.println();
Art z = new Art();
}
}
此程序运行结果为:
从结果可以证明构建过程是从基类“向外”扩散的,基类在导出类构建器可以访问它之前就已经完成了初始化。
上例中的每个类均有默认的构建器,编译器无需考虑传递参数的问题,但是如果没有默认的构建器,或者想调用一个带有参数的基类构建器,就必须用“super”关键字显示调用,并配备相应的参数列表,看如下代码:
package access;
class Game {
Game(int i){
System.out.println("Game constructor");
}
}
class BoardGame extends Game{
BoardGame(int i){
super(i);
System.out.println("BoardGame constructor");
}
}
public class Chess extends BoardGame{
Chess(){
super(11);
System.out.println("Chess constructor");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Chess x = new Chess();
}
}
此程序运行结果为: