首页 > 编程语言 >Java初学者笔记-11、反射注解动态代理

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

时间:2025-01-22 19:33:48浏览次数:1  
标签:11 Java String 代理 Class 初学者 注解 方法 public

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;
    @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思想。

标签:11,Java,String,代理,Class,初学者,注解,方法,public
From: https://www.cnblogs.com/subeipo/p/18686648/java-chu-xue-zhe-bi-ji11-fan-she-zhu-jie-dong-t

相关文章

  • [2924]基于JAVA的豆制品生产销售智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的豆制品生产销售智慧管理系统的设计与实现指导老师(一)选题的背景和意义在当前信息化、智能化的大背景下,企业运营管理方式的创新和升级显得尤为重要。豆制品生产销售行业作为民生基础产业,其生产与销售过程涉及到众多......
  • 全面解析 Java 流程控制语句
    Java学习资料Java学习资料Java学习资料在Java编程中,流程控制语句是构建程序逻辑的关键部分,它决定了程序的执行顺序和走向。通过合理运用这些语句,开发者能够实现各种复杂的业务逻辑,让程序更加灵活和智能。顺序结构顺序结构是程序中最基本的执行结构,它按照代码书写的......
  • Java 面向对象基础全面解析
    Java学习资料Java学习资料Java学习资料在Java编程领域,面向对象编程(OOP)思想是构建复杂且高效程序的基石。它将现实世界中的事物抽象为程序中的对象,通过一系列特性,让程序更具模块化、可维护性与扩展性。一、面向对象编程思想(一)OOP概念面向对象编程是一种编程范式,它......
  • 链表(双向环形链表)Java版
    双向环形链表(一个哨兵)双向环形链表介绍双向环形链表的特点应用场景代码实现双向环形链表介绍双向环形链表是双向链表的一种特殊形式,其特点是链表的头节点和尾节点相互连接,形成一个环。相较于普通双向链表,环形结构使得链表可以在任意节点上循环遍历,非常适合某些场景,例......
  • 链表(双向链表)Java版
    双向链表(有哨兵节点)双向链表介绍双向链表的特点应用场景代码解析Java代码双向链表介绍双向链表(DoublyLinkedList)是一种链式存储结构,每个节点不仅包含数据,还包含两个指针,分别指向前驱节点和后继节点。它相比单向链表有更高的灵活性,因为可以从任意节点向前或向后遍历......
  • 深化Edge AI 应用:德承工控机GM-1100安装Ubuntu 24.04.1 LTS系统操作指南
    EdgeAI:边缘运算(EdgeComputing)结合人工智能(AI),将AI模型和算法安排在负责处理边缘运算的工控机上,除了能够就近撷取设备端的数据外,还能够进行资料处理与机器学习的任务,透过EdgeAI,不再需要将大量数据传到云端服务器,有效缩短处理时间、提高反应速度,还能够降低对于网络带宽的需求......
  • 基于java web的社区人员流动管理系统的设计与实现-毕业设计源码19467
    目 录1绪论1.1研究背景与意义1.2国内外研究现状1.3论文结构与章节安排2 系统分析2.1可行性分析2.1.1技术可行性分析2.1.2经济可行性分析2.1.3法律可行性分析2.2系统功能分析2.2.1功能性分析2.2.2非功能性分析2.3系统用例分析2.4系......
  • JavaSE基础笔记
    Java基础笔记一、流程控制(一)Scanner输入1、next()读取到空白就会自动将其去掉,next()不能得到带有空格的字符串hasNext()可以判断是否还有输入的数据packagecom.TEST.Test01;importjava.util.Scanner;publicclassTest01{publicstaticvoidmain(String[......
  • java 中的匿名内部类
    在Java中,匿名内部类是一种没有名称的内部类,通常用于简化代码,尤其是在实现接口或继承类时,只需要一个简单的实现。匿名内部类允许你在创建类的同时实例化它,通常用于简化代码的书写。工作原理匿名内部类是在你需要使用接口或抽象类的实现时定义和实例化的。它们在使用时定义在方法......
  • No.11 异常值的识别与处理
    1.什么是异常值偏离观测值较大的值。?mtcarsmydata<-mtcars#删除第8,9列mydata1<-mydata[,-c(8,9)]mydata1运行结果:>#删除第8,9列>mydata1<-mydata[,-c(8,9)]>mydata1mpgcyldisphpdratwtqsecgearcarbMazdaRX4......