开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
反射(Reflection)的定义
学习反射之前首先知道两个概念:
**编译期:**把代码交给编译器编程成计算机可以执行的文件的过程。在java里就是把java代码编译成class文件的过程。编译期可以简单理解为未翻译,把人能看懂的东西翻译成jvm虚拟机可以看懂的东西;
运行期: 把编译后的文件交给计算机执行,直到程序运行结束。
java反射机制 是指在运行期过程中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象都能够调用它的任意方法和属性;
其实java本身的“封装”特性是让外部不要访问私有类或者私有属性,但是反射机制就违背了这一原则;其实这就是一个工具,工具就看怎么用了
反射使用的API
- Field类: 提供有关类的属性信息,以及对它的动态访问权限,一个封装反射类的属性的类
- Method类: 提供类的方法的信息,包括抽象方法,一个用来封装反射类方法的一个类
- Class类: 正在运行的java应用程序中的类的实例
- Constructor类:获取有关类的构造方法的信息
实例演示
基础User对象类
public class User {
/**
* 用户姓名
*/
private String userName;
/**
* 用户密码
*/
private String password;
/**
* 用户年龄
*/
public int age;
public User(String userName, String password, int age) {
this.userName = userName;
this.password = password;
this.age = age;
}
public User(){
}
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;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String run(String param){
System.out.println("这是一个私有函数");
return "runrun";
}
}
获取Class对象的三种方式
public static void main(String[] args) {
try {
//1、通过完整路径名获取class对象
Class userClass1 = Class.forName("com.xxx.yyy.core.model.policy.User");
System.out.println(userClass1);
//2、通过类的class属性
Class userClass2 = User.class;
System.out.println(userClass2);
//3、通过对象的getClass方法
User user = new User();
Class userClass3 = user.getClass();
System.out.println(userClass3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
获取成员变量属性
public static void main(String[] args) {
try {
//通过完整路径名获取class对象
Class userClass1 = Class.forName("com.xxx.yyy.core.model.policy.User");
//获取字段有两个API方法:getDeclaredFields 和 getFields.
//getDeclaredFields() 获取所有声明的字段(公有and 私有)
//getFields()仅获取公有字段
Field[] fields = userClass1.getDeclaredFields();
for (Field field : fields){
System.out.println("结果字段:"+field);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
输出结果
结果字段:private java.lang.String com.xxx.yyy.core.model.policy.User.userName
结果字段:private java.lang.String com.xxx.yyy.core.model.policy.User.password
结果字段:public int com.xxx.yyy.core.model.policy.User.age
获取构造方法
public static void main(String[] args) {
try {
//通过完整路径名获取class对象
Class userClass1 = Class.forName("com.xxx.yyy.core.model.policy.User");
//获取构造方法同样包含了两个 API:用于获取所有构造方法的 getDeclaredConstructors和用于获取公有构造方法的getConstructors
Constructor[] constructors = userClass1.getDeclaredConstructors();
for (Constructor constructor : constructors){
System.out.println("构造方法:"+ constructor);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
输出结果
构造方法:public com.xxx.yyy.core.model.policy.User(java.lang.String,java.lang.String,int)
构造方法:public com.xxx.yyy.core.model.policy.User()
获取成员方法
public static void main(String[] args) {
try {
//通过完整路径名获取class对象
Class userClass1 = Class.forName("com.xxx.yyy.core.model.policy.User");
//获取成员方法的两个 API 是:获取所有声明的非构造函数的 getDeclaredMethods 和仅获取公有非构造函数的 getMethods:
Method[] methods = userClass1.getDeclaredMethods();
for (Method method : methods){
System.out.println("获取的成员方法:"+ method.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
输出结果
获取的成员方法:run
获取的成员方法:setAge
获取的成员方法:setUserName
获取的成员方法:getAge
获取的成员方法:setPassword
获取的成员方法:getUserName
获取的成员方法:getPassword
实践、利用反射获取属性字段并赋值调用方法等
public static void main(String[] args) {
try {
//通过完整路径名获取class对象
Class userClass1 = Class.forName("com.alipay.mrcher.core.model.policy.User");
Constructor constructor = userClass1.getConstructor(String.class,String.class,int.class);
constructor.setAccessible(true);//私有方法可使用
//利用方法的newInstance方法创建对象,传入构造方法所需要的参数,
Object user = constructor.newInstance("xq","xq",19);
//获取字段 并赋值
Field nameField = userClass1.getDeclaredField("userName");
nameField.setAccessible(true);
nameField.set(user,"修改后的name");
System.out.println("反射修改后的name值:"+ nameField.get(user));
//使用invoke方法调用番薯
Method runMethod = userClass1.getDeclaredMethod("run",String.class);
runMethod.setAccessible(true);
Object result = runMethod.invoke(user,"invoke参数");
System.out.println(result);
} catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
其他使用方法
boolean isPrimitive = class1.isPrimitive();//判断是否是基础类型
boolean isArray = class1.isArray();//判断是否是集合类
boolean isAnnotation = class1.isAnnotation();//判断是否是注解类
boolean isInterface = class1.isInterface();//判断是否是接口类
boolean isEnum = class1.isEnum();//判断是否是枚举类
boolean isAnonymousClass = class1.isAnonymousClass();//判断是否是匿名内部类
boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class);//判断是否被某个注解类修饰
String className = class1.getName();//获取class名字 包含包名路径
Package aPackage = class1.getPackage();//获取class的包信息
String simpleName = class1.getSimpleName();//获取class类名
int modifiers = class1.getModifiers();//获取class访问权限
Class<?>[] declaredClasses = class1.getDeclaredClasses();//内部类
Class<?> declaringClass = class1.getDeclaringClass();//外部类
getSuperclass():获取某类的父类
getInterfaces():获取某类实现的接口
总结
反射 在逆向代码 、与注解相结合、单纯的反射框架(如eventbus),动态生成类等,动态赋值等,都有很方便的使用性;