Java反射
反射
反射基本概念
首先反射是什么:Java的反射是指在运行状态中,对于任何一个类都能知道他的属性和方法,对于任何一个对象都能调用他的属性和方法
Class在java中也是一个实实在在存在的类,每个java类运行时在JVM中都表现为一个Class对象,基本数据类型在JVM中表现也是一个Class对象。每个通过Class标识的类在内存中都有且只有一个与之对应的Class对象,无论创建多少个实例依据都是一个Class对象。Class类只有私有构造函数所有Class对象都只能有JVM创建和加载。Class类的作用是运行时提供或获得对象类型信息
反射基本使用
Class的获取
User对象
public class User {
private String userName;
private String age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", age='" + age + '\'' +
'}';
}
public User() {
}
public User(String userName, String age) {
this.userName = userName;
this.age = age;
}
public void prepareExamination(){
System.out.println("学生正在努力备考!!");
}
}
Class的三种获取方式
@Test
public void test18() throws Exception {
// 通过类名.class获取类的反射 获取Class对象的一个引用,返回表示该对象的实际类型的Class引用。
Class<User> userClass = User.class;
User user = new User("张三", "19");
// 通过实例.getClass()获取类的反射
Class<User> aClass = user.getClass();
// 通过Class.forName("类全限定类名获取反射") 获取Class对象的一个引用,但引用的类还没有加载(该类的第一个对象没有生成)就加载了这个类。
Class<User> aClass1 = Class.forName("com.zzk.myTest.User");
}
反射的方法
@Test
public void test19() throws Exception {
// 通过Class.forName("类全限定类名获取反射")
Class<?> userClass = Class.forName("com.zzk.myTest.User");
// 获取类的全限定类名
System.out.println("这是User类全定类名:" + userClass.getName());
// 获取类名
System.out.println("这是User类名:" + userClass.getSimpleName());
// 通过反射创建对象实例 返回一个Oject对象,是实现“虚拟构造器”的一种途径。使用该方法创建的类,必须带有无参的构造器。
System.out.println("这是通过反射新创建的User对象" + userClass.newInstance());
//=========================================构造方法==============================================================
// 通过参数类型获取public的构造方法 Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<?> constructor = userClass.getConstructor(String.class, String.class);
// 获取该类的所有的public的构造方法 Constructor<?>[] getConstructors() throws SecurityException
Constructor<?>[] constructors = userClass.getConstructors();
// 可利用获取的构造方法创建对象
// 例如 constructor创建对象就是使用的是 public User(String userName, String age)方法常见对象
// 若构造方法私有可使用 实例.setAccessible(true)方法设置访问权限
// 可使用getGenericParameterTypes()方法获取一组 type 对象,返回的就是 Constructor对象构造函数的形参类型。
// 可使用getParameterTypes()方法获取一组 Class 对象,返回的就是 Constructor对象构造函数的形参类型。
User newInstance = (User)constructor.newInstance("张三", "75");
System.out.println(newInstance); //结果是 User{userName='张三', age='75', result=null}
// =========================================获取方法=============================================================
// 根据方法名和参数类型获取该类public的方法(包括继承自父类public的方法) Method getMethod(String name, Class<?>... parameterTypes)
Method prepareExamination = userClass.getMethod("prepareExamination");
// 获取该类的所有public的方法(包括继承自父类public的方法) Method[] getMethods() throws SecurityException
Method[] methods = userClass.getMethods();
// 根据方法名和参数获取该类的public和非public方法(默认不包括继承自父类的方法) Method getDeclaredMethod(String name, Class<?>... parameterTypes)
Method declaredMethod = userClass.getDeclaredMethod("prepareExamination");
// 获取该类的所有public和非public的方法(默认不包括继承自父类的方法) Method[] getDeclaredMethods() throws SecurityException
Method[] declaredMethods = userClass.getDeclaredMethods();
// 可使用获得的 实例.invoke(该类实例(),参数..)执行类的方法
// getReturnType()方法返回class对象用来描述方法返回值
// getGenericReturnType()方法返回Type对象用来描述方法返回值
// getParameterTypes()方法返回Class对象数组用来描述方法参数类型
// getParameterTypes()方法返回Type对象数组用来描述方法参数类型
// getName()方法方法名称
// setAccessible(true)设置方法的可访问性
// 例如:
prepareExamination.invoke(newInstance);
// =========================================获取属性=============================================================
// 根据属性名称获取该类的public的属性(包括继承自父类public的属性)
Field result = userClass.getField("result");
// 获取该类的所有的public属性(包括继承自父类public的属性)
Field[] fields = userClass.getFields();
// 根据属性名称获取该类的public和非public的属性(默认不包括继承自父类属性)
Field age = userClass.getDeclaredField("age");
// 获取该类的所有的public属性(默认不包括继承自父类属性)
Field[] declaredFields = userClass.getDeclaredFields();
// 可使用set(该类实例,新值)方法来给对象设置值 使用get(类实例)来获取该属性值 getName返回该字段值
// 如参数不可访问可使用setAccessible(true)来改变访问性
// getType()返回Type对象来表示属性类型 getDeclaringClass()方法用来返回class对象表述属性类型
// 例:使用get()获取该类所属值
System.out.println(result.get(newInstance)); // null
result.set(newInstance,80);
System.out.println(result.get(newInstance)); // 80
// =========================================实现接口和父类=============================================================
// 获取该类的父类的class对象
Class<?> superclass = userClass.getSuperclass();
// 获取该类实现的所有接口
Class<?>[] interfaces = userClass.getInterfaces();
// 获取该类所有的注解
Annotation[] annotations = userClass.getAnnotations();
反射的应用
使用反射实现java原生动态代理
java的被代理的对象必须实现接口,会代理接口中的方法
// 接口
public interface Examination {
void prepareExamination();
}
// 实现接口
public class User implements Examination{
@Override
public void prepareExamination(){
System.out.println("学生正在努力备考!!");
}
}
// 代理handler
public class UserHandler implements InvocationHandler {
// 初始化
private Object object;
public Object bind(Object object){
this.object = object;
// 创建动态代理对象 参数为:使用什么类加载器加载代理类,代理对象实现接口,代理类handler
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(),this);
}
// method即被代理的方法,在方法之前执行的即前置通知,后面执行的即后置通知
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
front();
Object invoke = method.invoke(this.object, args);
after();
return invoke;
}
public void front(){
System.out.println("学生的父母送孩子来到学校");
}
public void after(){
System.out.println("学生考试结束!");
}
}
// 看看结果把!
@Test
public void test21(){
UserHandler userHandler = new UserHandler();
Examination examination = (Examination) userHandler.bind(new User("张三", "45"));
examination.prepareExamination();
}
// 输出结果
// 学生的父母送孩子来到学校
// 学生正在努力备考!!
// 学生考试结束!
参考:
https://pdai.tech/md/java/basic/java-basic-x-reflection.html
https://www.cnblogs.com/lzq198754/p/5780331.html