一、反射
1.1 创建运行时类的对象
Class<Person> clazz = Person.class;
Person obj = clazz.newInstance();
System.out.print(obj);
注意:
要想clazz.newInstance()运行成功,需要满足以下的需求
1、运行时类必须提供无参构造器
2、无参构造器的访问权限必须是public
在javaBean当中,一般要求提供一个public的无参构造器
原因:
1、便于通过反射,创建运行时类的对象
2、便于子类集成父类时,通过super()调用父类构造器
1.2 获取运行时类的完整结构
我们可以通过反射,回去运行时类中所有的属性、方法、构造器、父类、接口、包、泛型、注解等
public void test2(){
Class clazz = Person.class;
// 获取属性结构:当前运行类及父类的的所有public访问权限的属性
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
// 获得当前运行类当中申明的所有属性(不包含父类的)
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
}
public void test3(){
Class clazz = Person.class;
// 当前运行类包名
Package pack = clazz.getPackage();
System.out.println(pack);
}
public void test4(){
Class clazz = Person.class;
// 当前运行类注解
Annotation [] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
1.3 调用运行时类的指定结构
// 属性
public void test5(){
Class clazz = Person.class;
// 创建运行时类对象
Person p = (Person) clazz.newInstance();
// 获取运行时类当中指定变量名的属性
Field name =clazz.getDeclaredField("name");
// 保证当前属性是可以访问的
name.setAccessible(true);
// 设置、获取指定对象的此属性值
name.set(p,"Tom");
System.out.println(name.get(p));
}
// 方法
public void test6(){
Class clazz = Person.class;
// 创建运行时类对象
Person p = (Person) clazz.newInstance();
// 获取运行时类当中指定的某个方法:参数1--方法名,参数2--入参
Method method =clazz.getDeclaredMethod("name",String.class);
// 保证当前方法是可以访问的
method.setAccessible(true);
// 调用方法: 返回值就是方法的返回值
Object object= method.invoke(p,"CHN");
System.out.println(object);
}
// 构造器
public void test8(){
Class clazz = Person.class;
// 获取运行时类当中有参构造器
Constructor constructor =clazz.getDeclaredConstructor(String.class);
// 保证当前构造器是可以访问的
constructor.setAccessible(true);
// 调用次构造器创建运行时类对象
Person person = constructor.newInstance("Toms");
System.out.println(person);
}
二、代理
使用一个代理将对象包装起来,之后人后对原始对象的访问都要经过代理,代理决定是否以及何时去请求原始对象,代理分为动态代理和静态代理
静态代理:代理类和目标类在编译期间就确定了,同时,没一个代理类只能为一个接口服务,这样会需要很多的代理
动态里:使用一个代理完成所有的代理功能、在程序执行过程中,使用jdk的反射机制,创建代理类对象, 并动态的指定要代理目标类。
2.1 静态代理
- 创建一个接口
- 创建厂家类,实现1步骤的接口
- 创建代理,也需要实现1步骤中的接口。
- 创建客户端类,调用代理
public interface Human {
int eat(int count);
}
//目标类:
public class AppleFactory implements Human {
@Override
public int eat(int count) {
System.out.println("目标类中的方法调用 , AppleFactory 中的eat ");
return count;
}
}
public class JD implements Human {
//声明 被代理类
private Human factory = new AppleFactory();
@Override
public int eat(int count) {
//调用被代理类
int count = factory.eat(count);
//代理增加。
count += 40;//增强功能,代理类在完成目标类方法调用后,增强了功能。
System.out.println("吃了!");
return count;
}
}
public class Customer {
public static void main(String[] args) {
JD j = new JD();
int count = j.eat(1);
System.out.println(count);
}
}
2.2 动态代理
////////////////////////////////// 接口 //////////////////////////////////////////////////
/**
* @ClassName Human
* @description: 动态代理:接口
*/
public interface Human {
String getBelief();
void eat(String food);
}
///////////////////////////////////////// 被代理类 /////////////////////////////////////////////////////////
/**
* @ClassName SuperMan
* @description: 被代理类
*/
public class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe I can fly";
}
@Override
public void eat(String food) {
System.out.println("I love eat "+ food);
}
}
//////////////////////////////// 动态代理类 /////////////////////////////////////////////////////////
/**
* @ClassName ProxyTest
* @description: 代理类
* 问题一:如何根据加载到内存当中的代理类,动态的创建一个代理类及其对象(动态创建代理类及对象)
* 问题二:当通过代理类的对象调用方法时,如何动态的去调用被代理类的同名方法(动态创建被代理类方法)
* @author: bozhiqiang
* @Version 1.0.0
* @createTime: 2022-10-04 18:00:49
*/
public class ProxyFactory {
/**
* obj:被代理类对象(需要知道被代理类是啥,才可以创建代理类)
* @return:返回一个代理类对象
*/
public static Object getProxyInstance(Object obj){
MyInvocationHandler handler = new MyInvocationHandler();
// 被代理对象赋值
handler.bind(obj);
/**
* 根据被代理类对象动态的创建代理类
* 参数1:被代理类由什么类加载器加载
* 参数2:被代理类实现了什么接口(代理类和被代理类必须实现相同的接口)
* 参数3:动态调用方法实现
*/
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),handler);
}
}
public class MyInvocationHandler implements InvocationHandler {
// 被代理类
private Object obj;
public void bind(Object obj){
this.obj = obj;
}
// 当我们通过代理类的对象,调用该方法时,就会自动调用如下的invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/**
* 方法调用
* method:被代理对象方法
* obj:被代理对象
* args:被代理方法入参
*/
Object returnValue = method.invoke(obj,args);
return returnValue;
}
}
////////////////////////////////// 测试 /////////////////////////////////////////////////////////
/**
* @ClassName ProxyTest
* @description: 测试
*/
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
// 代理类对象
Human human = (Human) ProxyFactory.getProxyInstance(superMan);
// 自动调用被代理类当中同名的方法---invoke
human.getBelief();
human.eat("apple");
}
}