目录
引言
一、概述
二、获取Class对象
三、反射获取构造方法
代码示例:
四、反射获取成员变量
代码示例:
五、反射获取成员方法
代码示例:
结语
引言
Java中的反射(Reflection)是一种强大的机制,允许程序在运行时检查和操作其结构和行为。通过反射,程序可以动态地获取类的信息、调用方法、访问字段和创建对象。
一、概述
反射提供了一种在运行时检查类、接口、字段和方法的能力。通过反射,程序可以动态地:
- 获取类的所有属性和方法。
- 创建类的实例。
- 调用类的方法。
- 修改类的字段值。
二、获取Class对象
在Java中,Class对象表示类和接口的元数据。获取Class对象有三种主要方式:
通过类名获取:
Class<?> clazz = MyClass.class;
通过对象获取:
MyClass obj = new MyClass();
Class<?> clazz = obj.getClass();
通过全限定类名获取(使用Class.forName):
try {
Class<?> clazz = Class.forName("com.example.MyClass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
注意:一般来说反射创建class对象通过全限定类名获取最为常用,其第一种通过类名获取常用作为参数来传递,例如:synchronized(类名.class){} 中的锁对象常用这种方式指定。
三、反射获取构造方法
方法名 | 说明 |
---|---|
Constructor<?>[] getConstructors() | 获得所有的构造(只能public修饰) |
Constructor<?>[] getDeclaredConstructors() | 获得所有的构造(包含private修饰) |
Constructor<T> getConstructor(Class<?>... parameterTypes) | 获取指定构造(只能public修饰) |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 获取指定构造(包含private修饰) |
newInstance | 创建对象 |
setAccessible | 临时取消权限检验 |
其代码中所用到的Paper类:
import java.io.IOException;
public class Paper {
private String name;
private int age;
public String address;
public String getAddress() {
return address;
}
public Paper(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public void setAddress(String address) {
this.address = address;
}
public Paper() {
}
public Paper(String name, int age) {
this.name = name;
this.age = age;
}
private Paper(String name) {
this.name = name;
}
protected Paper(int age) {
this.age = age;
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
this.age = age;
}
private String eat(String something) throws IOException,NullPointerException,ClassCastException {
System.out.println("在吃" + something);
return "吃饱了";
}
private void sleep() {
System.out.println("正在睡觉");
}
public String toString() {
return "Paper{name = " + name + ", age = " + age + "}";
}
}
代码示例:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectConstructor {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取class对象
Class<?> aClass = Class.forName("com.pjk.a1024reflect.Paper");
//获取构造方法
//1.获取所有的公共构造方法
Constructor<?>[] cons1 = aClass.getConstructors();
for (Constructor<?> constructor : cons1) {
System.out.println(constructor);
}
//2.获取所有的构造方法
Constructor<?>[] cons2 = aClass.getDeclaredConstructors();
for (Constructor<?> constructor : cons2) {
System.out.println(constructor);
}
//3.获取单个的公共构造方法
// ()代表无参
// (String.class)代表带一个String参数的有参构造
Constructor<?> con1 = aClass.getConstructor();
System.out.println(con1);
//4.获取单个的构造方法
Constructor<?> con2 = aClass.getDeclaredConstructor(String.class);
System.out.println(con2);
Constructor<?> con3 = aClass.getDeclaredConstructor(int.class);
System.out.println(con3);
System.out.println(con2.getName());
System.out.println(con2.getModifiers());
System.out.println("-------------------------------------------------");
//利用获取出来的构造方法创建对象
//1.利用公共构造创建对象
Paper p1 = (Paper) con1.newInstance();
System.out.println(p1);
//2.利用非公共构造创建对象
//暴力反射:表示临时取消权限检验
con2.setAccessible(true);
Paper p2 = (Paper) con2.newInstance("zhangsan");
System.out.println(p2);
Paper p3 = (Paper) con3.newInstance(18);
System.out.println(p3);
}
}
四、反射获取成员变量
方法名 | 说明 |
---|---|
Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的) |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 获取值 |
setAccessible | 临时取消权限检验 |
代码示例:
import java.lang.reflect.Field;
public class ReflectField {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//获取class对象
Class<?> aClass = Class.forName("com.pjk.a1024reflect.Paper");
//利用反射获取成员变量
//1.获取所有公共成员变量
Field[] fields1 = aClass.getFields();
for (Field field : fields1) {
System.out.println(field);
}
//2.获取所有成员变量
Field[] fields2 = aClass.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}
//3.获取单个公共成员变量
Field address = aClass.getField("address");
System.out.println(address);
//4.获取单个成员变量
Field name = aClass.getDeclaredField("name");
System.out.println(name);
//获取成员变量的修饰符
System.out.println(name.getModifiers());
//获取成员变量记录的值
Paper p = new Paper("洁柔", 10, "广东");
//暴力反射:表示临时取消权限检验
name.setAccessible(true);
String n = (String) name.get(p);
System.out.println(n);
//修改对象里面记录的值
name.set(p, "维达");
System.out.println(p);
}
}
五、反射获取成员方法
方法名 | 说明 |
---|---|
Method[] getMethods() | 返回所有成员方法对象的数组(只能拿public的) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象(只能拿public的) |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
Object invoke(Object obj, Object... args) | 运行方法 |
setAccessible | 临时取消权限检验 |
注意:其中getMethods()获取成员方法时,包含了其父类的所有public公共方法。
代码示例:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class ReflectMethod {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//获取class对象
Class<?> aClass = Class.forName("com.pjk.a1024reflect.Paper");
//利用反射获取成员方法
//1.获取所有公共成员方法(包含父类的公共成员方法)
Method[] methods1 = aClass.getMethods();
for (Method method : methods1) {
System.out.println(method);
}
//2.获取所有的方法
Method[] methods2 = aClass.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(method);
}
//3.获取单个方法
Method method = aClass.getDeclaredMethod("eat", String.class);
//获取方法的形参
Parameter[] parameters = method.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//获取方法抛出的异常
Class<?>[] exceptionTypes = method.getExceptionTypes();
for (Class<?> exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
//方法运行
/*
* invoke:运行方法
* invoke(Object obj,Object... args)
* 参数一:用obj对象调用该方法
* 参数二:调用方法所需形参(没有就不写)
* */
Paper p = new Paper("洁柔", 10, "东莞");
method.setAccessible(true);
String kfc = (String) method.invoke(p, "KFC");
System.out.println(kfc);
}
}
结语
- 性能:反射通常比直接代码调用慢,因为它涉及额外的检查和类型转换。
- 安全性:反射可以绕过Java的访问控制机制,可能导致意外的副作用或安全问题。
- 异常处理:反射操作可能抛出多种检查异常(如ClassNotFoundException、NoSuchMethodException、IllegalAccessException等),需要妥善处理。
掌握反射,Java开发者可以编写更加灵活和动态的代码,但也需要谨慎使用,以避免潜在的性能和安全问题。