标签:初始化 java System 学习 println 机制 class 加载
/**
类的加载机制(这里的类指泛类:普通类,接口,枚举,注解...等一切类)
一 JVM和类
1 当调用java命令运行java程序时,该命令会启动一个java虚拟机进程,
不管该java程序多么复杂,该程序启动了多少进程,它们都在该java虚拟机进程里.
2 JVM进程被终止(jvm进程结束,该进程在内存中的所有数据都丢失了)
-正常结束
-运行System.exit)或Runtime.getRuntime().exit()
-程序出现了错误或未捕捉的异常
-平台强制结束了jvm进程
(II) 类的加载机制,3个步骤
1 类的加载
2 类的额连接
3 类的初始化
二 类的加载
(I)概念: 类的加载是指将类的class文件读取到内存中,并为之创建一个java.lang.Class对象的过程.(class文件->Class对象的过程)
(当程序使用任何类都是如此,都会为之创建一个java.lang.Class对象)
(II)类的加载由类的加载器完成(类加载器通常有JVM提供,当然也可以自定义类加载器,比如后面通过自定义类继承ClassLoader基类)
(III) 从不同来源加载类的二进制数据(通过不同的类加载器可以办到),类的二进制数据如下几种来源
1 从本地文件系统加载class文件(大多数类加载的方式)
2 从jar包中加载class文件(也很常见)
3 通过网络加载class文件
4 把一个java源文件动态编译,执行并加载
(VI) 注意: java虚拟机规范允许系统预先记载某些类,无需等到"首次使用"才加载该类
三 类的连接
(I)概念: 系统将类的加载生成的Class对象,在类的连接阶段将该类的二进制数据合并到JRE
分为三个阶段: 验证 -> 准备 -> 解析
1 验证: 验证被加载的类是否有正确的结构,并和其他类协调一致
2 准备: 为类的类变量分配内存,并设置默认的初始值.
3 解析:将类的二进制数据中的符号引用替换成直接引用.
四 类的初始化(这里的类指一切类,泛类,一个泛类的初始化步骤前总是先初始化其直接父类)
概念: 类的初始化阶段,主要是执行类的初始化语句(静态代码块和声明类变量显式初始化的语句)
类的初始化语句(按定义顺序执行)
1 在声明类变量时指定初始值的语句
2 静态代码块
类变量显式初始化的2种方式
1 声明类变量时指定初始值
2 静态代码块中为类变量指定初始值
类的初始化步骤:其实就2步
1 加载和连接该类(假如这个类没有被加载和连接)
2 先初始化其直接父类(假如该类的直接父类还没有被初始化)只是一个判断的过程
3 执行该类初始化语句(假如该类中有初始化语句).
注意:
1 如上2只是一个判断的过程,其实还是1和3,真实的执行步骤: 简单13 复杂时111333
2 一个泛类的初始化步骤前总是先初始化其直接父类(假如该类的直接父类还没有被初始化)
五 类初始化的时机
如下6中情况将引发类或接口的初始化.
1 初始化某个类的子类
2 通过反射创建某个类或接口对应的Class对象
3 创建该类的实例
4 访问某个类的类变量
5 访问静态方法
6 直接使用java.exe命令运行某个主类(也是访问静态方法)
如下行为不会导致类的初始化(初始化该类的静态类)和执行"类.class;"语句
初始化某个类的静态内部类
初始化某个类的内部枚举
初始化某个类的内部接口
初始化某个类的内部注解
类.class
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
class A {
static {
System.out.println("A的静态代码块");
}
static String a = "jack";
static void test(){}
static class InnerA{
static String innerA = "mary";
static {System.out.println("A的静态内部类的静态代码块");}
}
enum InnerEnum{
SPIRNG;
static {System.out.println("A的内部枚举的静态代码块");}
}
interface InnerInterface{
String name = "tom";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface InnerAnnotation{
String name() default "jerry";
}
}
@A.InnerAnnotation
public class 类的加载机制 {
static { System.out.println("================"); }
public static void main(String[] args) throws Exception{
// System.out.println(new A());//创建该类对象
// System.out.println(A.a); //静态变量
// A.test();//静态方法
// System.out.println(Class.forName("A"));//反射
// System.out.println();//使用java.exe命令运行当前主类main方法,初始化这个当前主类
// System.out.println(new A(){});//初始化某个类的子类,本条语句初始化A的匿名内部类(也是A的子类)
/**
* 单独测试如上注释的打印语句都可以看到"A的静态代码块"字样在控制台输出.
* 全部打印如下语句,没有看到"A的静态代码块"字样在控制台输出,说明A类没有执行初始化步骤
* 总结: 如下行为将导致类的初始化
* 访问该类的静态变量,静态方法,创建该类的对象,初始化该类的子类,反射该类的Class对象,java.exe运行当前类的main方法.
* 如下行为不会: 初始化某类的静态类(静态内部类,内部枚举,内部接口,内部注解)和类.class
*
*/
System.out.println(A.InnerA.innerA);//初始化某个类的静态内部类
System.out.println(A.InnerEnum.SPIRNG);//初始化某个类的内部枚举
System.out.println(A.InnerInterface.name);//初始化某个类的内部接口
//初始化某个类的内部注解,获取某个类的内部注解实例
System.out.println(类的加载机制.class.getDeclaredAnnotation(A.InnerAnnotation.class));
System.out.println(A.class);
}
}
输出结果如下:
================
A的静态内部类的静态代码块
mary
A的内部枚举的静态代码块
SPIRNG
tom
@com.china.school.reflect.A$InnerAnnotation(name="jerry")
class com.china.school.reflect.A
标签:初始化,java,System,学习,println,机制,class,加载 来源: https://www.cnblogs.com/runwithtime/p/16285794.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。