注解与反射(4)
反射
什么时候会发生类初始化
类的主动引用(一定会发生类的初始化)
- 当虚拟机启动,先初始化main方法所在的类
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
- 通过数组定义类引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
具体的
package com.yangxu.Annotation.reflection;
//什么时候发生类的初始化
public class Load {
static {
System.out.println("main方法的初始化");
}
public static void main(String[] args) throws ClassNotFoundException {
//主动引用------------------------------------------------
//1. new对象一定发生初始化,且如果父类未初始化会先初始化父类
//Son son = new Son();
//2. 反射也会主动引用初始化
//Class.forName("com.yangxu.Annotation.reflection.Son");
//被动引用------------------------------------------------
//1. 子类引用父类的静态变量
//System.out.println(Son.a);
//2. 数组时
//Son[] array = new Son[5];
//3. 常量时,因为常量在连接时就已经完成了赋值,初始化不管它的事!
//System.out.println(Son.M);
}
}
class Father{
static int a = 1;
static {
System.out.println("父类的初始化");
}
}
class Son extends Father{
static final int M = 100;
static {
System.out.println("子类的初始化");
}
}
类加载器的作用
类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口。
类缓存∶标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象
类加载器作用是用来把类(class)装载进内存的。JVM规范定义了如下类型的类的加载器。
具体的
package com.yangxu.Annotation.reflection;
public class Loader {
public static void main(String[] args) throws ClassNotFoundException {
ClassLoader loader = ClassLoader.getSystemClassLoader();
System.out.println(loader);
ClassLoader parent = loader.getParent();
System.out.println(parent);
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);
ClassLoader loader1 = Class.forName("com.yangxu.Annotation.reflection.Test01").getClassLoader();
System.out.println(loader1);
//JDK的包里面的类都是用根加载器
ClassLoader loader2 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(loader2);
//如何获得系统类加载器的加载路径
System.out.println(System.getProperty("java.class.path"));
/*
C:\Program Files\Java\jdk1.8.0_291\jre\lib\charsets.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\deploy.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\access-bridge-64.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\cldrdata.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\dnsns.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\jaccess.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\jfxrt.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\localedata.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\nashorn.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunec.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunjce_provider.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunmscapi.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\sunpkcs11.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\ext\zipfs.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\javaws.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\jce.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\jfr.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\jfxswt.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\jsse.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\management-agent.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\plugin.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\resources.jar;
C:\Program Files\Java\jdk1.8.0_291\jre\lib\rt.jar;
C:\Users\Lenovo\Desktop\课程学习\Java学习\out\production\Java学习;
D:\IJ\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar
由下往上查找加载器,双亲委派机制:如果有与JDK类重名的自定义类则不执行自定义类,执行JDK的
*/
}
}
创建运行时类的对象
通过反射获取运行时类的完整结构
Field、Method、Constructor、Superclass、Interface、Annotation
package com.yangxu.Annotation.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test08 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
Class c1 = Class.forName("com.yangxu.Annotation.reflection.User");
//获得类的名字
System.out.println(c1.getName());//获得包名+类名
System.out.println(c1.getSimpleName());//获得类名
System.out.println("=====================================");
//获得类的属性
Field[] fields = c1.getFields();
for (Field field : fields) {
System.out.println("public"+field);
}
fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println("私有的:"+field);
}
System.out.println("=====================================");
//获得指定属性的值
// Field name = c1.getField("name");
// System.out.println(name);
Field name = c1.getDeclaredField("name");
System.out.println(name);
System.out.println("=====================================");
//获得类的方法
Method[] methods = c1.getMethods();
for (Method method : methods) {
System.out.println("public:"+method);
}
methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println("私有的:"+method);
}
System.out.println("=====================================");
//获得类的指定方法
//指定文件类型是因为方法重载
Method name1 = c1.getMethod("getName");
System.out.println(name1);
Method name2 = c1.getDeclaredMethod("setName", String.class);
System.out.println(name2);
System.out.println("=====================================");
//获得类的构造器
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("public:"+constructor);
}
constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println("私有的:"+constructor);
}
System.out.println("=====================================");
//获得指定的构造器
Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
System.out.println(constructor);
Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
System.out.println(declaredConstructor);
}
}