1、Java 反射(Reflection)使用场景
反射在以下情况下很有用:
1)需要访问Jar包数据中的注解时。
2)检查和实例化jar包中的类型。
3)在运行时构建新类型。
4)编译时根本无法预知该对象的类型,程序只能依靠运行时来发现对象和类的具体信息
5)执行后期绑定,访问在运行时创建的类型上的方法。可以动态调用执行方法。
6)可以动态生成类框架,如Gson。
7)Tomcat服务器是典型的反射机制应用
2、Java 反射(Reflection)的使用
1)获取Class对象
通过Java代码获取Class对象有四种方法,具体如下,
import java.util.*; public class Main { public static void main(String[] args) throws Exception { Class<?> class1 = null; Class<?> class2 = null; Class<?> class3 = null; Class<?> class4 = null; //调用Class的静态方法:forName(全类名) class1 = Class.forName("java.util.Date"); //通过运行时类的对象的getClass方法 class2 = new java.util.Date().getClass(); //调用运行时类的属性 class3 = java.util.Date.class; //ClassLoader中的loadClass(全类名)方式获取 ClassLoader classLoader = Main.class.getClassLoader(); class4 = classLoader.loadClass("java.util.Date"); System.out.println(class4); System.out.println("类名称 " + class1.getName()); System.out.println("类名称 " + class2.getName()); System.out.println("类名称 " + class3.getName()); System.out.println("类名称 " + class4.getName()); System.exit(0); //success } }
2)9个预定义Class对象
byte
,short
,int
,long
,char
,float
,double
,boolean
和void
关键字,都有class
属性。例如,
int.class; boolean.class;
int
的包装类是Integer
,Integer
和 int
不是同一种数据类型,8个基本数据类型的包装类中都有一个常量TYPE
,TYPE
表示的是该包装类对应的基本数据类型的Class
对象,
Integer.TYPE == int.class;//true Integer.TYPE != Integer.class;//true
3)获取类中的构造器
获取所有公有构造器:Class对象的getDeclaredConstructors();
获取所有构造器:Class对象的getDeclaredConstructors();
获取单个公有无参构造器:Class对象的getConstructor(null);
获取单个指定公有构造器:Class对象的getConstructor(String.class);
获取单个指定构造器:Class对象的getDeclaredConstructor(String.class);
4)获取成员变量的方法
方法 | 描述 |
Field[] getFields() | 获取当前Class所表示类的所有public字段。 |
Field[] getDeclaredFields() | 获取当前Class所表示类的所有字段, 包括:private、protected、默认、public。 |
public Field getField(String fieldName) | 获取当前Class所表示类指定的public字段。 |
public Field getDeclaredField(String fieldName) | 获取当前Class所表示类的指定字段 (可以为private) |
public void set(Object obj,Object value) | 参数 obj:要设置的字段所在的对象, value:要为字段设置的值 |
5)获取类中的成员方法
方法 | 描述 |
public Method[] getMethods() | 获取当前Class所表示类和继承的所有public方法 (包含了父类的方法也包含Object类)。 |
public Method[] getDeclaredMethods() | 获取当前Class所表示类的所有成员方法, 包括私有的(不包括继承的,和访问权限无关)。 |
public Method getMethod (String name, Class... parameterTypes) | 获取当前Class所表示类的指定的public方法 (包括继承的)。 |
public Method getDeclaredMethod (String methodName, Class... parameterTypes) | 获取当前Class所表示类的指定的成员方法 (不包括继承的)。 参数 methodName:方法名, Class ... parameterTypes: 形参的Class类型对象 |
3、Java 反射使用实例
1)获取类名、修饰符和包信息
import java.lang.reflect.Modifier; public class Main { public static void main(String[] args) { Class<?> clazz = Sample.class; // 获取类名和修饰符 System.out.println("getName: " + clazz.getName() + "\tgetSimpleName: " + clazz.getSimpleName()); int mod = clazz.getModifiers(); System.out.println("Modifier.isPublic: " + Modifier.isPublic(mod) + "\tModifier.isProtected: " + Modifier.isProtected(mod)); // 获取包信息 System.out.println("getPackage: " + clazz.getPackage()); } } class Sample { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } }
2)获取父类和接口信息
public class Main { public static void main(String[] args) { Class<?> clazz = Sample.class; // 获取父类和实现的接口 System.out.println("getSuperclass: " + clazz.getSuperclass()); System.out.println("getInterfaces: " + clazz.getInterfaces().length); } } class Sample { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } }
3)获取构造方法和所有方法
import java.lang.reflect.Method; public class Main { public static void main(String[] args) { Class<?> clazz = Sample.class; // 获取构造方法 System.out.println("getConstructors: " + clazz.getConstructors().length); // 获取并打印所有方法 Method[] methods = clazz.getMethods(); System.out.println("getMethods: " + methods.length); for (Method method : methods) { System.out.println("Method: " + method.getName()); } } } class Sample { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } }
4)调用特定方法
import java.lang.reflect.Method; public class Main { public static void main(String[] args) throws Exception { Sample s = new Sample(); s.setProp1("cjavapy.com"); Class<?> clazz = Sample.class; // 调用特定方法 Method getProp1Method = clazz.getMethod("getProp1"); System.out.println("getProp1: " + getProp1Method.invoke(s)); // 调用带参数的 setter 方法 Method setProp3Method = clazz.getMethod("setProp3", Double.class); setProp3Method.invoke(s, 2.0); } } class Sample { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } }
5)获取和修改字段的值
import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws Exception { Sample s = new Sample(); s.setProp1("cjavapy.com"); Class<?> clazz = Sample.class; // 获取字段并设置值 Field[] fields = clazz.getDeclaredFields(); System.out.println("getDeclaredFields: " + fields.length); for (Field field : fields) { field.setAccessible(true); field.set(s, null); // 设置字段值为 null System.out.println("Field: " + field.getName() + " = " + field.get(s)); } } } class Sample { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } }
6)获取类的注解
import java.lang.annotation.Annotation; public class Main { public static void main(String[] args) { Class<?> clazz = Sample.class; // 获取类注解 Annotation[] annotations = clazz.getAnnotations(); System.out.println("getAnnotations: " + annotations.length); } } class Sample { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } }
7)使用反射调用 ArrayList对象的add方法
import java.lang.reflect.Method; import java.util.ArrayList; public class Main { public static void main(String[] args) throws Exception{ ArrayList list = new ArrayList<>(); list.add("Java"); list.add("CJavaPy"); //获取ArrayList的Class对象,调用add()方法,添加数据 Class listClass = list.getClass(); //得到 list对象的字节码对象 //获取add()方法 Method m = listClass.getMethod("add", Object.class); //调用add()方法 m.invoke(list, "https://www.cjavapy.com"); //可以通过反射越过泛型检查的,添加整型的值 m.invoke(list,11); //遍历集合 for(Object obj : list){ System.out.println(obj); } } }
8)使用反射为对象赋值
import java.lang.reflect.Field; public class Main { private String prop1; private Integer prop2; private Double prop3; public String getProp1() { return prop1; } public void setProp1(String prop1) { this.prop1 = prop1; } public Integer getProp2() { return prop2; } public void setProp2(Integer prop2) { this.prop2 = prop2; } public Double getProp3() { return prop3; } public void setProp3(Double prop3) { this.prop3 = prop3; } public static Object setClassValue(Object source, Object target) { try { Field[] sourceFields = source.getClass().getDeclaredFields(); Field[] targetFields = target.getClass().getDeclaredFields(); for (Field sourceField : sourceFields) { sourceField.setAccessible(true); for (Field targetField : targetFields) { if (sourceField.getName().equals(targetField.getName())) { targetField.setAccessible(true); targetField.set(target, sourceField.get(source)); break; } } } return target; } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String[] args) { try { Main source = new Main(); source.setProp1("Java"); source.setProp2(11); source.setProp3(22.00); Main target = new Main(); setClassValue(source, target); System.out.println(target.getProp1() + " " + target.getProp2() + " " + target.getProp3()); } catch (Exception e) { e.printStackTrace(); } } }