框架设计的灵魂 框架是半成品软件,简化编码
概念:将类的各个组成部分封装为其他对象,就是反射机制
Java代码:三个阶段:
1、第一阶段:Source源代码阶段:代码在磁盘上 .java类文件 ------>.class字节码文件
2、第二阶段:Class类对象阶段:ClassLoader类加载器,将字节码文件加载到内存:Class类对象:Fiilds对象,Constructor对象,Method对象
3、第三阶段:Runtime运行时阶段:new 类();
优点:1、可以在程序运行过程中,操作这些对象
2、解耦代码
获取Class对象的方式Class对象只有一个也即是 .class字节码文件只会加载一次
1、对于第一阶段:Class.forname(“全类名”);将字节码文件加载到内存里,返回Class对象
- 多用于配置文件,将类名定义在配置文件中,读取文件,来加载类
2、对于第二阶段:类名.Class:通过类名的属性class获取
- 多用于参数的传递
3、第三阶段:对象。getClass();该方法在Object中定义,故所有对象都有该方法
- 多用于对象的获取字节码的方式
tips:ClassNotFoundException一般都是类名写错了
Class对象的功能- 获取功能
- 获取成员变量们:getFields():等方法
- set设置值
- get获取值
- setAccessible(true):暴力反射,忽略访问权限修饰符的安全检测
- 获取构造方法getConstructor等方法
- 创建对象
- T newInstance(Object… initargs初始化参数)
- 如果使用空参构造方法创建对象,操作可简化:Class对象的newInstance方法
- 创建对象
- 获取成员方法getMethods(),都是Method类对象
- 执行方法
- 方法.invoke(对象,Object… initargs)
- getName()获取方法名
- 执行方法
- 获取类名
- getName()
- 获取成员变量们:getFields():等方法
概念:
- 注释:文字解释程序功能,给程序员看的 - 注解:也叫元数据 代码级别的说明,1.5后新特性,对程序元素进行说明注释,给程序看的
作用分类:
- 编写文档:通过代码里标识的元数据生成文档(生成doc文档)
- 代码分析:通过代码里标识的元数据对代码进行分析(使用反射)
- 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查(override)
主要使用其代码分析的功能:
使用注解-
预定义注解
- @override
- @Deprecated 已经过时的:建议弃用
- @SuppressWarnings:压制警告:对该方法产生的警告,都进行忽略,参数All
-
自定义注解
-
格式
元注解
publi @inerface 注解名称{}
public @interface MyAno{ int age(); String name() default "zhangsan"; }-
本质:注解本质就是一个接口,该接口默认继承Annotation接口
-
注解的属性:接口中可以定义的抽象方法
-
属性的返回值类型:除了以下类型,其他都不行
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
-
定义了属性,在使用时需要给属性赋值
- 定义属性使用default关键字给属性默认初始化值,使用时不赋值
- 只有一个属性需要赋值,并属性的名字式value,使用时则value可省略,直接定义值即可
- 数组赋值时,值使用{}包裹
-
-
元注解:用于描述注解的注解
- @Target:注解可以使用的位置
- TYPE
- METHOD
- FIELD
- @Retention:注解可以存活到的阶段(三个阶段)注解被 保留 的阶段
- SOURCE
- CLASS
- RUNTIME
- @Documented:注解是否被抽取到api文档
- @Inherited:描述注解是否被子类继承
- @Target:注解可以使用的位置
-
解析注解:使用注解中定义的属性
注解替换配置文件
public class Demo{ public void show(){ System.out.println("show running"); } }@Target({ElementType.TYPE}) @Tetention(RententPolicy.RUNTIME) public @interface Pro{ String className(); String methodName(); }@Pro(className="com.mytest.Demo",methodName="show") public class ReflectTest{ public static void main(Sring[] args){ //解析注解 //获取该类的字节码文件 ClassreflectTestClass = ReflectTest.class; //通过具体的注解类名获取上边的注解对象(在这个大类的字节码文件中所有信息都有的) //在内存中生成了一个该注解接口的子类实现对象ProImpl,而且将响应的数据返回 Pro an = reflectTestClass.getAnnotation(Pro.class); //直接调用注解对象中的抽象方法,获取返回值 String clsaaName = an.className();//获取到了数据"com.mytest.Demo" String methodName = an.methodName(); //加载该类进内存 Class cls = Class.forName(className); //创建对象 Object obj = cls.newInstance(); //获取方法对象 Method method = cls.getMethod(methodName); //执行方法 method.invlke(obj); } } -
总结
-
1、获取注解定义的位置的对象(Class,Method,Field)
-
2、获取指定的注解
getAnnotation(注解.class)
在内存中生成一个该注解接口的子类实现对象
-
调用注解中的抽象方法获取配置的属性值
-
-
-
//要被测试的类,也就是要加@Chack测试注解的类
public class Calculator{
//@Check
public int add(){
System.out.println(1+0);
}
//@Check
public int sub(){
System.out.println(1-0);
}
//@Check
public int mul(){
System.out.println(1*0);
}
//@Check
public int div(){
System.out.println(1/0);//这个是有异常的
}
}
public class TestCheck{
public static void main(String[] args){
//创建计算器对象
Calculator c = new Calculator();
//获取字节码文件
Class cls = c.getClass();
//获取所有方法
Method[] methods = cls.getMethods();
int number = 0;//出现异常的次数
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for(Method method : methods){
//判断方法上是否有Check注解
if(method.isAnnotationPresent(Check.class)){
try{
method.invoke(c); //捕获执行方法时的异常
}catch(Exception e){
//记录异常信息到文件中
number++;
bw.write(method.getName()+"方法出现异常了");
bw.newLine();
bw.write("异常的名称"+e.getCause().getSimpleName());
bw.newLine();
bw.write("异常的原因"+e.getCause().getMessage());
bw.newLine();
bw.write("------------------------");
bw.newLine();
}
}
}
bw.write("本次测试一共出现"+num+"次异常");
bw.flush();
bw.close();
}
}



