反射机制

1.Junit(单元测试)
2.反射(框架设计的灵魂)
3.注解
 
1. Junit
测试分类:黑盒,白盒。Junit是白盒
传统按代码测试的缺点:main函数一次侧一行,重复侧,不方便统一管理
 
步骤:
(1)定义一个测试类:创建类名,包名
(2)定义测试方法:可以独立运行。方法名,为Test+被测方法名,返回void,空参
(3)加注解@test
(4)导入Junit依赖环境
(5)测试方法中编写用例,使用unit运行,运行之后检验运行结果。
测试环境很少用输出字符串,使用assert类提供的方法,断言操作处理结果。
 
@before :所注解的方法在测试单元方法执行前被执行,用于资源的申请
@close :类似上面,用于资源释放
 
2.反射
框架是半成品软件,在其基础上进行开发,简化编码
反射概念:将类的各部分封装成其他对象。
Java代码阶段:
(1)源代码阶段:源代码->字节码(硬盘)
字节码:3个部分
成员变量
构造方法
成员方法
(2)类(Class类)对象阶段通过类加载器把字节码文件加载到内存
内存中用Class类对象描述字节码文件,字节码的3个部分分别封装成3类对象
成员变量:Field类[]
构造方法:Constructor类[]
成员方法:Method类[] (都是数组)
(3)创建对象
new出来
 
反射使得:
(1)在运行时可以分析和操作对象
(2)解耦,提高程序可拓展性
获取Class对象:
(1)Class.forName(“全类名”); //从硬盘加载字节码获取,返回Class对象
用于配置文件,定义类名在配置文件里,读取文件来加载类
(2)类名.class;
用于参数传递
(3)对象.getClass();
多用于对象获取字节码对象
同一个字节码文件,在一次程序运行中,用任何方法获取的Class对象只有一个
 
Class对象功能:
1.获取成员变量Field
Field[] getField(); Field getField(String name); Field[] getDeclaredFields()...
 
getField只获取public修饰的变量(可以清楚显示级别)
按字符串搜索时查询同名域取继承级别最新的,不支持全名查询所以无法指定级别
使用Field对象获取具体对象的公有域值:
Field field = stu1.getClass().getField("name");
Object obj = field.get(stu1);
System.out.println(obj);//获得了stu1的public的名字
也可以使用域设定对象的值:
field.set(stu1,"Steve");//改名字为Steve
 
getDeclaredField:获取所有域,包括私有。但是对私有域直接访问报错。
(不取父类域)
此时使用 域.setAccessible(true);//破坏了私有性, 暴力反射
Field field = stu1.getDeclaredField("name");
field.setAccessible(true);
field.set(stu1,"FZK");//改private的name域内容为FZK
 
2.获取构造方法 (用来创建对象)
类对象.getConstructor(构造器参数对应的Class对象列表)
Constructor constuctor = studentClass.getConstructor(String.class);
System.out.println(cons);
//输出 public Student(java.lang.String)
使用构造器创建对象:T Constructor.newInstance(参数列表)
Student stu2=(Student) cons.newInstance("WXY");//返回Object,强制类型转换一下
类型对不上会报错
空参构造器直接可以通过Class.newInstance调用(@Deprecated方法)
getDeclaredConstructor类似上面,也有暴力反射
3获取成员方法
getMethod(方法名,参数列表.如果有 );
执行方法:类对象.invoke(对象,参数列表);
注意:多态方法,按照具体要取的方法确定参数列表,取出来的是单个的没有多态的方法,用invoke调用必须严格按照参数列表来进行。
 
Method.getname()返回String
 
getDeclaredMethods类似上面,也有暴力对象
4.获取类名
String getName()
 
 
反射的实际使用:
例:写一个程序,不能改变其中任意代码的情况下,创建任意对象,执行其任意方法。
细节:
(1)需要创建的对象的全类名和需要执行的方法放入配置文件中
(2)在程序中加载读取配置文件
(3)使用反射来加载类文件进内存
(4)创建对象
(5)执行方法
 
首先写配置文件:
className = fuck.Student
methodName = print
执行代码:
//Reflect Test
//      配置文件
        Properties pro = new Properties();
        ClassLoader classLoader = Hello.class.getClassLoader();
        InputStream inputStream=classLoader.getResourceAsStream("fuck.properties");
        pro.load(inputStream);
//      获取配置数据
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");
//       加载进内存
        Class aClass = Class.forName(className);
//       创建对象
        Object obj = aClass.newInstance();
//      执行
        Method method = aClass.getMethod(methodName);
        method.invoke(obj);
上述只有无参数方法调用,含参数方法可能1.配置复杂一些,2.使用起来也麻烦一些
 
 
3.注解
对程序的说明,面向计算机,是一种代码级别的说明。
JDK1.5之后特性,用于对各种元素进行说明,注释。
@注解名称
 
预定义注解:
@override
@Deprecated(已过时,有更好方法)
@SurpressWarning(消除警告,一般传递参数“all”)
自定义注解:
格式:
元注解
public @interface 注解名称{
属性列表
}
 
本质:一个接口,默认继承下列
public interface 注解名 extends java.lang.annotation.Annotation{}
属性:接口可以定义的一些抽象方法
属性的返回值类型只能是基本数据类型、String、enum类、注解以及以上组
定义属性,使用时需要赋值,default可默认初始化值。
 
 
使用注解:...
 
作用:编写文档和编译检查(常规)、代码分析(特殊)
(1)编译检查:@Override等
(2)通过注解生成javadoc
/**
 * 尝试交换两数哈希码
 * @param a (描述)
 * @param b 
 */
public static void swap(String a,String b ){
    a.toUpperCase();
    assert a.hashCode()==b.hashCode();
 
}
(3)代码分析:通过代码里的注解对代码进行分析(使用反射)
 
 
关于注解的更详细介绍:
 
反射机制面试设计比较多,后续学习进行复习以及深入理解应用。另外还有动态代理相关
posted @ 2019-09-23 10:42  CaptainL  阅读(169)  评论(0编辑  收藏  举报