参考:https://frxcat.fun/
Java 反射 一个需求引出反射
问题定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| package com.reflection.question;
import com.Cat;
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties;
@SuppressWarnings({"ALL"}) public class ReflectionQuestion { public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Properties properties = new Properties(); properties.load(new FileInputStream("src\\re.properties")); String classfullpath = properties.get("classfullpath").toString(); String methodName = properties.get("method").toString(); System.out.println("classfullpath="+classfullpath); System.out.println("method="+methodName);
Class cls = Class.forName(classfullpath); Object o = cls.newInstance(); System.out.println("o的运行类型="+o.getClass()); Method method1 = cls.getMethod(methodName); System.out.println("========================="); method1.invoke(o); } }
|
反射机制
Java Reflection
Java 反射机制原理示意图!!!
Java 反射机制可以完成
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时得到任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
反射相关的主要类
- java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
- java.lang.reflect.Method:代表类的方法, Method对象表示某个类的方法
- java.lang.reflect.Field:代表类的成员变量, Field对象表示某个类的成员变量
- java.lang.reflect.Constructor:代表类的构造方法, Constructor对象表示构造器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| package com.reflection;
import java.io.FileInputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Properties;
@SuppressWarnings({"all"}) public class Reflection01 { public static void main (String[] args) throws Exception{
Properties properties = new Properties(); properties.load(new FileInputStream("src\\re.properties")); String classfullpath = properties.get("classfullpath").toString(); String methodName = properties.get("method").toString();
Class cls = Class.forName(classfullpath); Object o = cls.newInstance(); System.out.println("o的运行类型=" + o.getClass()); Method method1 = cls.getMethod(methodName); System.out.println("========================="); method1.invoke(o);
Field nameFile = cls.getField("age"); System.out.println(nameFile.get(o));
Constructor constructor1 = cls.getConstructor(); System.out.println(constructor1);
Constructor constructor2 = cls.getConstructor(String.class); System.out.println(constructor2); } }
|
反射优点和缺点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| package com.reflection;
import com.Cat; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
@SuppressWarnings({"all"}) public class Reflection02 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { m1(); m2(); m3(); }
public static void m1(){ Cat cat = new Cat(); long start = System.currentTimeMillis(); for (int i = 0; i < 90000000; i++) { cat.hi(); } long end = System.currentTimeMillis(); System.out.println("传统方法来调用hi耗时="+(end-start)); }
public static void m2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Class cls = Class.forName("com.Cat"); Object o = cls.newInstance(); Method method = cls.getMethod("hi"); long start = System.currentTimeMillis(); for (int i = 0; i < 90000000; i++) { method.invoke(o); } long end = System.currentTimeMillis(); System.out.println("反射机制方法来调用hi耗时="+(end-start)); }
public static void m3() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Class cls = Class.forName("com.Cat"); Object o = cls.newInstance(); Method method = cls.getMethod("hi"); method.setAccessible(true); long start = System.currentTimeMillis(); for (int i = 0; i < 90000000; i++) { method.invoke(o); } long end = System.currentTimeMillis(); System.out.println("m3 调用hi耗时="+(end-start)); } }
|
Class类
基本介绍
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.reflection.class_;
import com.Cat;
public class Class01 { public static void main(String[] args) throws ClassNotFoundException {
Class cls1 = Class.forName("com.Cat");
Class cls2 = Class.forName("com.Cat"); System.out.println(cls1.hashCode()); System.out.println(cls2.hashCode()); Class cls3 = Class.forName("com.Dog"); System.out.println(cls3.hashCode()); } }
|
Class类的常用方法
应用实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com.reflection.class_;
import com.Car; import java.lang.reflect.Field;
public class Class02 { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
String classAllPath = "com.Car"; Class<?> cls = Class.forName(classAllPath); System.out.println(cls); System.out.println(cls.getClass()); System.out.println(cls.getPackage().getName()); System.out.println(cls.getName()); Car car = (Car)cls.newInstance(); System.out.println(car); Field brand = cls.getField("brand"); System.out.println(brand.get(car)); brand.set(car,"奔驰"); System.out.println(brand.get(car)); System.out.println("========所有的字段属性======="); Field[] fields = cls.getFields(); for (Field f :fields) { System.out.println(f.getName()); } } }
|
获取Class对象的几种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package com.reflection.class_;
import com.Car;
public class GetClass_ { public static void main(String[] args) throws ClassNotFoundException {
String classAllPath = "com.Car"; Class<?> cls1 = Class.forName(classAllPath); System.out.println(cls1);
Class cls2 = Car.class; System.out.println(cls2);
Car car = new Car(); Class cls3 = car.getClass(); System.out.println(cls3);
ClassLoader classLoader = car.getClass().getClassLoader(); Class cls4 = classLoader.loadClass(classAllPath); System.out.println(cls4);
System.out.println(cls1.hashCode()); System.out.println(cls2.hashCode()); System.out.println(cls3.hashCode()); System.out.println(cls4.hashCode());
Class<Integer> integerClass = int.class; Class<Character> characterClass = char.class; Class<Boolean> booleanClass = boolean.class; System.out.println(integerClass);
Class<Integer> type = Integer.TYPE; Class<Character> type1 = Character.TYPE; System.out.println(type1);
System.out.println(integerClass.hashCode()); System.out.println(type1.hashCode()); } }
|
哪些类型有Class对象
如下类型有 Class 对象
- 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
- interface:接口
- 数组
- enum:枚举
- annotation:注解基本数据类型
- void
应用实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.reflection.class_;
import java.io.Serializable;
public class AllTypeClass { public static void main(String[] args) {
Class<String> cls1 = String.class; Class<Serializable> cls2 = Serializable.class; Class<Integer[]> cls3 = Integer[].class; Class<float[][]> cls4 = float[][].class; Class<Deprecated> cls5 = Deprecated.class; Class<Thread.State> cls6 = Thread.State.class; Class<Long> cls7 = long.class; Class<Void> cls8 = void.class; Class<Class> cls9 = Class.class;
System.out.println(cls1); System.out.println(cls2); System.out.println(cls3); System.out.println(cls4); System.out.println(cls5); System.out.println(cls6); System.out.println(cls7); System.out.println(cls8); System.out.println(cls9); } }
|
类加载
基本说明
反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。
- 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
- 动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性
类加载时机
- 当创建对象时(new )//静态加载
- 当子类加载时,父类也加载//静态加载
- 调用类中的静态成员时//静态加载
- 通过反射//动态加载
1
| Class.forName("com.test.Cat");
|
类加载过程图
类加载各阶段完成任务
加载阶段
连接阶段-验证
连接阶段-准备
JVM 会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、OL、null、false等)。这些变量所使用的内存都将在方法区中进行分配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.reflection.classload_;
public class ClassLoad02 { public static void main(String[] args) {
} }
class A { public int n1 = 10; public static int n2 = 20; public static final int n3 = 30; }
|
连接阶段-解析
虚拟机将常量池内的符号引用替换为直接引用的过程
Initialization(初始化)
执行clint方法,编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的复制动作和静态代码块中的语句,并合并
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package com.reflection.classload_;
public class ClassLoad3 { public static void main(String[] args) throws ClassNotFoundException {
new B(); System.out.println(B.num);
B b = new B(); } } class B{ static { System.out.println("B 静态代码块被执行"); num=300; } static int num=100; public B(){ System.out.println("B 构造器被执行"); } }
|
通过反射获取类的结构信息
第一组: java.lang.Class 类
第二组:java.lang.reflect.Field 类
第三组: java.lang.reflect.Method 类
第四组: java.lang.reflect.Constructor 类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| package com.reflection;
import org.junit.jupiter.api.Test;
import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method;
public class ReflectionUtils { public static void main(String[] args) {
}
@Test public void api_02()throws ClassNotFoundException{ Class<?> personCls = Class.forName("com.reflection.Person"); Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(" 本类中所有属性="+declaredField.getName() +" 该属性的修饰符值="+declaredField.getModifiers() + " 该属性的类型="+declaredField.getType()); } Method[] declaredMethods = personCls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中所有方法="+declaredMethod.getName() +" 该方法的访问修饰符="+declaredMethod.getModifiers() +" 该方法返回类型"+declaredMethod.getReturnType()); Class<?>[] parameterTypes = declaredMethod.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println("该方法的形参类型="+parameterType.getName()); } } Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor<?> declaredConstructor: declaredConstructors) { System.out.println("本类中所有的构造器="+declaredConstructor.getName()); Class<?>[] parameterTypes = declaredConstructor.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println("该构造器的形参类型="+parameterType.getName()); } }
} @Test public void api_01() throws ClassNotFoundException {
Class<?> personCls = Class.forName("com.reflection.Person"); System.out.println(personCls.getName()); System.out.println(personCls.getSimpleName()); Field[] fields = personCls.getFields(); for (Field field : fields) { System.out.println("本类及父类的属性="+field.getName()); } Field[] declaredFields = personCls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("本类中所有属性="+declaredField.getName()); } Method[] methods = personCls.getMethods(); for (Method method : methods) { System.out.println("本类及父类的="+method.getName()); } Method[] declaredMethods = personCls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println("本类中所有方法="+declaredMethod.getName()); } Constructor<?>[] constructors = personCls.getConstructors(); for (Constructor<?> constructor : constructors) { System.out.println("本类构造器="+constructor.getName()); } Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors(); for (Constructor<?> declaredConstructor: declaredConstructors) { System.out.println("本类中所有的构造器="+declaredConstructor.getName()); } System.out.println(personCls.getPackage()); Class<?> superclass = personCls.getSuperclass(); System.out.println("父类的Class对象="+superclass); Class<?>[] interfaces = personCls.getInterfaces(); for (Class<?> anInterface : interfaces) { System.out.println("接口信息="+anInterface.getName()); } Annotation[] annotations = personCls.getAnnotations(); for (Annotation annotation : annotations) { System.out.println("注解信息="+annotation); } } } interface IA{} interface IB{} class A{ public String hobby; public A(){} } @Deprecated class Person extends A implements IA,IB{ public String name; protected static int age; String job; private double sal; public Person(){} public Person(String name){} private Person(String name,int age){}
public void m1(String name,int age,double sal){ } protected String m2(){ return null; } void m3(){} private void m4(){} }
|
通过反射创建对象
- 方式一:调用类中的public修饰的无参构造器
- 方式二:调用类中的指定构造器
- Class类相关方法
- newlnstance:调用类中的无参构造器,获取对应类的对象
- getConstructor(Class..clazz):根据参数列表,获取对应的public构造器对象
- getDecalaredConstructor(Class...clazz):根据参数列表,获取对应的所有构造器对象
- Constructor类相关方法
- setAccessible:暴破
- (Object...obj):调用构造器
案例演示
测试 1:通过反射创建某类的对象,要求该类中必须有 public 的无参构造
测试 2:通过调用某个特定构造器的方式,实现创建某类的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException;
public class ReflectCreateInstance { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<?> userClass = Class.forName("User"); Object o = userClass.newInstance(); System.out.println(o);
Constructor<?> constructor = userClass.getConstructor(String.class); Object hhh = constructor.newInstance("hhh"); System.out.println("hhh="+hhh); Constructor<?> constructor1 = userClass.getDeclaredConstructor(int.class, String.class); constructor1.setAccessible(true); Object user2 = constructor1.newInstance(100, "张三丰"); System.out.println("user2="+user2);
} } class User{ private int age; private String name="name";
public User() { }
public User(String name) { this.name = name; }
private User(int age, String name) { this.age = age; this.name = name; }
@Override public String toString() { return "User{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
|
通过反射访问类中的成员
访问属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import java.lang.reflect.Field;
public class ReflectAccessProperty { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<?> stuClass = Class.forName("Student"); Object o = stuClass.newInstance(); System.out.println(o.getClass()); Field age = stuClass.getField("age"); age.set(o,88); System.out.println(o); System.out.println(age.get(o));
Field name = stuClass.getDeclaredField("name"); name.setAccessible(true); name.set(null,"小明"); System.out.println(o); System.out.println(name.get(null)); System.out.println(name.get(o));
} } class Student{ public int age; private static String name; public Student(){
}
@Override public String toString() { return "Student{" + "age=" + age + '}'; } }
|
访问方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class ReflectAccessMethod { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, NoSuchFieldException, InvocationTargetException {
Class<?> bossClass = Class.forName("Boss"); Object o = bossClass.newInstance(); Method hi = bossClass.getDeclaredMethod("hi",String.class); hi.invoke(o, "快乐每一天");
Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class); say.setAccessible(true); System.out.println(say.invoke(o,100,"张三",'男')); System.out.println(say.invoke(null,200,"李四",'女'));
Object reVal = say.invoke(null, 300, "王五", '男'); System.out.println("reVal 的运行类型="+reVal.getClass()); } }
class Boss { public int age; private static String name;
public Boss() { }
private static String say(int n, String s, char c) { return n + " " + s + " " + c;
}
public void hi(String s) { System.out.println("hi " + s);
} }
|
本章作业
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class Homework01 { public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
Class<PrivateTest> privateTestClass = PrivateTest.class; PrivateTest privateTestObj = privateTestClass.newInstance(); Field name = privateTestClass.getDeclaredField("name"); name.setAccessible(true); name.set(privateTestObj,"hh"); Method getName = privateTestClass.getMethod("getName"); Object invoke = getName.invoke(privateTestObj); System.out.println("name的属性值="+invoke);
} } class PrivateTest{ private String name="hello";
public String getName(){ return name; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| \import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class Homework02 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> fileClass = Class.forName("java.io.File"); Constructor<?>[] declaredConstructors = fileClass.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println("File构造器="+declaredConstructor); } Constructor<?> declaredConstructor = fileClass.getDeclaredConstructor(String.class); String fileALLPath="E:\\Mynew.txt"; Object file = declaredConstructor.newInstance(fileALLPath); Method createNewFile = fileClass.getMethod("createNewFile"); createNewFile.invoke(file); System.out.println(file.getClass()); System.out.println("创建文件成功"+fileALLPath);
} }
|