第九章 反射技术 v1.0
第一部分 反射基础
一、反射的概念
1.基本概念
Java 反射机制是 Java 语言的一个重要特性,是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。
简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。
2.反射的作用
- 在运行时,可以直接得到这个类的构造器对象:Constructor
- 在运行时,可以直接得到这个类的成员变量对象:Field
- 在运行时,可以直接得到这个类的成员方法对象:Method
- 这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制
二、反射的使用
1.获取Class类的对象的三种方式
- 调用Class类方法:
Class c = Class.forName("全类名"); - 直接由类名创建:
Class c = 类名.class; - 由现有的类的对象创建:
Class c = 对象.getClass();
全类名:包名.类名形式,例:asia.hymsk.package.MyClass
2.反射可以访问的信息
3.相关方法
a.构造方法(Constructor类)
newInstance(...):根据指定的构造器创建对象,参数为构造器参数setAccessible(boolean flag):设置是否暴力反射(取消访问权限检查)
b.成员变量(Fileds类)
get(Object):获取Object对象的成员变量值set(Object, value):为Object对象的成员变量赋值setAccessible(boolean flag):设置是否暴力反射(取消访问权限检查)
c.成员方法(Method)
invoke(Object, ...):在某个对象中触发该成员方法并执行setAccessible(boolean flag):设置是否暴力反射(取消访问权限检查)getAnnotation():获得方法上的注解getExceptionTypes():获得方法抛出的异常getReturnType():获得返回值类型getParameterTypes():获得参数类型getParameterCount():获得参数个数getName():获得方法名
第二部分 注解(JDK5引入)
对Java中类、方法、成员变量、参数等进行标记,然后进行特殊处理,具体进行何种处理由业务需求来决定。
一、自定义注解
1.标准格式
public @interface 注解名称{
属性类型 属性名() default 默认值;
}2.特殊属性(value属性)
如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写,但是如果有多个属性,且多个属性没有默认值,那么value名称是不能省略的。
3.元注解
@Target:约束自定义注解只能在哪些地方使用@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注解上的数据
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 = )
第三部分 单元测试
单元测试是针对程序最小的功能单元(Java为方法)编写测试代码,即对方法测试进而检查方法的正确性
Junit单元测试框架
JUnit是使用Java语言实现的单元测试框架,几乎所有的IDE工具都集成了JUnit,此处以版本4进行学习记录
1.优点
- JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法
- JUnit可以生成全部方法的测试报告
- 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试
2.命名要求
- 测试类:
TestClassName - 测试方法:
testMethodName
3.Junit常用注解
4.测试方法编写
要求:方法必须是公共的无参数无返回值的非静态方法,在测试方法上使用@Test注解标注
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.由实现类生成动态代理
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;
}
});