JVM(六) 类的初始化
来源:互联网 发布:合肥关键词优化 编辑:程序博客网 时间:2024/05/21 17:44
HOW
途径
在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值。在程序中,静态变量的初始化有两种途径:(1)在静态变量的声明处进行初始化;(2)在静态代码块中进行初始化。例如在以下代码中,静态变量a和b都被显示初始化,而静态变量c没有被显示初始化,它将保持默认值0。
public class Sample{ private static int a =1; //在静态变量的声明处进行优化 public static long b; public static long c; Static{ b=2; //在静态代码块中进行初始化 } ...}
依次执行
静态变量的声明语句,以及静态代码块都被看做类的初始化语句,Java虚拟机会按照初始化语句在类文件中的先后顺序来依次执行它们。例如当以下Sample类被初始化后,它的静态变量a的取值为4.
public class Sample {static int a =1;static{ a=2;}static{ a=4;}public static void main(String args[]){System.out.println("a="+a); //打印a=4}}
类的初始化步骤
(1)假如这个类还没有被加载和连接,那就先进行加载和连接。
(2)假如类存在直接的父类,并且这个父类还没有被初始化,那就先初始化直接的父类。
(3)假如类中存在初始化语句,那就依次执行这些初始化语句。
类的初始化时机(前面的博客已经提过两遍)
主动使用(六种)
1、创建类的实例
例:new Test();
2、访问某个类或接口的静态变量,或者对该静态变量赋值
例:int b=Test.a;
Test.a=b;
3、调用类的静态方法
例:Test.doSomething();
4、反射
例:Class.forName("come.tgb.Test");
5、初始化一个类的子类
例:class Parent{}
class child extends Parent
{public static int a =3;}
Child.a=4;
6、Java虚拟机启动时被标明为启动类的类
例:Test.java可能被编译成多个类文件,Test.class, Parent.class, Child.class,最终运行java Test,那么Test.class就是启动类。
除了以上6种情况,其他使用Java类的方式都被看看作是对类的被动使用,都不会导致类的初始化。当Java虚拟机初始化一个类时,要求它的所有父类都已经被初始化,但是这条规则并不适用于接口。
在初始化一个类时,并不会先初始化它所实现的接口。
在初始化一个接口时,并不会先初始化它的父接口。
因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的静态变量时,才会导致该接口的初始化。干货上架!
Test2.java
class FinalTest{public static final int x = 6/3;static {System.out.println("FinalTest static block");}}public class Test2 {public static void main(String[] args){System.out.println(FinalTest.x);}}运行结果:
2
分析:
用了final关键字,并将2赋值给x。使x为编译时的常量。所以调用就不会初始化。如果将final关键字去掉,那么就会初始化,依次执行。会输出"FinalTeststatic block”。
Test3.java
package jvmDemo;import java.util.Random;class FinalTest2{public static final int x = new Random().nextInt(100); //100是不包含在内的,只产生0~99之间的整数。static {System.out.println("FinalTest static block");}}public class Test3 {public static void main(String[] args){System.out.println(FinalTest2.x);}}运行结果:
FinalTest static block
20
分析:
和Test2.java唯一的不同是x的赋值。这里当编译时并不能确定x的值,运行的时候才确定,所以由主动使用的第二种。
Test4.java
package jvmDemo;class Parent{static int a = 3;static {System.out.println("Parent static block");}}class Child extends Parent{static int b = 4;static{System.out.println("Child static block");}}public class Test4 {static {System.out.println("Test4 static block");}public static void main(String[] args){System.out.println(Child.b);}}运行结果:
Test4 static block
Parent static block
Child static block
4
分析:
启动类先加载进行初始化, 对子类的"主动使用"会导致父类被初始化。
Test5.java
package jvmDemo;class Parent2{static int a = 3;static {System.out.println("Parent static block");}}class Child2 extends Parent2{static int b = 4;static{System.out.println("Child static block");}}public class Test5 {static {System.out.println("Test5 static block");}public static void main(String[] args){Parent2 parent;System.out.println("--------------");parent = new Parent2();System.out.println(Parent2.a);System.out.println(Child2.b);}}运行结果:
Test5 static block
--------------
Parent static block
3
Child static block
4
分析:
启动类先加载进行初始化,只声明没有创建实例不会对Parent2进行初始化。对父类的"主动使用"并不会导致子类初始化。在同一个类加载器下只能初始化一次。
Test6.java
package jvmDemo;class Parent3{static int a = 3;static {System.out.println("Parent3 static block");}static void dosomething(){System.out.println("do something");}}class Child3 extends Parent3{static{System.out.println("Child3 static block");}}public class Test6 {public static void main(String[] args){System.out.println(Child3.a);Child3.dosomething();}}运行结果:
Parent3 static block
3
do something
分析:
只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或接口的主动使用。以上程序,Child3.a是对其父类的主动使用。
Test7.java
package jvmDemo;class CL{static {System.out.println("Class CL");}}public class Test7 {public static void main(String[] args) throws Exception{//获得系统类加载器ClassLoader loader = ClassLoader.getSystemClassLoader();Class<?> clazz = loader.loadClass("jvmDemo.CL");System.out.println("------------------");clazz = Class.forName("jvmDemo.CL");}}运行结果:
------------------
Class CL
分析:
调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。
拓展:
getSystemClassLoader()
官网api文档的介绍:http://docs.oracle.com/javase/7/docs/api/
getSystemResourceAsStream
public static InputStream getSystemResourceAsStream(String name)
Open for reading, a resource of the specified name from the search path used to load classes. This method locates the resource through the system class loader (seegetSystemClassLoader()
).- Parameters:
name
- The resource name- Returns:
- An input stream for reading the resource, or null if the resource could not be found
- Since:
- 1.1
官网api文档的介绍:http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#loadClass(java.lang.String)
loadClass
public Class<?> loadClass(String name) throws ClassNotFoundException
Loads the class with the specified binary name. This method searches for classes in the same manner as theloadClass(String, boolean)
method. It is invoked by the Java virtual machine to resolve class references. Invoking this method is equivalent to invokingloadClass(name, false)
.- Parameters:
name
- The binary name of the class- Returns:
- The resulting Class object
- Throws:
ClassNotFoundException
- If the class was not found
- JVM(六) 类的初始化
- jvm初始化一个类的六种情形
- JVM类的初始化
- JVM 类的加载初始化
- jvm 类初始化的条件
- jvm - 类的初始化过程
- JVM 的类初始化机制
- JVM学习笔记(四):类的初始化
- jvm(一)类的加载,连接,初始化简介
- jvm(二)类的加载,连接,初始化详解
- JVM(三) 类的加载、连接与初始化
- JVM学习笔记(六):类加载的时机
- JVM java类的装载、链接、初始化
- 聊聊JVM(六)理解JVM的safepoint
- J2SE(六)Java之类的初始化
- JVM类使用过程(加载,初始化)
- jvm规范规定的对类(或者接口)初始化的情况
- jvm规范规定的对类(或者接口)初始化的情况
- Redis常见7种使用场景(PHP实战)
- spring-boot--使用thymeleaf模板
- GObject消息系统之Signals
- 补一
- Esri官网如何申请试用版 ArcGIS Desktop?试用版过期怎么办?
- JVM(六) 类的初始化
- itunes安装苹果测试包总是“正在安装”
- 第九次多校赛总结+CSU 1914+CSU 1921加强版解法
- 当前a标签保持样式,其余恢复
- 【Unity3D】世界坐标与屏幕坐标
- android 杜绝崩溃闪退处理
- Serializable(长时间保存对象 方法一)
- 逆波兰表达式
- 命令行设置代理