Java初学者笔记-11、反射注解动态代理

Junit单元测试

针对最小的功能单元:方法,编写测试代码对其进行正确性测试。
Junit单元测试框架:可以用来对方法进行测试,它是第三方公司开源出来的(很多开发工具已经集成了Junit框架,比如IDEA)。可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部方法的自动化测试,且各自独立。
不需要程序员去分析测试的结果,会自动生成测试报告。

单元测试的步骤

  1. 将Junit框架的jar包导入到项目中(IDEA已经集成了Junit框架)。
  2. 为需要测试的业务类,定义对应的测试类;为每个业务方法,编写对应的测试方法(公共、无参、无返回值)。
  3. 测试方法上必须声明@Test注解,然后在测试方法中,编写代码调用被测试的业务方法进行测试。
  4. 开始测试:选中测试方法,右键选择“JUnit运行”,如果测试通过则是绿色;如果测试失败,则是红色。测试的正确性取决于测试方法的编写。

反射

概念

通过反射加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。

  1. 加载类,获取类的字节码:Class对象。
  2. 获取类的构造器:Constructor对象。
  3. 获取类的成员变量:Field对象。
  4. 获取类的成员方法:Method对象。

获取Class对象

  1. 方法一:直接创建。Class c1 = 类名.class
  2. 方法二:调用Class提供的静态方法。public static Class forName(String package);,其中,package是全类名
  3. 方法三:调用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,表示禁止检查访问控制(暴力反射)

反射的作用

  1. 基本作用:可以得到一个类的全部成分然后操作。
  2. 可以破坏封装性。
  3. 可以绕过泛型的约束。
  4. 更重要的用途:适合做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)

  1. TYPE, 类,接口
  2. FIELD,成员变量
  3. METHOD,成员方法
  4. PARAMETER,方法参数
  5. CONSTRUCTOR,构造器
  6. LOCAL_VARIABLE,局部变量

@Retention

作用:声明注解的保留周期。
@Retention(RetentionPolicy.RUNTIME)

  1. SOURCE,只作用在源码阶段,字节码文件中不存在。
  2. CLASS(默认值),保留到字节码文件阶段,运行阶段不存在。
  3. 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;@Overridepublic void sing(String name) {System.out.println(this.name + "表演唱歌:" + name);}@Overridepublic 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(){@Overridepublic 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思想。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/873391.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

movfuscator学习

demovfuscator docker镜像 - 狗小剩就是利用32位mov的图灵完备性,来代替各种代码(32位汇编太逆天了).如果看到只有mov就知道是这b玩意了,不过这种程序性能肯定不行,代码段也好长.可以利用ida查锁定字节码的范围,查相应的字符串. demovfuscator问题太多了,一个是识别c的代码无法…

中考英语优秀范文-016 How to keep a good relationship with parents 如何与父母保持良好的关系

1 写作要求 某英文报社正就青少年与父母关系这一话题开展题为“How to keep a good relationship with parents”的征文活动。请你根据以下要点, 写一篇80个词左右的英语短文参加此次活动: 1 父母规矩太多, 过于强调学习成绩, 不理解自己等问题; 2 你对这些问题的看法; 3 你与父…

KubeSphere 开源社区 2024 年度回顾与致谢

随着 2024 年圆满落幕,我们回顾 KubeSphere 社区这一年走过的每一步,感慨万千。2024 年,KubeSphere 继续领跑云原生技术的创新与发展,推动开源文化的传播,致力于为全球开发者和企业用户提供更强大的平台和解决方案。感谢每一位社区成员的辛勤付出,正是因为你们的共同努力…

云--什么是云

https://whatiscloud.com/

城市生命线安全保障:技术应用与策略创新

城市生命线工程是维系城市正常运行、满足群众生产生活需要的重要基础设施。随着城市化进程的加快,城市基础设施生命线安全运行的复杂性日益加剧,保障城市居民日常生活正常运行的水、电、气、热等各类地下管线以及桥梁、市政设施、轨道交通等城市基础设施的安全问题日益突出。…

Android图形层垂直同步虚拟VSYNC机制

简介 某次调图形性能的时候(启动后台录屏,下(或)称case)发现Android SurfaceFlinger Vsync机制并没有以前想的这么简单粗糙,特别是这次调图形性能发现一些跟Vsync有关联,因此做个总结详解。 跟不上旋律节奏的VSYNC 一份追踪报告,发现Vsync信号非常不规律,于是从这里入手…

[日志] 打印异常堆栈信息的技巧

序Java的异常堆栈信息,对提升排查问题的效率,有极大的帮助————便于我们快速定位异常的发生过程和发生异常的代码行。本文使用的日志框架slf4j : 1.7.25 log4j(2) : 2.20.0 日志行的打印策略 : log4j2.properties# property.log.layout.consolePattern=%d{yyyy/MM/dd HH:m…

【vjudge训练记录】大一寒假专项训练——前缀和/差分

训练情况A题 前缀和模板题,我们输入完 \(a_i\) 后直接求前缀和 \(a_i = a_i + a_{i-1}\),求区间 \([l,r]\) 的和就为 \(a_r-a_{l-1}\)点击查看代码 #include <bits/stdc++.h> #define int long long #define endl \nusing namespace std;void solve(){int n,m;cin>&…

VSCode使用之go语言配置

时间:2025/1/22 扩展:go 目的:支持go语言,方便安装其他必备插件安装该扩展包后可以执行该扩展包提供的命令Go:Install/Update Tools来进一步扩展go工具执行命令的窗口可以通过Ctrol+Shift+P调出点击后会出现很多选项,可以根据自己需要勾选然后点击确定,等待下载安装,一般情…

VSCode设置之默认在当前文件目录下打开终端

在vscode界面依次点击“文件”→“首选项”→“设置”→“用户”→“功能”→“终端”,找到Integrated:Cwd选项,将其值修改为”${fileDirname}“,即可在所有打开的工程内实现终端默认在当前文件的路径启动

树上的轮廓线DP!——AGC017F Zigzag

树上的轮廓线DP!——AGC017F Zigzag 注意到 \(n,m\le 20\),考虑状压,设 \(f_{i,S}\) 表示对于第 \(i\) 条线,其路线为 \(S\) 的方案数。 转移需要枚举 \(f_{i-1,S}\) 复杂度 \(\mathcal O(4^n\text{poly}(n))\)。 发现这种相邻状态之间的限制很像矩形中行的扩展,于是我们可…