可以用构造器来进行初始化,但是成员变量的自动初始化是在构造器被调用之前发生的,即成员变量的自动初始化不能被阻止。
如以下例子:
public class Counter {
int count;
Counter(){
count = 7;
}
}
count首先是为0,当调用其构造方法后,才使得count为7.
1.初始化顺序
在类的内部,变量定义的先后顺序决定了其初始化顺序。但变量的初始化操作会在调用任何方法之前完成,包括构造方法,哪怕变量的定义散布于方法定义之间。
如以下例子:
class Window{
Window(int i){
System.out.println("Window("+i+")");
}
}
class House{
Window window1 = new Window(1);
House(){
System.out.println("----I'm contructor method----");
}
Window window2 = new Window(2);
void f(){
System.out.println("-----I'm f()-----");
}
Window window3 = new Window(3);
}
public class Demo {
public static void main(String[] args) {
House house = new House();
house.f();
}
}
当运行这个代码时,其结果为:
Window(1)
Window(2)
Window(3)
----I'm contructor method----
-----I'm f()-----
由此可以看出,Window的几个对象均在House的构造器和f()方法之前便已完成初始化。
2、静态数据的初始化
无论创建多少对象,静态数据都只占据一份存储域。static关键字不能应用于局部变量,因此它只能作用于域。
可以通过一个例子来看静态数据的初始化是如何进行的:
package com.hd.demo;
class Bowl{
Bowl(int i){
System.out.println("Bowl("+i+")");
}
void f(int i){
System.out.println("f("+i+")");
}
}
class Table{
static Bowl bolw1 = new Bowl(1);
Table(){
System.out.println("----I'm Table contructor method----");
}
void f(){
System.out.println("-----I'm f() method in Table-----");
}
static Bowl bolw2 = new Bowl(2);
}
class Cupboard{
Bowl bowl3 = new Bowl(3);
static Bowl bowl4 = new Bowl(4);
Cupboard(){
System.out.println("----I'm Cupboard contructor method----");
bowl4.f(1);
}
void f(){
System.out.println("-----I'm f() method in Cupboard-----");
}
static Bowl bowl5 = new Bowl(5);
}
public class StaticDemo {
public static void main(String[] args) {
System.out.println("creating new Cupboard() in main");
new Cupboard();
System.out.println("creating new Cupboard() in main");
new Cupboard();
table.f();
cupboard.f();
}
static Table table = new Table();
static Cupboard cupboard = new Cupboard();
}
其运行结果如下:
Bowl(1)
Bowl(2)
----I'm Table contructor method----
Bowl(4)
Bowl(5)
Bowl(3)
----I'm Cupboard contructor method----
f(1)
creating new Cupboard() in main
Bowl(3)
----I'm Cupboard contructor method----
f(1)
creating new Cupboard() in main
Bowl(3)
----I'm Cupboard contructor method----
f(1)
-----I'm f() method in Table-----
-----I'm f() method in Cupboard-----
以上代码有几个需要注意的地方,一个是StaticDemo中在main方法的下面定义了静态数据成员table和cupboard。它们会在main方法执行之前先进行初始化。另一个是Cupboard类中,先定义了一个非静态的bowl3成员。最后就是在main方法中又new了Cupboard对象。
通过以上运行结果可以得出以下结果:
1)、静态初始化只有在必要的时候才会进行,如果不创建Table对象,那么bowl1和bowl2就不会创建。
2)、静态数据只有在第一次被访问时才会进行初始化,此后便不再被初始化。比如,在main方法中new Cupboard,初始化了非静态成员bowl3,而静态成员bowl4和bowl5不再被初始化。
3)、初始化的顺序是先静态对象,后是非静态对象。
3、显示的静态初始化
先看一段代码:
class Cup{
Cup(int mark){
System.out.println("Cup("+mark+")");
}
void f(int mark){
System.out.println("f("+mark+")");
}
}
class Cups{
static Cup cup1 ;
static Cup cup2 ;
static {
cup1 = new Cup(1);
cup2 = new Cup(2);
}
}
public class ExplicitStatic {
public static void main(String[] args) {
Cups.cup1.f(1); //(1)
}
//static Cups cups1 = new Cups(); //(2)
//static Cups cups2 = new Cups(); //(3)
}
其运行结果如下:
Cup(1)
Cup(2)
f(1)
假设注释掉(1)的代码,解除(2)或(3)的代码,那么结果就会为:
Cup(1)
Cup(2)
如果同时解除(2)和(3)的代码,其运行结果都是一样的。因为上面已经提到,静态数据只有在第一次被访问时才会初始化,此后便不再初始化。
4、非静态实例初始化
先看一段代码:
class Mug{
Mug(int i){
System.out.println("Mug("+i+")");
}
}
public class Mugs {
Mug mug1;
Mug mug2;
{
mug1 = new Mug(1);
mug2 = new Mug(2);
}
Mugs(){
System.out.println("无参构造器");
}
Mugs(int i){
System.out.println("有参构造器");
}
public static void main(String[] args) {
new Mugs();
new Mugs(1);
}
}
运行结果:
Mug(1)
Mug(2)
无参构造器
Mug(1)
Mug(2)
有参构造器
可以看到,因为少了一个static关键字,因此,每new一个对象,mug1和mug2都会初始化一次,并且也是在构造器执行之前完成。
写这篇博客是因为在《Java思想编程》中看到专门讲构造器初始化的知识,感觉自己有很多不懂的地方,看了两三遍才明白。现在再总结一下,算是加深印象吧。