有下面的一个类,请问最后main方法输出是什么?请试着分析打印输出的过程,写出自己的理解。
public class Book {
static Book book = new Book();
static int amount = 112;
static {
System.out.println("书的静态代码块");
System.out.println("amount=" + amount);
}
int price = 110;
{
System.out.println("书的普通代码块");
}
Book() {
System.out.println("书的构造方法");
System.out.println("price=" + price + ",amount=" + amount);
}
public static void staticFunction() {
System.out.println("书的静态方法");
}
public static void main(String[] args) {
staticFunction();
}
}
运行代码后输出:
分析:
- 运行main方法,会先发生 Book 类的加载,类加载的过程是:加载->验证->准备->解析->初始化->使用->卸载,在执行初始化这个阶段的时候,会对类所有的静态变量进行初始化,也就是book = null,amount=0。注意:假如使用final修饰静态变量,它是不会初始化的,直接赋值,因为final修饰的变量不可改变;
- 第二步是对静态变量赋值,先赋值book = new Book();这个地方new 了一个Book,new Book()需要类加载,然后再进行对象实例化,但是类加载已经进行过了,那么这次就直接实例化对象了。
- 实例化Book对象,需要先对Book的成员变量赋值int price = 110,然后执行代码块 { System.out.println(“书的普通代码块”); },所以我们看到控制台先打印了这句话,接着执行构造方法,打印输出 书的构造方法,打印输出price=110,amount=0,price=110很好理解,就是刚才在实例化对象的时候成员变量赋值,那么amount=0呢?这就得联系到刚才初始化类的时候我们给类的静态变量初始化,amount被初始化为0,所以打印了amount=0。
- 再往下继续给类的静态变量赋值,amount = 112;,赋值完所有的静态变量后开始执行类的静态块:
static {
System.out.println("书的静态代码块");
System.out.println("amount=" + amount);
}
- 类加载结束之后,开始执行main方法里面的代码,打印 书的静态方法 这句话。
芜湖~ 看起来没那么复杂啊。但是通过这个小例子,却能很好地理解类加载的机制,尤其是各个代码块执行的顺序,一目了然。
再比如下面的一个类,请问最后main方法输出是什么?
public class Main {
public static int k = 0;
static Main t1 = new Main("t1");
public static Main t2 = new Main("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
static {
print("静态块");
}
public Main(String str) {
System.out.println((++k) + ": " + str + " i=" + i + " n=" + n);
++i;
++n;
}
public static int print(String str) {
System.out.println((++k) + ": " + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
new Main("init");
}
}
运行结果:
分析一番:
- 运行main方法会触发类加载,第一步先初始化类的静态变量,k=0,t1=null,t2=null,i=0,n=0。
- 然后是静态变量的赋值,k=0,t1=new Main(“t1”),到了new Mian(“t1”)这一步会再次触发类加载,但是类已经加载过了,那么就直接执行对象的初始化了。
- 初始化对象,先给对象的成员变量 j 赋值,直接调用了类的静态方法print(“j”),所以打印:1: j i=0 n=0, 执行完后:k=1, i =1, n=1。
- 然后执行构造方法 Main(“t1”),输出:2: t1 i=1 n=1,执行完后:k=2, i=2,n=2。
- 再往下,执行到t2=new Main(),再次触发类加载,类加载已经进行了,所以还是对象的初始化。注意:类加载只有一次,对象可以初始化多次,那么t2的执行流程和刚才的t1是完全一致的,先执行print(“j”)方法:3: j i=2 n=2,再执行构造函数输出:4: t2 i=3 n=3,执行完后:k=4, i=4,n=4。
- 赋值完t1和t2,接下来赋值静态变量 i,执行静态方法:print(“i”),打印输出:5: i i=4 n=4,执行完后k=5, i=5,n=5。
- 再赋值静态变量n=99,执行完后k=5, i=5,n=99。
- 赋值完所有的静态变量,就开始执行静态代码块了,在静态代码块里,还是执行了静态方法print(“静态块”),打印 6: 静态块 i=5 n=99,执行完后k=6, i=6,n=100。
- 最后执行main函数里面的代码 new Main(“init”),同上面一样,先是对成员变量 j 赋值,输出 7: j i=6 n=100,执行完后:k=7, i=7,n=101,再执行构造方法,输出8: init i=7 n=101, 执行完后:k=8, i=8,n=102。
以上就是本题的全部解析了,怎么样?是不是静下心来分析,也没那么难呢?还是那个道理,只要掌握了方法,分析任何问题都只是时间的问题。就跟我们解数学题一样,但是Java代码远没有数学那么枯燥和复杂,当你真的自己分析出来的时候,喜悦感会油然而生的,当然,这份喜悦也只有自己能体会到。