假设一个类变量的定义为: publicstaticintvalue=3;
那么变量value在准备阶段过后的初始值为0,而不是3,因为这时候尚未开始执行任何Java方法,而把value赋值为3的 publicstatic指令是在程序编译后,存放于类构造器 ()方法之中的,所以把value赋值为3的动作将在初始化阶段才会执行。所以在执行构造函数之前 value的值是默认值0,在执行类构造函数中,会优先赋值静态变量(静态变量按赋值顺序赋值)
如果类字段的字段属性表中存在 ConstantValue属性,即同时被final和static修饰,那么在准备阶段变量value就会被初始化为ConstValue属性所指定的值。
-
public class TestStatic {
-
public static void main(String []args){
-
staticFunticon();
-
}
-
static TestStatic s = new TestStatic();
-
static
-
{
-
System.out.println("1");
-
}
-
{
-
System.out.println("2");
-
}
-
public TestStatic(){
-
System.out.println("3");
-
System.out.println("a=:"+a+" b=:"+b);
-
}
-
public static void staticFunticon(){
-
System.out.println("4");
-
}
-
int a =110;
-
static int b =112;
-
-
}
点击(此处)折叠或打开
先上了题和答案,看能否答对
在上两段话,自己对照答案去理解,最后上改题的分析过程
什么情况下需要开始类加载过程的第一个阶段:"加载"。虚拟机规范中并没强行约束,这点可以交给虚拟机的的具体实现自由把握,但是对于初始化阶段虚拟机规范是严格规定了如下几种情况,如果类未初始化会对类进行初始化。
一、
-
创建类的实例
-
访问类的静态变量(除常量【被final修辞的静态变量】原因:常量一种特殊的变量,因为编译器把他们当作值(value)而不是域(field)来对待。如果你的代码中用到了常变量(constant
variable),编译器并不会生成字节码来从对象中载入域的值,而是直接把这个值插入到字节码中。这是一种很有用的优化,但是如果你需要改变final域的值那么每一块用到那个域的代码都需要重新编译。(调用数组也不会主动初始化)
-
访问类的静态方法
-
反射如(Class.forName("my.xyz.Test"))
-
当初始化一个类时,发现其父类还未初始化,则先出发父类的初始化(对于访问静态字段,初始化父类的时候只有直接定义这个字段的类才会初始化)
-
虚拟机启动时,定义了main()方法的那个类先初始化
二、
1.若要加载类A,则先加载执行其父类B(Object)的静态变量以及静态语句块(执行先后顺序按排列的先后顺序)。
2.然后再加载执行类A的静态变量以及静态语句块。(并且1、2步骤只会执行1次)
3.若需实例化类A,则先调用其父类B的构造函数,并且在调用其父类B的构造函数前,依次先调用父类B中的非静态变量及非静态语句块.最后再调用父类B中的构造函数初始化。
4.然后再依次调用类A中的非静态变量及非静态语句块.最后调用A中的构造函数初始化。( 并且3、4步骤可以重复执行)
5.而对于静态方法和非静态方法都是被动调用,即系统不会自动调用执行,所以用户没有调用时都不执行,主要区别在于静态方法可以直接用类名直接调用(实例化对象也可以),而非静态方法只能先实例化对象后才能调用。
运行结果分析:
首先执行main函数中的staticFunticon,因为调用静态方法了按照 一、6(
虚拟机启动时,定义了main()方法的那个类先初始化),会初始化该类,初始化之前要先 加载、连接(验证、准备、解析)、初始化、使用、卸载,按照二、1(
若要加载类A,则先加载执行其父类B(Object)的静态变量以及静态语句块(执行先后顺序按排列的先后顺序))先执行static TestStatic s = new TestStatic();这一句,因为这里new了一个实例对象,所以就会接着触发构造函数(如果没有new的话构造函数是在static变量和static语句块之后的,这
里还有说一句因为static TestStatic s = new TestStatic()在static int b=110之前,所以b还没有初始化,在准备阶段所有的static变量都是先以默认值赋值的,所以这里的b现在是默认值(0))执行构造函数前参照二、4(
然后再依次调用类A中的非静态变量及非静态语句块.最后调用A中的构造函数初始化)也就是说类中非静态成员和非静态代码块要在类构造函数前执行。所以这里先执行了System.out.println("2");,a=110;接着执行构造函数,所以输出的a=110,b=0;然后在继续向下执行static代码块System.out.println("1");最后回到main函数中执行staticFunticon方法
-
class SuperClass {
-
static {
-
System.out.println("superclass init");
-
}
-
public static int value = 123;
-
}
-
-
class SubClass extends SuperClass {
-
static {
-
System.out.println("subclass init");
-
}
-
}
-
-
public class Test {
-
public static void main(String[] args) {
-
System.out.println(SubClass.value);// 被动应用1
-
SubClass[] sca = new SubClass[10];// 被动引用2
-
}
-
}
-
程序运行输出 superclass init
-
123
-
public class InitialOrderTest {
-
/* 静态变量 */
-
public static String staticField = "静态变量";
-
public static int a = 1;
-
/* 变量 */
-
public String field = "变量";
-
/* 静态初始化块 */
-
static {
-
System.out.println(staticField);
-
System.out.println("静态初始化块");
-
System.out.print("a:"+a);
-
}
-
/* 初始化块 */
-
{
-
System.out.println(field);
-
System.out.println("初始化块");
-
}
-
-
/* 构造器 */
-
public InitialOrderTest() {
-
System.out.println("构造器");
-
}
-
-
public static void main(String[] args) {
-
//new InitialOrderTest();
-
}
-
}
阅读(1120) | 评论(0) | 转发(0) |