Java反射和动态代理
反射
反射允许对封装类的成员变量、成员方法和构造方法的信息进行编程访问
成员变量:修饰符、名字、类型、get/set值
构造方法:修饰符、名字、形参、创建对象
成员方法:修饰符、名字、形参、返回值、抛出的异常、获取注解、运行方法
获取class对象
- Class.forName(“全类名”);全类名是包名加类名
- 类名.class
- 对象.getClass();
在源代码阶段可以使用第一种方法(最常用)
在加载阶段可以使用第二种方法(当参数传递)
在运行阶段可以使用第三种方法(当已经有了这个类的对象的时候才可以调用)
构造方法的对象—Constructor
变量(字段)的对象—Field
成员方法—Method
Class consumer = Class.forName("Consumer");
Constructor[] constructors = consumer.getConstructors();
for (int i = 0; i < constructors.length; i++)
System.out.println(constructors[i]);
Constructor[] declaredConstructors = consumer.getDeclaredConstructors();
Constructor constructor = consumer.getConstructor();
Constructor declaredConstructor = consumer.getDeclaredConstructor();
// consumer.getConstructor(对应构造函数的参数列表);比如说String可以使用String.class
// consumer.getDeclaredConstructor(对应构造函数的参数列表);比如说int,可以使用int.class
Class consumer = Class.forName("Consumer");
Constructor constructor = consumer.getConstructor(String.class);
System.out.println(constructor.getModifiers());//获取对应构造函数的权限修饰符
上面的方法可以获取对应构造方法的权限修饰符。但是其是以整数的形式表示出来的:
1024:Abstract
16:Final
512:Interface
256:native
2:private
4:protected
1:public
8:static
2048:strict
32:synchronized
128:transient
64:volatile
Class consumer = Class.forName("Consumer");
Constructor constructor = consumer.getConstructor(String.class);
System.out.println(constructor.getParameterCount());//获取所需的参数个数
Parameter[] parameters = constructor.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}//获取所需的参数类型
Class consumer = Class.forName("Consumer");
Constructor declaredConstructor = consumer.getDeclaredConstructor(String.class);//获取私有构造方法
declaredConstructor.setAccessible(true);//临时取消私有的权限修饰
declaredConstructor.newInstance("张三");//使用私有构造方法创建对象实例
获取成员变量
Class类中的用于获取成员变量的方法
方法 | 作用 |
---|---|
Field[] getFields() | 返回所有公共的成员变量对象的数组 |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组 |
Field getField(String name) | 返回单个公共成员变量的对象 |
Field getDeclaredField(String name) | 返回单个成员变量的对象 |
Field类中用于创建对象的方法
方法 | 作用 |
---|---|
void set(Object o,Object value) | 赋值 |
Object get(Object obj) | 获取值 |
也可以获取权限修饰符,还可以获取字段类型
也可以暂时修改权限修饰符,然后可以进行get、set方法
获取成员方法
getMethods获取的方法包含父类中的方法
Declared不可以获取父类的,但是可以获取私有的
反射可以结合配置文件动态的创建对象调用方法。
动态代理
动态代理可以无侵入式的为方法增加功能
对象有什么方法想被代理,代理就一定要有对应的方法
通常要被代理的方法都放在接口中,两个类都实现这个接口
Java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数一:用于指定使用哪一个类加载器,去加载生成的代理类
参数二:指定接口,这些接口用于指定生成的代理有什么方法
参数三:用于指定生成的代理对象要干什么事情
下面是一个示例:
方法类:
public class BigStar implements modefier {
String name;
public BigStar() {
}
public BigStar(String name) {
this.name = name;
}
@Override
public String Sing(String songName) {
System.out.println(this.name + "正在唱" + songName);
return "谢谢大家\n";
}
@Override
public String Dance(String danceName) {
System.out.println(this.name + "正在唱" + danceName);
return "谢谢大家\n";
}
/**
* 获取
*
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
public String toString() {
return "BigStar{name = " + name + "}";
}
}
接口:(写想要被代理的方法)
public interface modefier {
public abstract String Sing(String name);
public abstract String Dance(String name);
}
代理类:
其中要判断执行为方法附加的功能
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class proxyUtil {
public static modefier CreatProxy(BigStar bs) {
modefier o = (modefier) Proxy.newProxyInstance(proxyUtil.class.getClassLoader(),
new Class[]{modefier.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("Sing".equals(method.getName())) {
System.out.println("唱歌先收钱");
} else if ("Dance".equals(method.getName())) {
System.out.println("跳舞也要收钱");
}
return method.invoke(bs, args);
}
}
);
return o;
}
}
测试类:
BigStar bs = new BigStar("cxk");
modefier modefier = proxyUtil.CreatProxy(bs);
System.out.println(modefier.Sing("只因你太美"));