Java初学者笔记-11、反射注解动态代理
Junit单元测试
针对最小的功能单元:方法,编写测试代码对其进行正确性测试。
Junit单元测试框架:可以用来对方法进行测试,它是第三方公司开源出来的(很多开发工具已经集成了Junit框架,比如IDEA)。可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。
不需要程序员去分析测试的结果,会自动生成测试报告。
单元测试的步骤
- 将Junit框架的jar包导入到项目中(IDEA已经集成了Junit框架)。
- 为需要测试的业务类,定义对应的测试类;为每个业务方法,编写对应的测试方法(公共、无参、无返回值)。
- 测试方法上必须声明
@Test
注解,然后在测试方法中,编写代码调用被测试的业务方法进行测试。 - 开始测试:选中测试方法,右键选择“JUnit运行”,如果测试通过则是绿色;如果测试失败,则是红色。测试的正确性取决于测试方法的编写。
反射
概念
通过反射加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。
- 加载类,获取类的字节码:Class对象。
- 获取类的构造器:Constructor对象。
- 获取类的成员变量:Field对象。
- 获取类的成员方法:Method对象。
获取Class对象
- 方法一:直接创建。
Class c1 = 类名.class
- 方法二:调用Class提供的静态方法。
public static Class forName(String package);
,其中,package
是全类名 - 方法三:调用Object提供的方法。
Class c3 = 对象.getClass();
获取类的成分
获取构造器
获取到构造器后,可以使用构造器初始化对象返回。
方法 | 说明 |
---|---|
Constructor<?>[] getConstructors() |
获取全部public修饰的构造器 |
Constructor<?>[] getDeclaredConstructors() |
获取全部构造器 |
Constructor<T> getConstructor(Class<?>... parameterTypes) |
获取某个public修饰的构造器 |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) |
获取某个构造器 |
Constructor提供的方法 | 说明 |
---|---|
T newInstance(Object... initargs) |
调用此构造器对象表示的构造器,并传入參数,完成对象的初始化并返回 |
public void setAccessible(boolean flag) |
设置为true,表示禁止检查访问控制(暴力反射) |
获取成员变量
获取到成员变量后,可以对成员变量进行赋值取值。
方法 | 说明 |
---|---|
public Field[] getFields() |
获取类的全部public修饰的成员变量 |
public Field[] getDeclaredFields() |
获取类的全部成员变量 |
public Field getField(String name) |
获取类的某个public修饰的成员变量 |
public Field getDeclaredField(String name) |
获取类的某个成员变量 |
方法 | 说明 |
---|---|
void set(Object obj, Object value) |
赋值 |
Object get (Object obj) |
取值 |
public void setAccessible(boolean flag) |
设置为true,表示禁止检查访问控制(暴力反射) |
获取成员方法
获取到成员方法后,可以将成员方法执行。
方法 | 说明 |
---|---|
Method[] getMethods() |
获取类的全部public修饰的成员方法 |
Method[] getDeclaredMethods() |
获取类的全部成员方法 |
Method getMethod(String name, Class<?>... parameterTypes) |
获取类的某个public修饰的成员方法 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) |
获取类的某个成员方法 |
Method提供的方法 | 说明 |
---|---|
public Object invoke(Object obj, Object.. args) |
触发某个对象的该方法执行 |
public void setAccessible(boolean flag) |
设置为true,表示禁止检查访问控制(暴力反射) |
反射的作用
- 基本作用:可以得到一个类的全部成分然后操作。
- 可以破坏封装性。
- 可以绕过泛型的约束。
- 更重要的用途:适合做Java的框架。基本上,主流的框架都会基于反射设计出一些通用的功能。
注解(重要)
概述
就是Java代码里的特殊标记,比如:@Overide、@Test
等.
作用是:让其他程序根据注解信息来决定怎么执行该程序。
注意:注解可以用在类上、构造器上、方法上、成员变量上、參数上、等位置处。
自定义注解
自己定义注解。
public @interface 注解名称 { public 属性类型 属性名() default 默认值; } public @interface A { String name(); int age() default 18; String[] address(); }
特殊属性名:如果在使用时 注解中只有 一个value属性,使用注解时,value名称可以不写!
public @interface B { String value(); } @B("delete") //这样使用是对的 // =============== public @interface B { String value(); int age() default 18; } @B(value = "delete", age = 19) @B("delete") // 原本是 @B(value = "delete", age = 18)// age=18默认值可省略
注解的原理
注解本质上是一个接口,通过反编译可以看到接口继承了Annotation。
注解中定义的属性全部都是抽象方法。
@注解(...)
:其实就是创建了一个实现类对象,实现了该注解以及Annotation接口。
元注解
元注解就是:注解注解的注解。即对注解进行注解。
@Retention(RetentionPolicy.RUNTIME) @Target ({ElementType .METHOD}) public @interface Test { }
@Target
作用:声明被修饰的注解只能在哪些位置使用。
@Target(ElementType.TYPE)
- TYPE, 类,接口
- FIELD,成员变量
- METHOD,成员方法
- PARAMETER,方法参数
- CONSTRUCTOR,构造器
- LOCAL_VARIABLE,局部变量
@Retention
作用:声明注解的保留周期。
@Retention(RetentionPolicy.RUNTIME)
- SOURCE,只作用在源码阶段,字节码文件中不存在。
- CLASS(默认值),保留到字节码文件阶段,运行阶段不存在。
- RUNTIME(开发常用),一直保留到运行阶段。
注解的解析
就是判断类上、方法上成员变量上是否存在注解并把注解里的内容给解析出来。
指导思想:要解析谁上面的注解,就应该先拿到谁。
比如要解析类上面的注解,则应该先获取该类的Class对象,再通过Class对象解析其上面的注解。
Class、Method、Field、Constructor都实现了AnnotatedElement接口,它们都拥有解析注解的能力。
AnnotatedElement接口提供了解析注解的方法 | 说明 |
---|---|
public Annotation[] getDeclaredAnnotations() |
获取当前对象上面的注解 |
public T getDeclaredAnnotation(Class<T> annotationClass) |
获取指定的注解对象 |
public boolean isAnnotationPresent(Class<Annotation> annotationClass) |
判断当前对象上是否存在某个注解 |
Class c1 = Demo.class; if (c1.isAnnotationPresent(MyTest2.class)) { MyTest2 myTest2 = (MyTest2)c1.getDeclaredAnnotation(MyTest2.class); String[] address = myTest2.address(); double height = myTest2.height(); String value = myTest2.value(); }
动态代理(设计模式)
认识动态代理
程序为什么需要代理?代理长什么样?
对象如果嫌身上干的事太多的话,可以通过代理来转移部分职责。
对象有什么方法想被代理,代理就一定要有对应的方法。
关键是使用接口。
为Java对象创建代理对象
java.lang.reflect.Proxy
类:提供了为对象产生代理对象的方法。
专门有静态方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
参数一:用于指定用哪个类加载器,去加载生成的代理类。
参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法。
参数三:用来指定生成的代理对象要干什么事情。
创建代理最好使用工具类独立一个方法,代理也要实现接口。
// 明星行为接口 public interface StarService{ void sing(String name); String dance; }
// 明星类 @Data @AllArgsConstructor @NoArgsConstructor public class Star implements StarService { private String name; @Override public void sing(String name) { System.out.println(this.name + "表演唱歌:" + name); } @Override public String dance() { System.out.println(this.name + "表演跳舞:魅力四射!"); return "谢谢!谢谢"; } }
// 创建代理工具类 public class Proxyutil { // 创建一个明星对象的代理对象返回。 public static <T> T createProxy(T s){ /** * 参数一:用哪个类加载器去加载生成的代理类。 * 参数二:用于指定代理类需要实现的接口:明星类实现了哪些接口,代理类就实现些接口。 * 參数二:用于指定代理类需要如何去代理(代理要做的事情〉。 */ T proxy = (T) Proxy.newProxyInstance( ProxyUtil.class.getClassLoader(), s.getClass().getInterfaces(), new InvocationHandler(){ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 这个匿名内部类用来声明代理对象要干的事 // 参数一:proxy接收到代理对象本身(暂时用处不大) // 参数二:method代表正在被代理的方法 // 参数三:args代表正在被代理的方法的参数 String methodName = method.getName(); if("sing".equals(methodName)){ System.out.println("准备话筒,收钱20万!"); }else if("dance".equals(methodName)){ System.out.printLn("准备场地,收钱100万!"); } // 真正干活(把真正的明星对象叫过来正式干活) // 找真正的明星对象来执行被代理的行为:method方法 Object result = method.invoke(s, args); // 反射的思想 return result; } }); return proxy; }
public class Test { public static void main(String(] args) { Star star = new Star ("小小"); //创建一个专属于她的代理对象 StarService proxy = ProxyUtil.createProxy(star); proxy.sing("《红昭愿》"); //找invokehandler的invoke方法 System.out.println(proxy.dance()); //找invokehandler的invoke方法 } }
动态代理解决的实际问题
给对象升升级。
Spring就是一个这样的框架,给你的对象宝宝加个代理,返回一个超级对象宝宝。
切面编程 AOP思想。
本文作者:subeipo
本文链接:https://www.cnblogs.com/subeipo/p/18686648/java-chu-xue-zhe-bi-ji11-fan-she-zhu-jie-dong-tai
版权声明:本作品采用署名—非商业性使用—相同方式共享 4.0 协议许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步