关于JAVA中初始化及默认值的细节问题

来源:互联网 发布:数字集成电路用啥软件 编辑:程序博客网 时间:2024/06/04 23:26

在JAVA中,若某个主数据类型属于一个类成员,那么即使不显示初始化,也可以获得一个默认值。

如下表格:

主类型默认值BooleanfalseChar'\u0000' (null)byte(byte) 0short(short) 0int 0long0Lfloat0.0fdouble0.0d

一旦将变量作为类成员使用,就要注意由Java分配的默认值,这样做的目的是为了保证主类型成员变量得到初始化,有效遏制编程错误。但是在“局部”变量中,则并不会按照上表所示进行分配默认值。例如:

import java.util.*;public class Project1 {public static void main(String[] args) {// TODO Auto-generated method stubclass 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 stubCard 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 stubSystem.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 stubSystem.out.println("Inside main()");Cups.c1.f(99);            //1}//static Cups x = new Cups();     //2//static Cups y = new Cups();     //2}
此段程序运行结果为:


若注释掉1,不注释掉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 stubCartoon 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 stubChess x = new Chess();}}
此程序运行结果为:




























原创粉丝点击