栏目分类:
子分类:
返回
终身学习网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
终身学习网 > IT > 软件开发 > 后端开发 > Java

从反射到框架实现原理

Java 更新时间:发布时间: 百科书网 趣学号
反射(Class对象)

框架设计的灵魂 框架是半成品软件,简化编码

概念:将类的各个组成部分封装为其他对象,就是反射机制

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()
注解

概念:

- 注释:文字解释程序功能,给程序员看的
- 注解:也叫元数据    代码级别的说明,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:描述注解是否被子类继承
    • 解析注解:使用注解中定义的属性

      注解替换配置文件

      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){
              //解析注解
          	//获取该类的字节码文件
              Class reflectTestClass = 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();
        
    }
}
转载请注明:文章转载自 www.051e.com
本文地址:http://www.051e.com/it/957270.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 ©2023-2025 051e.com

ICP备案号:京ICP备12030808号