反射
正常情况下,需要import语句引入一个类,再通过new关键字创建实例化对象。而通过实例化对象,来寻找其类的定义这就是反射机制
反射类的体系结构

类加载器
Java程序执行流程

类加载器所做的事情
- 类加载:读取class文件到内存,并创建一个Class对象
- 类连接
- 验证阶段:检查类的内部结构是否正确
- 准备阶段:为类变量分配内存,设置初始化参数(不同形式的0)
- 解析阶段:将类的二进制数据中的符号引用替换为直接引用(将变量变为地址信息)
- 类的初始化
- 该类的直接父类未被加载,先加载父类并初始化
- 执行类变量的显示赋值
类的加载时机
- 创建类的实例
- 调用类的静态方法
- 访问类或接口的静态变量
- 反射方式强制创建该类的Class对象
- 使用其子类
- 使用java命令运行该类的主方法
类加载机制
- 全盘负责:加载某个类时,该类的依赖和引用都由该加载器负责
- 父类委托:加载某个类时,先让父加载器加载,父加载器无法加载自己才加载
- 缓存机制:加载过的类会缓存,只有缓存中不存在要加载的类时才会读取相对应的class文件到缓存中
类加载器查看方式
System.out.println(String.class.getClassLoader());
System.out.println(ClassLoader.getSystemClassLoader());
System.out.println(ClassLoader.getSystemClassLoader().getParent());
System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
动态获取文件路径
System.out.println(Test.class.getClassLoader().getResource("/"));
System.out.println(Test.class.getClassLoader().getResource(""));
System.out.println(Test.class.getClassLoader().getResource("file"));
System.out.println(Test.class.getResource("/"));
System.out.println(Test.class.getResource(""));
System.out.println(Test.class.getResource("file"));
InputStream is = Test.class.getClassLoader().getResourceAsStream("file");
InputStream is = Test.class.getResourceAsStream("file");
自定义类加载器
public class Test{
public static void test(){
System.out.println("test!!!");
}
}
继承Classloader,读取class文件,返回父类的defineClass方法即可
public class Main{
public static void main(String[] args) throws Exception {
TestClassLoader testClassLoader = new TestClassLoader();
Class<?> test = testClassLoader.loader("Test");
Method testFun = test.getMethod("test");
testFun.invoke(test);
System.out.println(test.getClassLoader());
System.out.println(test.getClassLoader().getParent());
System.out.println(test.getClassLoader().getParent().getParent());
System.out.println(test.getClassLoader().getParent().getParent().getParent());
}
}
class TestClassLoader extends ClassLoader {
public Class<?> loader(String name) throws Exception {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(new File("Test.class")));
byte[] bytes = bufferedInputStream.readAllBytes();
bufferedInputStream.close();
return super.defineClass(name,bytes,0,bytes.length);
}
}
获取反射的三种方式
方式 |
方法 |
描述 |
通过对象获取 |
对象.getClass() |
该方法是Object继承的,final修饰无法被重写 |
通过类似于类静态属性获取 |
类名.class |
其实是Java原生代码支持,class本身就是关键字 |
通过Class类的静态方法来获取 |
Class<?> forName(String className) |
参数是类的全类名,即包名+类名的字符串形式 |
Class类
获取结构信息方法
方法名 |
描述 |
String getName() |
获取类的全类名 |
String getSimpleName() |
获取类的简单类名 |
Package getPackage() |
获取类的包对象 |
Class<?>[] getInterfaces() |
获取类实现的全部接口的反射 |
Class<? super T> getSuperclass() |
获取类的父类的反射 |
boolean isArray() |
判断该反射是否是数组 |
包类
方法名 |
描述 |
String getName() |
获取包名 |
获取构造方法
方法名 |
描述 |
Constructor<?>[] getConstructors() |
获取所有public修饰的构造方法 |
Constructor<T> getConstructor(Class<?>... parameterTypes) |
根据指定参数列表获取指定单个public修饰的构造方法,参数是数据类型的反射对象 |
Constructor<?>[] getDeclaredConstructors() |
获取所有构造方法 |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) |
根据指定参数列表获取单个构造方法,参数是数据类型的反射对象 |
构造方法类
方法名 |
描述 |
T newInstance(Object ... initargs) |
创建实例化对象,参数对应构造方法的参数 |
获取普通方法
方法名 |
描述 |
Method[] getMethods() |
获取所有public修饰的方法,包括继承的 |
Method getMethod(String name, Class<?>... parameterTypes) |
根据方法名和参数列表获取public修饰的方法,参数是数据类型的反射对象 |
Method[] getDeclaredMethods() |
获取所有方法,不包括继承的 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) |
根据方法名和参数列表获取方法,参数是数据类型的反射对象 |
方法类
方法名 |
描述 |
Object invoke(Object obj, Object... args) |
调用obj的该方法,args参数列表,返回值类型是Object |
int getModifiers() |
获取方法修饰符,若想查看字面上的修饰符则使用Modifier.toString(int mod) 转换 |
Class<?> getReturnType() |
获取方法返回值数据类型的反射对象 |
String getName() |
获取方法名称 |
Class<?>[] getParameterTypes() |
获取方法的全部参数数据类型的反射对象 |
Class<?>[] getExceptionTypes() |
获取方法的所有异常反射对象 |
获取属性
方法名 |
描述 |
Field[] getFields() |
获取所有public修饰的属性,包括继承的 |
Field getField(String name) |
根据name获取单个public修饰的属性 |
Field[] getDeclaredFields() |
获取全部的属性,不包括继承的 |
Field getDeclaredField(String name) |
根据name获取的属性 |
属性类
方法名 |
描述 |
Class<?> getType() |
获取属性类型的反射对象 |
Object get(Object obj) |
获取obj对象的该属性内容 |
void set(Object obj, Object value) |
为obj对象的该属性赋值为value |
获取注解
方法名 |
描述 |
Annotation[] getAnnotations() |
获取全部注解 |
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) |
根据注解的反射对象来判断该注解是否存在 |
<T extends Annotation> T getAnnotation(Class<T> annotationClass) |
根据注解的反射对象来获取指定的注解 |
注解类
得到具体的注解类对象,直接调用注解.属性()
就可以返回注解的属性值,这样看来注解中的属性其实算是方法
Unsafe类
private Unsafe() {};
private static final Unsafe theUnsafe = new Unsafe();
只能通过反射机制来获取其封装的属性,该类可以实现绕过创建对象的步骤,直接调用该类的普通方法
class Test{
private Test(){
System.out.println("构造方法被调用");
}
public void method(){
System.out.println("普通方法别调用");
}
}
public class Main{
public static void main(String[] args) throws Exception {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Test test = (Test)unsafe.allocateInstance(Test.class);
test.method();
}
}
Comments NOTHING