反射的简单使用
查考文章
整理Java反射常用方法 https://blog.youkuaiyun.com/github_35180164/article/details/52037112
深入解析Java反射(1) - 基础 https://www.sczyh30.com/posts/Java/java-reflection-1/
反射是什么
反射:允许任意一个类在运行时获取自身的类信息,并且可以操作这个类的方法和属性。这种动态获取类信息和动态调用对象方法的功能称为Java的反射机制。
为什么要用反射
通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。
反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁
反射可以降低程序耦合性,提高程序的灵活性
反射常用类
java.lang.reflect.Constructor<T>
:与构造函数相关的反射java.lang.reflect.Field
:与字段相关的反射java.lang.reflect.Method
:与方法相关的反射java.lang.reflect.Modifier
:与修饰符相关的反射
反射常用方法
-
Field相关
- Class.getDeclaredFields() : 获取当前类所有的(包括私有)字段
- Class.getDeclaredField(String) : 获取单个字段(包括私有)
- Class.getFields() : 获取当前类所有的(不包括私有)字段
- Class.getField(String) : 获取单个字段(不包括私有)
-
Method相关
- Class.getDeclaredMethods() : 获取类本身的所有方法,包括公有、保护、私有
- Class.getDeclaredMethod(String, Class[]) : 获取类本身的指定方法,包括公有、保护、私有
- Class.getMethods() : 获取类本身和其所有父类的公有和保护方法
- Class.getMethod(String, Class[]) : 获取类本身和其所有父类指定的公有和保护方法
反射的运用
- 测试 user 类
public class User {
private String username;
private String password;
public User() {
super();
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private String privateMethod(String str) {
return "这是调用私有方法:" + str;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}
获得 Class 对象三种方法
- 使用 Class.forName 静态方法:
public static Class<?> forName(String className)
例如:
try {
Class<?> userClass = Class.forName("com.test.User");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
- 调用对象的 class
Class<?> userClass = User.class;
- 调用某个对象的 getClass() 方法
User user = new User();
Class<? extends User> userClass = user.getClass();
创建对象实例
@Test
public void run(){
try {
Class<?> userClass = Class.forName("com.test.User");
// 直接使用Class.newInstance()方法来创建Class对象的无参构造生成实例对象
User user1 = (User) userClass.newInstance();
user1.setUsername("小茗");
user1.setPassword("123ABC");
System.out.println("无参构造生成实例对象: " + user1.toString());
// 使用 java.lang.reflect.Constructor 类生成有参构造生成实例对象
// getConstructor(Class... arg0) 参数为Java的可变参数 传入类型为 java.lang.Class 类型
Constructor<?> constructor = userClass.getConstructor(String.class, String.class);
User user2 = (User) constructor.newInstance("小黄", "ABC123");
System.out.println("有参构造生成实例对象 : " + user2.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
结果:
操作方法
获取方法的属性
@Test
public void run() {
try {
Class<?> userClass = Class.forName("com.redis.test.User");
// 获取类本身的所有方法,包括公有、保护、私有
Method[] methods = userClass.getDeclaredMethods();
// 获取类本身和其所有父类的公有和保护方法
// Method[] methods = userClass.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
//
System.out.println("方法修饰符未转义前: " + methods[i].getModifiers());
System.out.println("方法修饰符转义后: " + Modifier.toString(methods[i].getModifiers()));
System.out.println("获取方法名: " + methods[i].getName());
System.out.println("获取方法参数列表变量数量: " + methods[i].getParameterCount());
// 获取参数列表类型
Class<?>[] types = methods[i].getParameterTypes();
System.out.print("获取方法参数列表变量类型: ");
for (int j = 0; j < types.length; j++) {
System.out.print(types[j].getName() + ",");
}
System.out.println();
System.out.println();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
- 结果
通过反射对方法操作
@Test
public void run() {
try {
Class<?> userClass = Class.forName("com.redis.test.User");
// 通过反射 调用非私有方法 set 方法为其赋值
User user = (User) userClass.newInstance();
Method setUsernameMethod = userClass.getMethod("setUsername", String.class);
Method setPasswordMethod = userClass.getMethod("setPassword", String.class);
setUsernameMethod.invoke(user, "小茗");
setPasswordMethod.invoke(user, "123ABC");
System.out.println("调用对象获取值: " + user.toString());
// 通过反射 调用非私有方法 get 方法获取所赋的值
Method getUsernameMethod = userClass.getMethod("getUsername");
Method getPasswordMethod = userClass.getMethod("getPassword");
String username = (String) getUsernameMethod.invoke(user);
String password = (String) getPasswordMethod.invoke(user);
System.out.println("通过反射 调用getter方法获取值: username=" + username + ", password=" + password);
// 通过反射为私有属性赋值
// 使用 getMethod 方法不能找到私有方法,否则会报 java.lang.NoSuchMethodException
Method privateMethod = userClass.getDeclaredMethod("privateMethod", String.class);
// 该方法是private的,需要调用该方法的 f.setAccessible(true); 才能读取和修改该方法。 否则会报
// java.lang.IllegalAccessException:
privateMethod.setAccessible(true);
String value = (String) privateMethod.invoke(user, "ABCD");
System.out.println("通过反射 调用private修饰的方法: " + value);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
- 结果
字段信息
字段属性信息
@Test
public void run() {
try {
Class<?> userClass = Class.forName("com.redis.test.User");
// 获取类本身的所有字段,包括公有、保护、私有
Field[] declaredFields = userClass.getDeclaredFields();
// 获取类本身和其所有父类的公有和保护字段
// Field[] declaredFields = userClass.getFields();
// 获取属性的类型
for (int i = 0; i < declaredFields.length; i++) {
System.out.println("属性修饰符未转义前: " + declaredFields[i].getModifiers());
System.out.println("属性修饰符转义后: " + Modifier.toString(declaredFields[i].getModifiers()));
System.out.println("获取属性类型: " + declaredFields[i].getType().getName());
System.out.println("获取属性类型: " + declaredFields[i].getType().getSimpleName());
System.out.println("获取属性名: " + declaredFields[i].getName());
System.out.println();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
- 结果
字段属性操作
@Test
public void run6() {
try {
Class<?> userClass = Class.forName("com.redis.test.User");
// 创建User实例
User user = (User) userClass.newInstance();
Field usernameField = userClass.getDeclaredField("username");
// 该字段是private的,需要调用该字段的 f.setAccessible(true); 才能读取和修改该字段。 否则会报
// java.lang.IllegalAccessException:
usernameField.setAccessible(true);
usernameField.set(user, "晓明");
Field passwordField = userClass.getDeclaredField("password");
// 该字段是private的,需要调用该字段的 f.setAccessible(true); 才能读取和修改该字段。 否则会报
// java.lang.IllegalAccessException:
passwordField.setAccessible(true);
passwordField.set(user, "123abc");
System.out.println(user);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
- 结果
使用反射创建JavaBean
- 创建简单 JavaBean
public class User {
private String username;
private String password;
public User() {
super();
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}
- 创建 JavaBean 反射类
import java.lang.reflect.Field;
/**
* 获取 javaBean 并使用反射重新生成
*
*/
public class ReflectClass {
public static void main(String[] args) throws ClassNotFoundException {
// 加载需要被反射的类
Class<?> forName = Class.forName("com.redis.test.User");
// 获取所有字段(包括私有的变量)
Field[] declaredFields = forName.getDeclaredFields();
StringBuffer sb = new StringBuffer();
sb.append("public class User {\n");
// 拼接 字段
for (int i = 0; i < declaredFields.length; i++) {
sb.append("\t");
sb.append(java.lang.reflect.Modifier.toString(declaredFields[i].getModifiers()));
sb.append(" ");
sb.append(declaredFields[i].getType().getSimpleName());
sb.append(" ");
sb.append(declaredFields[i].getName());
sb.append(";");
sb.append("\n");
}
sb.append("\n");
// 拼接GET SET 方法
for (int i = 0; i < declaredFields.length; i++) {
// 将字段转换为首字母大写
char[] cs=declaredFields[i].getName().toCharArray();
cs[0]-=32;
// 拼接GET 方法
sb.append("\tpublic ").append(declaredFields[i].getType().getSimpleName()).append(" get").append(String.valueOf(cs)).append("(){").append("\n");
sb.append("\t\t");
sb.append("return this.").append(declaredFields[i].getName()).append(";");
sb.append("\n\t");
sb.append("}");
sb.append("\n");
// 拼接SET 方法
sb.append("\tpublic void set").append(String.valueOf(cs)).append("("+declaredFields[i].getType().getSimpleName()+" "+declaredFields[i].getName()).append("){").append("\n");
sb.append("\t\t");
sb.append("this.").append(declaredFields[i].getName()).append(" = " ).append(declaredFields[i].getName()).append(";");
sb.append("\n\t");
sb.append("}");
sb.append("\n");
}
sb.append("}");
System.out.print(sb.toString());
}
}
- 控制台打印结果