反射学习笔记
title: 反射学习笔记
date: 2020-01-01 12:08:14
tags:
categories:
概述
定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
功能
-
运行时判断任意一个对象所属的类
-
运行时构造任一个类的对象
-
运行时判断任意一个类的成员变量和方法
-
运行时调用任意一个对象的成员变量和方法
-
动态代理(反射的关键应用)
主要API
类名 | 用途 |
---|---|
Class类 | 代表类的实体,在运行的Java应用程序中表示类和接口 |
Field类 | 代表类的成员变量(成员变量也称为类的属性) |
Method类 | 代表类的方法 |
Constructor类 | 代表类的构造的构造方法 |
Class类
在Object类中定义了getClass()方法,这个方法被所有子类继承
public final Class getClass()
实例化Class类对象的四种方法
- 通过类名创建
Class clazz = String.class;
- 通过实例创建
Class clazz = "www.xyz.com".getClass(); //通过String对象创建
- 通过类的全类名创建
Class clazz = Class.forName("java.lang.String");
- 通过类加载器创建
ClassLoader cl = this.getClass().getClassLoader();
Class clazz = cl.loadClass("全类名");
Class对象的常见方法
类相关:
方法 | 用途 |
---|---|
getName() | 获得类的完整路径名字 |
getSimpleName() | 获得类的名字 |
getSuperclass() | 获得当前类继承的父类的名字 |
getInterfaces() | 获得当前类实现的类或是接口 |
newInstance() | 创建类的实例,无参,返回Object,需要强转 |
如果需要创建一个有参实例,先获取有参的构造函数,在通过newIntsance()创建;
构造器相关:
方法 | 用途 |
---|---|
getConstructors() | 获得该类的所有公有构造方法 |
getConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的公有构造方法 |
getDeclaredConstructors() | 获得该类所有构造方法 |
getDeclaredConstructor(Class…<?> parameterTypes) | 获得该类中与参数类型匹配的构造方法 |
通过反射机制,强制调用私有构造函数创建对象
Constructor c = clazz.getDeclaredConstructors(String.class);
c.setAccessible(true);//解除私有封装
Object ob = c.newInstance("Hello");
方法相关:
方法 | 用途 |
---|---|
getDeclaredMethods() | 返回此Class对象所表示的类或接口的全部方法 |
getMethods() | 返回此Class对象所表示的类或接口的public方法 |
通过反射调用特定方法
Method m = clazz.getMethod(name,params);
m.invoke(obj,args);//obj是实例化的对象,args是实参
如果需要调用一个私有方法需要加上
m.setAccessible(true);
调用有返回值的方法
Method m = clazz.getMethod(name,params);
Object c =m.invoke(obj,args);
属性相关:
方法 | 用途 |
---|---|
getFields() | 返回此Class对象所表示的类或接口的public属性 |
getDelcaredFields() | 返回此Class对象所表示的类或接口的全部Field |
通过反射调用属性
Constructor con = clazz.getConstructor();
Student stu = (Student)con.newInstance();
Field f = clazz.getField("school");
f.set(stu,"第一中学"); //设置属性
String school = (String)f.get(stu); //获取属性
通过反射调用私有属性
Field f = clazz.getDeclaredField("privateField");
f.setAccessible(true); //解除私有封装
f.set(stu,"私有属性");
String field = (String)f.get(stu);
Constructor类
Method类
Field类
public int getModifiers() 以整数形式返回此Field的修饰符
public Class<?> getType() 得到Field的属性类型
public String getName() 返回Field的名称
动态代理
考虑下需求:
某一开发人员,假设它会java和C++两种语言,但是由于这两种语言难度不同,所以他掉的头发也会不同。所以在他写代码之前,他都会祈祷让自己的头发少掉一点,所以如何在真正写代码前完成这样一个祈祷并告知发量的程序呢,利用动态代理即可。
先定义一个Java接口,表示码农
public interface Coder {
void codeJava();
void codeCPlusPlus();
}
然后写出该接口的一个实现类,表示某一个具体的码农
public class Developer implements Coder {
@Override
public void codeJava() {
System.out.println("System.out.println(\"Hello,World\");");
}
@Override
public void codeCPlusPlus() {
System.out.println("cout << \"Hello, world!\";");
}
}
然后插入动态代理,在执行方法前,完成告知发量状况
public class Coding {
public static void main(String[] args) {
Developer zhong = new Developer();
/**
* 匿名类实现
*/
Coder zhongProxy = (Coder)Proxy.newProxyInstance(zhong.getClass().getClassLoader(),zhong.getClass().getInterfaces(),
((proxy, method, args1) -> {
if(method.getName().equals("codeJava")){
System.out.println("coding Java...Hair reduce 30%");
}else if (method.getName().equals("codeCPlusPlus")){
System.out.println("coding C++...Hair reduce 60%");
}
Object result = method.invoke(zhong, args);
System.out.println("coding done!");
return result;
}));
zhongProxy.codeJava();
System.out.println("=========================================================================");
}
执行结果:
coding Java...Hair reduce 30%
System.out.println("Hello,World");
coding done!
上述这种方式采用了匿名类实现,更加简洁,如果喜欢麻烦,可以使用下面这种方式
创建码农代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DevelopProxy implements InvocationHandler {
private Object object;
public DevelopProxy(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("codeJava")){
System.out.println("coding Java...Hair reduce 30%");
}
if(method.getName().equals("codeCPlusPlus")){
System.out.println("coding C++...Hair reduce 60%");
}
Object result = method.invoke(object, args);
System.out.println("coding done!");
return result;
}
}
同样,在main方法中调用Proxy.newInstance即可
public class Coding {
public static void main(String[] args) {
Developer zhong = new Developer();
/**
* 老老实实写接口类实现
*/
zhongProxy = (Coder)Proxy.newProxyInstance(zhong.getClass().getClassLoader(),zhong.getClass().getInterfaces(),new DevelopProxy(zhong));
zhongProxy.codeCPlusPlus();
}
}
执行结果:
coding C++…Hair reduce 60%
cout << “Hello, world!”;
coding done!