package com.kuang.reflection;
import java.lang.annotation.ElementType;
//所有类型的Class
public class Test04 {
public static void main(String[] args) {
Class c1 = Object.class;//类的class
Class c2 = Comparable.class;//接口的class
Class c3 = String[].class;//一维数组的class
Class c4 = int[][].class;//二维数组的class
Class c5 = Override.class;//注解的class
Class c6 = ElementType.class;//枚举的class
Class c7 = Integer.class;//基本数据类型的class
Class c8 = void.class;//void的class
Class c9 = Class.class;//class类的calss
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println(c5);
System.out.println(c6);
System.out.println(c7);
System.out.println(c8);
System.out.println(c9);
//只要元素类型与维度一样,就是同一个class
int[] i1 = new int[10];
int[] i2 = new int[5];
System.out.println(i1.getClass().hashCode());
System.out.println(i2.getClass().hashCode());
}
}
Class的加载内存分析
package com.kuang.reflection;
public class Test05 {
public static void main(String[] args) {
A a = new A();
System.out.println(A.m);
/*
1.加载到内存,会产生一个类对应的 class对象
2.链接,链接结束后 m = 0
3.初始化
<clinit>(){
System.out.println("A类静态的初始化");
m = 300;
m = 100;
}
*/
}
}
class A{
static {
System.out.println("A类静态的初始化");
m = 300;
}
/*
m = 300;
m = 100;
*/
static int m = 100;
public A() {
System.out.println("A类的无参构造器初始化");
}
}
分析类的初始化
package com.kuang.reflection;
//测试类什么时候会初始化
public class Test06 {
public static void main(String[] args) throws ClassNotFoundException {
//1.主动调用
//Son son = new Son();
//2.反射也会产生主动引用
//Class.forName("com.kuang.reflection.Son");
//不会产生类的引用的方法
//System.out.println(Son.b);
//Son[] array = new Son[5];
System.out.println(Son.M);
}
static {
System.out.println("main类被加载");
}
}
class Father{
static int b = 2;
static{
System.out.println("父类被加载");
}
}
class Son extends Father{
static{
System.out.println("子类被加载");
m = 300;
}
static int m = 100;
static final int M = 1;
}
/*
加载阶段
类的加载阶段是将class文件中的二进制数据读取到内存中,然后将该字节流所代表的静态存储结构转化为方法区中运行时的数据结构,并且在堆内存中生成一个该类的java.lang.class对象,作为方法区数据结构的入口。
类加载阶段的最终产物的堆内存中的class对象,对于同一个Classloader对象,不管某各类被加载多少次,对应堆内存中的class对象始终只有一个。
类加载阶段发生在连接阶段之前,但连接阶段不必等加载阶段结束才开始,可以交叉工作。
连接阶段
类的连接阶段包括三个小的过程:分别是验证、准备和解析。
(1)验证
验证在连接阶段中的主要目地是确保class文件的字节流所包含的内容符合JVM规范,并且不会出现危害JVM自身安全的代码。但验证不符合要求时,会抛出VerifyError这样的异常后其子异常。
主要验证内容有:
验证文件格式:包括文件头部的魔术因子、class文件主次版本号、class文件的MD5指纹、变量类型是否支持等
元数据的验证:对class的字节流进行语义分析,判断是否符合JVM规范。简单来说就是java语法的正确性
字符码验证:主要验证程序的控制流程,如循环、分支等
符号引用验证:验证符号引用转换为直接引用时的合法性,保证解析动作的顺利执行。比如不能访问引用类的私有方法、全限定名称是否能找到相关的类。
(2)准备
准备阶段主要做的事就是在方法区为静态变量发配内存以及赋初始默认值(区别于初始化阶段赋的程序指定的真实值)
注意:final修饰的静态常量在编译阶段就已经赋值,不会导致类的初始化,是一种被动引用,因此也不存在连接阶段。
(3)解析
解析就是在常量池中寻找类、接口、字段和方法的符号引用,并且将这些符号引用替换成直接引用的过程。
解析过程主要针对类接口、字段、类方法和接口方法四类进行。
初始化阶段
初始化阶段是类的加载过程的最后一个阶段,该阶段主要做一件事情就是执行< clinit>(),该方法会为所有的静态变量赋予正确的值。
*/
所有类型的Classpackage com.kuang.reflection;import java.lang.annotation.ElementType;//所有类型的Classpublic class Test04 { public static void main(String[] args) { Class c1 = Object.class;//类的class Class c2 = Comparable.class;//接口的class