Skip to content

第九章 反射技术 v1.0 ​

第一部分 反射基础 ​

一、反射的概念 ​

1.基本概念 ​

Java 反射机制是 Java 语言的一个重要特性,是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。

简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。

2.反射的作用 ​

  • 在运行时,可以直接得到这个类的构造器对象:Constructor
  • 在运行时,可以直接得到这个类的成员变量对象:Field
  • 在运行时,可以直接得到这个类的成员方法对象:Method
  • 这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制

二、反射的使用 ​

1.获取Class类的对象的三种方式 ​

  1. 调用Class类方法:Class c = Class.forName("全类名");
  2. 直接由类名创建:Class c = 类名.class;
  3. 由现有的类的对象创建:Class c = 对象.getClass();

全类名:包名.类名形式,例:asia.hymsk.package.MyClass

2.反射可以访问的信息 ​

3.相关方法 ​

a.构造方法(Constructor类) ​
  1. newInstance(...):根据指定的构造器创建对象,参数为构造器参数
  2. setAccessible(boolean flag):设置是否暴力反射(取消访问权限检查)
b.成员变量(Fileds类) ​
  1. get(Object):获取Object对象的成员变量值
  2. set(Object, value):为Object对象的成员变量赋值
  3. setAccessible(boolean flag):设置是否暴力反射(取消访问权限检查)
c.成员方法(Method) ​
  1. invoke(Object, ...):在某个对象中触发该成员方法并执行
  2. setAccessible(boolean flag):设置是否暴力反射(取消访问权限检查)
  3. getAnnotation():获得方法上的注解
  4. getExceptionTypes():获得方法抛出的异常
  5. getReturnType():获得返回值类型
  6. getParameterTypes():获得参数类型
  7. getParameterCount():获得参数个数
  8. getName():获得方法名

第二部分 注解(JDK5引入) ​

对Java中类、方法、成员变量、参数等进行标记,然后进行特殊处理,具体进行何种处理由业务需求来决定。

一、自定义注解 ​

1.标准格式 ​

java
public @interface 注解名称{
	属性类型 属性名() default 默认值;
}

2.特殊属性(value属性) ​

如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写,但是如果有多个属性,且多个属性没有默认值,那么value名称是不能省略的。

3.元注解 ​

  1. @Target:约束自定义注解只能在哪些地方使用
  2. @Retention:申明注解的生命周期
[@Target详细可使用值,定义在ElementType枚举类中]
  • TYPE:类,接口
  • FIELD:成员变量
  • METHOD:成员方法
  • PARAMETER:方法参数
  • CONSTRUCTOR:构造器
  • LOCAL_ VARIABLE:局部变量
[@Retention详细可使用值,定义在RetentionPolicy枚举类中]
  • SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
  • CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值.
  • RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)

二、注解解析 ​

注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容

1.解析方法(AnnotaedElement接口) ​

注:所有的类成分Class, Method , Field , Constructor都实现了该接口,都拥有解析注解的能力

2.注解解析案例 ​

[注解解析案例]

①定义注解Book,要求如下:

  • 包含属性:String value:书名
  • 包含属性:double price:价格,默认值为100
  • 包含属性:String[] authors:多位作者
  • 限制注解使用的位置:类和成员方法上
  • 指定注解的有效范围:RUNTIME

②定义BookStore类,在类和成员方法上使用Book注解

③定义AnnotationDemo01测试类,获取Book注解上的数据

java
public class AnnotationDemo1{
    @Test
    public void parseClass() {
        Class c = BookStore.class;
        if(c.isAnnotationPresent(Bookk.class)){
            Bookk book = (Bookk) c.getDeclaredAnnotation(Bookk.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.author()));
        }
    }
}

@Bookk(value = )

image.png ​

第三部分 单元测试 ​

单元测试是针对程序最小的功能单元(Java为方法)编写测试代码,即对方法测试进而检查方法的正确性

Junit单元测试框架 ​

JUnit是使用Java语言实现的单元测试框架,几乎所有的IDE工具都集成了JUnit,此处以版本4进行学习记录

1.优点 ​

  1. JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法
  2. JUnit可以生成全部方法的测试报告
  3. 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试

2.命名要求 ​

  1. 测试类:TestClassName
  2. 测试方法:testMethodName

3.Junit常用注解 ​

4.测试方法编写 ​

要求:方法必须是公共的无参数无返回值的非静态方法,在测试方法上使用@Test注解标注

java
import org.junit.Assert;
import org.junit.Test;
class TestClass() {
    @Test
    public void testMethod() {
        Assert.assertEquals(message, expected, result);  //分别代表提示信息,预期结果,实际结果
    }
}

第四部分 动态代理 ​

一、概述 ​

1.原理 ​

代理主要是对对象的行为额外做一些辅助操作,通过java.lang.reflect.Porxy类实现

2.优点 ​

  1. 可以在不改变方法源码的情况下,实现对方法功能的增强,提高了代码的复用。
  2. 简化了编程工作、提高了开发效率,同时提高了软件系统的可扩展性。
  3. 可以为被代理对象的所有方法做代理。
  4. 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。

二、实现 ​

1.创建接口 ​

创建接口指定对象进行的操作(代理必须要有接口)

2.创建类实现接口 ​

创建接口的实现类(代理对象类必须要实现接口)

3.由实现类生成动态代理 ​

java
MyClass obj = new MyClass();  //MyClass为某接口的实现类
agent = (MyClass)Porxy.newProxyInstance(
    obj.getClass().getClassLoader(),  
    obj.getClass().getInterfaces(),
    new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args){
            //执行前操作
            Object rs = method.invoke(obj, args);
            //执行后操作
            return rs;
        }
    });