对于方法的局部变量,java以编译时错误的形式来保证,所以如果写成:
void f(){
int i;
i++; //Error.. i not initialized
}
会得到一条错误信息,告诉你i 可能尚未初始化。当然,编译器也可以为i 赋一个默认值,但是为初始化的局部变量更有可能是程序员的疏忽,所以采用默认值反而会掩盖这种失误。因此强制程序员提供一个初始值。
对于类的数据成员(字段):若将基本类型(主类型)设为一个类的数据成员,情况就会变得稍微有些不同。由于任何方法都可以初始化或使用那个数据,所以在正式使用数据前,若还是强迫程序员将其初始化成一个适当的值,就可能不是一种实际的做法。然而,若为其赋予一个垃圾值,同样是非常不安全的。因此,一个类的所有基本类型数据成员都会保证获得一个初始值。
每个基本类型会有一个初始值,如果定义一个引用类型没有初始化,此引用会获得一个特殊值null。
构造器初始化:无法阻止自动初始化的进行,自动初始化在构造器调用之前发生。
public class Counter{
int i;
Counter(){i=7;}
}
i 首先被置为0 ,然后变成7,对于所有的基本类型和引用类型都是成立的。
初始化顺序:
在类的内部,变量定义的先后顺序决定了初始化的顺序。即使变量定义散布于方法定义之间,他们仍旧会在任何方法(包括构造器)被调用之前得到初始化。
package com.test.mianshi;
class Tag {
Tag(
int marker) {
System.out.println(
"Tag(" + marker +
")");
}
}
class Card {
Tag t1 =
new Tag(1);
// Before constructor
Card() {
// Indicate we're in the constructor:
System.out.println(
"Card()");
t3 =
new Tag(33);
// Re-initialize t3
}
Tag t2 =
new Tag(2);
// After constructor
void f() {
System.out.println(
"f()");
}
Tag t3 =
new Tag(3);
// At end
}
public
class OrderOfInitialization {
public
static
void main(String[] args) {
Card t =
new Card();
t.f();
// Shows that construction is done
}
}
// /:~
在Card中,Tag对象的定义故意到处散布,以证明它们全都会在构建器进入或者发生其他任何事情之前得到初始化。除此之外,t3在构建器内部得到了重新初始化。它的输入结果如下:
Tag(1)
Tag(2)
Tag(3)
Card()
Tag(33)
f()
2. 静态数据的初始化
若数据是静态的(static),那么同样的事情就会发生;如果它属于一个基本类型(主类型),而且未对其初始化,就会自动获得自己的标准基本类型初始值;如果它是指向一个对象的句柄,那么除非新建一个对象,并将句柄同它连接起来,否则就会得到一个空值(NULL)。
如果想在定义的同时进行初始化,采取的方法与非静态值表面看起来是相同的。但由于static值只有一个存储区域,所以无论创建多少个对象,都必然会遇到何时对那个存储区域进行初始化的问题。下面这个例子可将这个问题说更清楚一些:
package com.test.mianshi;
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);
static {
System.out.println(
"Cupboard");
}
Cupboard() {
System.out.println(
"Cupboard()");
b4.f(2);
}
{
System.out.println(
"Cupboard 构造块");
}
void f3(
int marker) {
System.out.println(
"f3(" + marker +
")");
}
static Bowl b5 =
new Bowl(5);
}
public
class StaticInitialization {
public
static
void main(String[] args) {
System.out.println(
"Creating new);
new Cupboard();
System.out.println(
"Creating new);
new Cupboard();
t2.f2(1);
t3.f3(1);
}
static Table t2 =
new Table();
static Cupboard t3 =
new Cupboard();
}
// /:~
输出结果:
Bowl(1)
Bowl(2)
Table()
f(1)
Bowl(4)
Cupboard //静态代码块
Bowl(5)
Bowl(3)
Cupboard 构造块
Cupboard() //构造方法
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard 构造块
Cupboard()
f(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard 构造块
Cupboard()
f(2)
f2(1)
f3(1)
分析:
StaticInitialization 中,先初始化静态成员,再执行静态方法
2、 static Table t2 = new Table(); 先初始化静态成员,如果有静态代码块的话,他们都按声明顺序 顺序初始化,然后执行构造方法。只执行一次。
3、 static Cupboard t3 = new Cupboard(); 先初始化静态成员,执行静态代码块,只执行一次。然后初始化成员变量,调用构造块,调用构造方法,并且每次创建对象时,都会执行。
4、 System.out.println( "Creating new ); 静态成员都初始化以后,执行静态方法。
static初始化 仅执行一次——首次生成那个类的一个对象时,或者首次访问属于那个类的一个static成员时(即便从未生成过那个类的对象)
package com.test.mianshi;
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) {
System.out.println(
"Inside main()");
Cups.c1.f(99);
// (1)
}
static Cups x =
new Cups();
// (2)
static Cups y =
new Cups();
// (2)
}
// /:~
输出结果:
Cup(1)
Cup(2)
Cups()
Cups()
//静态成员只初始化一次,所以当执行
static
Cups y =
new
Cups(); 时,直接调用构造方法,两个静态成员已经完成了初始化了。
Inside main()
f(99)
注释(2),保留(1),输出结果是:
Inside main()
Cup(1)
Cup(2)
f(99)
所以,只要调用静态成员,就会完成全部静态数据的初始化,注意到本次运行,并没有创建 Cups对象
非静态实例的初始化:
class Mug {
Mug(
int marker) {
System.out.println(
"Mug(" + marker +
")");
}
void f(
int marker) {
System.out.println(
"f(" + marker +
")");
}
}
public
class Mugs {
Mug c1;
Mug c2;
{
c1 =
new Mug(1);
c2 =
new Mug(2);
System.out.println(
"c1 & c2 initialized");
}
Mugs() {
System.out.println(
"Mugs()");
}
public
static
void main(String[] args) {
System.out.println(
"Inside main()");
Mugs x =
new Mugs();
}
}
// /:~
输出结果:
Inside main()
Mug(1)
Mug(2)
c1 & c2 initialized
Mugs()
构造块优先于构造方法执行,并且每创建一个对象就执行一次
大家可看到实例初始化从句:
{
c1 = Mug(1);
c2 = Mug(2);
System.out.println();
}
它看起来与静态初始化从句极其相似,只是static关键字从里面消失了。为支持对“匿名内部类”的初始化,必须采用这一语法格式。
java类加载顺序:先父类的static成员变量-》子类的static成员变量-》父类的成员变量-》父类构造-》子类成员变量-》子类构造。
转载于:https://blog.51cto.com/2301703/1034767