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();
}
}
}