曾经被一哥们问题个问题,为什么接口的常量只能定义为static final,我当时还说他一个接口你定义点方法就行了,还弄什么常量,不过话又说回来,我确实没有解决他的这个问题,以前看Thinking in java貌似解决了类初始化为对象的过程,今天看了一下CLass的类字节变量,感觉又明白许多,下面将代码贴上,逐个分析
package com.bird.thinking;import java.util.Random;/** * @use 探寻Java的Class类内幕 * @author bird * */class Initable{ public static final int staticFinal = 47;//他的值不变 public static final int staticFinal2 = //他的值是变化的 ClassInitialization.rand.nextInt(1000); static { System.out.println("初始化 Initable"); }}class Initable2{ public static int stationNonFinal = 147;//注意没有final static{ System.out.println("初始化 Initable2"); }}class Initable3{ public static int staticNonFinal = 74; static{ System.out.println("初始化 Intiable3"); }}public class ClassInitialization { public static Random rand = new Random(47); @SuppressWarnings("unchecked") public static void main(String [] args) throws ClassNotFoundException{ @SuppressWarnings("unused") Class initable = Initable.class;//只是加载字节码进入虚拟机,获得引用没有初始化 System.out.println("After creating Initable ref"); System.out.println(Initable.staticFinal);//请求访问static final定值 System.out.println(Initable.staticFinal2);//请求访问static final 为直接定义的值 System.out.println(Initable2.stationNonFinal);//访问static的值 @SuppressWarnings("unused") Class initable3 = Class.forName("com.bird.thinking.Initable3");//装载并且初始化 System.out.println("After creating Initable3 ref"); System.out.println(Initable3.staticNonFinal); }}
运行结果如下
After creating Initable ref47初始化 Initable258初始化 Initable2147初始化 Intiable3After creating Initable3 ref74
1.首先说一下第39行,他的意思是仅仅使用Class的方法将
Initable.java的字节码装载到虚拟机中,得到对类的引用,并不初
始化类,更不可能执行static代码块
2.加载完字节码后,直接访问Initable的static final常量,没有任何
问题,说明虽然类没有被初始化,但是static final常量已经可以被
访问(这个是解释接口的重点)
3.当访问Initable的在编译时候没有指定值的static final常量的时
候,他就不能直接访问,看运行结果可知道,他需要初始化类,
即调用static静态代码块,才可以使用.
4.当调用Initable2的static变量的时候,类就必须被执行初始化才能
被访问
5.当调用Class.Forname()方法的时候,将类装载进入虚拟机,就
果断执行了static代码块,初始化后才能继续访问.
6.因此总结一下,一个类的初始化准备工作如下
6.1加载:这个由类加载器完成,他去查找字节码,并且创建一个
Class对象
6.2连接:验证类中的字节码,为静态域分配存储空间,并且如果
必须的话,将解析这个类创建的对其他类的引用
6.3初始化:如果这个类有超类,则对其进行初始化,执行静态初
始化器和静态初始化代码块
6.4初始化被延迟到了对静态方法(构造器是隐士的静态方法)或
非静态方法的首次引用才执行
7.由上面可以知道,接口不能被初始化,如果想定义常量,必须是
在接口的字节码被装载到虚拟机的时候他的常量就得被访问,所
以他必须是static final的
8static final叫编译期常量,不需要初始化就能读取。
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow