一、反射
1.1 反射介绍
Java反射:在编译时不确定哪个类被加载,而在程序运行时才加载、探知、使用
1.1.1 Java 程序的运行过程
1.1.2 反射及其作用
反射是指能够在运行时,观察并修改自己运行时(Runtime)行为的特性 Java 反射机制主要提供了以下的一些功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的属性和方法
- 在运行时调用任意一个对象的方法
1.2 反射技术常用 API
- java.lang.Class 类可获取类和类的成员信息
- java.lang.reflect.Constructor 类可调用类的构造方法
- java.lang.reflect.Field 类可访问类的属性
- java.lang.reflect.Method 类可调用类的方法
1.2.1 使用反射的基本步骤
- 导入
java.lang.reflect.*
- 获得需要操作的类的 java.lang.Class 对象
- 调用Class的方法获取 Field、Method 等对象
- 使用反射 API 操作实例成员
1.3 反射的入口类 Class
Class 类是 Java 反射机制的起源和入口
- 每个类都有自己向关的 Class 对象
- 提供了获取类信息的相关方法
Class 类存放类的结构信息
- 类名
- 父类﹑接口
- 构造方法﹑方法﹑属性
- 注解
- ……
1.3.1 获取 Class 实例
获取 Class 实例的常用方式
// 方法1:对象.getClass()
Class clazz = new Student().getClass();
// 方法2:类.class
Class clazz = Student.class;
// 方法3:Class.forName()
Class clazz = Class.forName("xxx.xxx.Student");
// 方法4:基本数据类型包装类.TYPE
Class<Integer> clazz = Integer.TYPE;
1.4 反射获取信息
1.4.1 获取类的基本信息
方法 | 说明 |
---|---|
String getName() | 以字符串形式返回该类型的名称 |
String getSimpleName() | 以字符串形式返回该类型的简称 |
Package getPackage() | 获取该类型所在的包 |
Class getSuperclass() | 返回该类型的超类的 Class 实例 |
Class[] getInterfaces() | 返回该类型所实现的全部接口的 Class 实例 |
int getModifiers() | 返回该类型的所有修饰符,由 public、protected、private、final、staic、abstract 等对应的 int 常量组成,返回的整数应使用 Modifier 工具类来解码,才可以判断修饰符的构成 |
Class[] getDeclaredClasses() | 返回该类型中包含的全部内部类的 Class 实例 |
Class getDeclaringClass() | 返回该类型所在的外部类的 Class 实例 |
- 演示案例
public class Xz01 {
public static void main(String[] args) throws ClassNotFoundException {
Class<Student> c1 = Student.class;
Class<?> c2 = new Student().getClass();
Class<?> c3 = Class.forName("xuanzi.Student");
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c1 == c2);
// hashCode 编码以及 内存地址一致表示同一个 Class 对象
System.out.println("获取全类名(包含包路径):" + c1.getName());
System.out.println("获取类名(仅类名称):" + c1.getSimpleName());
System.out.println("获取包名(仅包名):" + c1.getPackage().getName());
System.out.println("获取类加载器:" + c1.getClassLoader());
System.out.println("获取父类路径:" + c1.getSuperclass().getName());
System.out.println("获取类访问修饰符:" + c1.getModifiers());
System.out.println("表示 PUBLIC:" + Modifier.PUBLIC);
}
}
// 1324119927
// 1324119927
// 1324119927
// true
// 获取全类名(包含包路径):xuanzi.Student
// 获取类名(仅类名称):Student
// 获取包名(仅包名):xuanzi
// 获取类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
// 获取父类路径:java.lang.Object
// 获取类访问修饰符:1
// 表示 PUBLIC:1
1.4.2 获取构造方法信息
方法 | 说明 |
---|---|
Constructor getConstructor(Class… params) | 返回该类型指定参数列表的 public 构造方法,构造方法的参数列表与 params 所指定的类型列表所匹配 |
Constructor[] getConstructors() | 返回该类型的所有 public 构造方法 |
Constructor getDeclaredConstructor(Class… params) | 返回该类型的指定参数列表的构造方法,访问级别不限 |
Constructor[] getDeclaredConstructors() | 返回该类型的所有构造方法,访问级别不限 |
- 演示案例
public class Xz02 {
public static void main(String[] args) throws NoSuchMethodException {
Class<Student> c1 = Student.class;
Constructor<Student> constructor = c1.getConstructor();
Constructor<?>[] constructors = c1.getConstructors();
Constructor<Student> declaredConstructor = c1.getDeclaredConstructor();
Constructor<?>[] declaredConstructors = c1.getDeclaredConstructors();
Constructor<?> declaredConstructors1 = c1.getDeclaredConstructor(String.class);
System.out.println(constructor);
System.out.println(Arrays.toString(constructors));
System.out.println(declaredConstructor);
System.out.println(Arrays.toString(declaredConstructors));
System.out.println(declaredConstructors1);
System.out.println("================================");
for (Constructor<?> cc : declaredConstructors) {
int modifier = cc.getModifiers();
String xiu = "";
if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) {
xiu = "PUBLIC";
} else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) {
xiu = "PROTECTED";
} else if ((modifier & Modifier.FINAL) == Modifier.FINAL) {
xiu = "FINAL";
} else if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
xiu = "ABSTRACT";
} else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) {
xiu = "PRIVATE";
} else {
xiu = "未知";
}
System.out.println(xiu);
}
System.out.println("================================");
Class<?>[] parameterTypes = declaredConstructors1.getParameterTypes();
if (parameterTypes.length == 0) {
System.out.println("无参");
} else {
for (int i = parameterTypes.length - 1; i >= 0; i--) {
System.out.println(parameterTypes[i].getSimpleName());
}
}
System.out.println("================================");
}
}
// public xuanzi.Student()
// [public xuanzi.Student(java.lang.String,int,char), public xuanzi.Student()]
// public xuanzi.Student()
// [public xuanzi.Student(java.lang.String,int,char), public xuanzi.Student(), protected xuanzi.Student(java.lang.String), private xuanzi.Student(java.lang.String,int)]
// protected xuanzi.Student(java.lang.String)
// ================================
// PUBLIC
// PUBLIC
// PROTECTED
// PRIVATE
// ================================
// String
// ================================
1.4.3 获取属性信息
方法 | 说明 |
---|---|
Field getField(String name) | 返回该类型中指定名称的 public 属性,name 参数用于指定属性名称 |
Field[] getFields() | 返回该类型中所有 public 属性 |
Field getDeclaredField(String name) | 返回该类型中指定名称的属性,与属性的访问级别无关 |
Field[] getDeclaredFields() | 返回该类型中的全部属性,与属性的访问级别无关 |
- 演示案例
public class Xz03 {
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
Class<Student> c1 = Student.class;
Field[] fields = c1.getFields();
Field name = c1.getField("name");
Field declaredName = c1.getDeclaredField("name");
Field[] declaredFields = c1.getDeclaredFields();
System.out.println(Arrays.toString(fields));
System.out.println(name);
System.out.println(declaredName);
System.out.println(Arrays.toString(declaredFields));
System.out.println("================================");
for (Field df : declaredFields) {
int modifier = df.getModifiers();
String xiu = "";
if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) {
xiu = "PUBLIC";
} else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) {
xiu = "PROTECTED";
} else if ((modifier & Modifier.FINAL) == Modifier.FINAL) {
xiu = "FINAL";
} else if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
xiu = "ABSTRACT";
} else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) {
xiu = "PRIVATE";
} else {
xiu = "未知";
}
System.out.println(xiu);
}
System.out.println("================================");
for (Field declaredField : declaredFields) {
System.out.print(declaredField.getModifiers() + " - ");
System.out.print(declaredField.getName() + " - ");
System.out.print(declaredField.getType() + " - ");
System.out.println();
}
System.out.println("================================");
}
}
// [public java.lang.String xuanzi.Student.name, public int xuanzi.Student.age]
// public java.lang.String xuanzi.Student.name
// public java.lang.String xuanzi.Student.name
// [public java.lang.String xuanzi.Student.name, public int xuanzi.Student.age, private char xuanzi.Student.gender]
// ================================
// PUBLIC
// PUBLIC
// PRIVATE
// ================================
// 1 - name - class java.lang.String -
// 1 - age - int -
// 2 - gender - char -
// ================================
1.4.4 获取方法信息
方法 | 说明 |
---|---|
Method getMethod(String name, Class… params) | 返回该实例中指定的 public 方法,name 参数用于指定方法名称,params 参数指定参数列表 |
Method[] getMethods() | 返回该实例中所有 public 方法 |
Method getDeclaredMethod(String name, Class… params) | 返回该实例中指定的方法,与方法的访问级别无关 |
Method[] getDeclaredMethods() | 返回该实例中的全部方法,与方法的访问级别无关 |
- 演示案例
public class Xz04 {
public static void main(String[] args) throws NoSuchMethodException {
Class<Student> c1 = Student.class;
Method[] methods = c1.getMethods();
Method getStudent = c1.getMethod("setName", String.class);
Method[] declaredMethods = c1.getDeclaredMethods();
Method declaredMethod = c1.getDeclaredMethod("getGender");
System.out.println(getStudent);
System.out.println(Arrays.toString(methods));
System.out.println(Arrays.toString(declaredMethods));
System.out.println(declaredMethod);
System.out.println("================================");
for (Method dm : declaredMethods) {
int modifier = dm.getModifiers();
String xiu = "";
if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) {
xiu = "PUBLIC";
} else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) {
xiu = "PROTECTED";
} else if ((modifier & Modifier.FINAL) == Modifier.FINAL) {
xiu = "FINAL";
} else if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
xiu = "ABSTRACT";
} else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) {
xiu = "PRIVATE";
} else {
xiu = "未知";
}
System.out.println(xiu);
}
System.out.println("================================");
for (Method declaredField : declaredMethods) {
System.out.print((declaredField.getModifiers() == Modifier.PUBLIC ? "PUBLIC" : "PRIVATE") + " - ");
System.out.print(declaredField.getName() + " - ");
System.out.print(declaredField.getReturnType().getSimpleName() + " - ");
System.out.print(Arrays.toString(declaredField.getParameterTypes()) + " - ");
System.out.print(Arrays.toString(declaredField.getExceptionTypes()) + " - ");
System.out.println();
}
System.out.println("================================");
}
}
// public void xuanzi.Student.setName(java.lang.String)
// [public java.lang.String xuanzi.Student.getName(), public java.lang.String xuanzi.Student.toString() throws java.lang.IllegalArgumentException,java.lang.ArithmeticException, public void xuanzi.Student.setName(java.lang.String), public int xuanzi.Student.getAge(), public void xuanzi.Student.setAge(int), public void xuanzi.Student.setGender(char), public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]
// [public java.lang.String xuanzi.Student.getName(), public java.lang.String xuanzi.Student.toString() throws java.lang.IllegalArgumentException,java.lang.ArithmeticException, public void xuanzi.Student.setName(java.lang.String), private char xuanzi.Student.getGender(), public int xuanzi.Student.getAge(), public void xuanzi.Student.setAge(int), private java.lang.String xuanzi.Student.show(java.lang.String,int,char), public void xuanzi.Student.setGender(char)]
// private char xuanzi.Student.getGender()
// ================================
// PUBLIC
// PUBLIC
// PUBLIC
// PRIVATE
// PUBLIC
// PUBLIC
// PRIVATE
// PUBLIC
// ================================
// PUBLIC - getName - String - [] - [] -
// PUBLIC - toString - String - [] - [class java.lang.IllegalArgumentException, class java.lang.ArithmeticException] -
// PUBLIC - setName - void - [class java.lang.String] - [] -
// PRIVATE - getGender - char - [] - [] -
// PUBLIC - getAge - int - [] - [] -
// PUBLIC - setAge - void - [int] - [] -
// PRIVATE - show - String - [class java.lang.String, int, char] - [] -
// PUBLIC - setGender - void - [char] - [] -
// ================================
1.5 反射实例化对象
1.5.1 通过反射实现类的实例化
- java.lang.Class
Student student = Student.class.newInstance();
// 通过 class 获取对象
- java.lang.reflect.Constructor
Student student = Student.class.getConstructor().newInstance();
// 通过构造获取对象
- 演示案例
public class Xz05 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Student student = new Student();
// 直接 new 对象
Student student1 = Student.class.newInstance();
// 通过 class 获取对象
Student student2 = Student.class.getConstructor().newInstance();
// 通过构造获取对象
Constructor<Student> studentConstructor = Student.class.getConstructor(String.class, char.class);
studentConstructor.setAccessible(true);
// 通过有参构造获取对象
Student student3 = studentConstructor.newInstance("XuanZi", '男');
Constructor<Student> studentConstructor1 = Student.class.getDeclaredConstructor(String.class, int.class);
studentConstructor1.setAccessible(true);
// 可设置私有构造函数
Student student4 = studentConstructor1.newInstance("XuanZi", 12);
System.out.println(student);
System.out.println(student1);
System.out.println(student2);
System.out.println(student3);
System.out.println(student4);
}
}
// xuanzi.Student{name='null', age=0, gender= }
// xuanzi.Student{name='null', age=0, gender= }
// xuanzi.Student{name='null', age=0, gender= }
// xuanzi.Student{name='XuanZi', age=0, gender=男}
// xuanzi.Student{name='XuanZi', age=12, gender= }
1.5.2 通过反射访问实例的字段
java.lang.reflect.Field
方法 | 说明 |
---|---|
xxx getXxx(Object obj) | xxx 表示8种基本数据类型之一,若 Field 实例表示的是一个静态属性,则 obj 可以设置为 null |
Object get(Object obj) | 以 Object 类型返回 obj 中相关属性的值 |
void setXxx(Object obj, xxx val) | 将 obj 中相关属性的值设置为 val。xxx 为8种基本数据类型之一 |
void set(Object obj, Object val) | 将 obj 中相关属性的值设置为 val |
void setAccessible(boolean flag) | 对相关属性设置访问权限。设置为 true 可以禁止 Java 语言访问检查 |
- 演示案例
public class Xz06 {
public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
Field name = studentClass.getField("name");
System.out.println(name.get(student));
name.set(student, "玄子");
System.out.println(name.get(student));
}
}
// null
// 玄子
1.5.3 通过反射调用实例的方法
java.lang.reflect.Method
public Object invoke( Object obj, Object... args )
- Object:返回值
- Object obj:执行该方法的对象
- Object… args:执行该方法时传入的参数
- 演示案例
public class Xz07 {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
Method name = studentClass.getMethod("setName", String.class);
name.invoke(student, "张三");
System.out.println(student);
}
}
// xuanzi.Student{name='张三', age=0, gender= }
1.6 反射的优缺点
1.6.1 优点
- 允许程序创建和控制任何类的对象,无需提前硬编码目标类
- 提高了 Java 程序的灵活性和扩展性,降低了耦合性,提高自适应能力
- 反射的应用领域:开源框架,如 MyBatis、Spring 等
1.6.2 缺点
- 性能问题:反射机制主要应用在对灵活性和扩展性要求很高的系统框架上
- 代码维护问题:反射会模糊程序内部逻辑,可读性较差,且反射可能会破坏封装