java进阶知识--反射、junit、注解 一、反射 二、Junit单元测试 三、注解

 1.1 反射机制

    概述:将类的各个组成部分封装成其他对象,在代码运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

    好处:

      1. 可以在程序运行的过程中,操作这些对象;
      2. 可以解耦,提高程序的可扩展性。

    用途:在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的。

    反射机制的相关类:

类名 用途
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法
    java代码在计算机中经历的三个阶段java进阶知识--反射、junit、注解
一、反射
二、Junit单元测试
三、注解

 1.2 获取Class对象的方式

     1. Class.forName("全类名"):将字节码文件加载进内存,返回Class对象
        * 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
     2. 类名.class:通过类名的属性class获取
        * 多用于参数的传递
     3. 对象.getClass():getClass()方法在Object类中定义着。
        * 多用于对象的获取字节码的方式
     结论:
     同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
  小贴士:
    上述三种获取Class对象的方式,刚好对应java代码经历的三个阶段。

 1.3 Class对象功能

    获取功能:
      1. 获取成员变量
         * Field[] getFields() :获取所有public修饰的成员变量
         * Field getField(String name)   获取指定名称的 public修饰的成员变量
 
         * Field[] getDeclaredFields()  获取所有的成员变量,不考虑修饰符
         * Field getDeclaredField(String name)  获取指定名称的成员变量,不考虑修饰符
      2. 获取构造方法
         * Constructor<?>[] getConstructors() 
         * Constructor<T> getConstructor(类<?>... parameterTypes) 
 
         * Constructor<?>[] getDeclaredConstructors() 
         * Constructor<T> getDeclaredConstructor(类<?>... parameterTypes) 
      3. 获取成员方法
         * Method[] getMethods() 
         * Method getMethod(String name, 类<?>... parameterTypes) 
 
         * Method[] getDeclaredMethods() 
         * Method getDeclaredMethod(String name, 类<?>... parameterTypes) 
      4. 获取全类名 
         * String getName()  

 1.4 Field成员变量

    操作:
      1. 设置值
         * void set(Object obj, Object value) 
      2. 获取值
         * get(Object obj)
      3. 当给私有属性get/set时,需忽略访问权限修饰符的安全检查
         * setAccessible(true):暴力反射

 1.5 Constructor构造方法

    创建对象:
      * T newInstance(Object... initargs)

  如果使用空参数构造方法创建对象时,操作可以简化:Class对象.newInstance方法

 1.6 Method方法对象

    * 执行方法:
      * Object invoke(Object obj, Object... args)
    * 获取方法名称:
      * String getName:获取方法名
 

二、Junit单元测试

 2.1 测试分类

    1. 黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
    2. 白盒测试:需要写代码的。关注程序具体的执行流程。

 2.2 Junit使用(白盒测试的一种)

     步骤:
      1. 定义一个测试类(测试用例)
          * 测试类名:被测试的类名Test
          * 包名:xxx.xxx.xx.test
      2. 定义测试方法:可以独立运行
          * 方法名:test测试的方法名  testAdd() 
          * 返回值:void
          * 参数列表:空参
      3. 给方法加@Test
      4. 导入junit依赖环境
      * 判定结果:
        * 一般我们会使用断言操作来处理结果:Assert.assertEquals('期望的结果','运算的结果');
 补充:
    * @Before注解:  修饰的方法会在测试方法之前自动被执行
    * @After注解:  修饰的方法会在测试方法执行之后自动被执行
 

三、注解

 3.1 概述

    注解(Annotation),也叫元数据。一种代码级别的说明,即用来说明程序的。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。
小贴士:它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
    格式:@注解名称

 3.2 注解的作用

    分类:
      ①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
      ②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
      ③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】

 3.3 JDK中预定义的一些注解

    * @Override :检测被该注解标注的方法是否是继承自父类(接口)的
    * @Deprecated:该注解标注的内容,表示已过时
    * @SuppressWarnings:压制警告
        * 一般传递参数all  @SuppressWarnings("all")

 3.4 自定义注解

   3.4.1 格式

      元注解
      public @interface 注解名称{
        属性列表;
      }

   3.4.2 本质

      注解本质上就是一个接口,该接口默认继承Annotation接口。

      如:public interface MyAnno extends java.lang.annotation.Annotation {...}

   3.4.3 属性 

      属性:接口中的抽象方法
        * 要求:
           1. 属性的返回值类型有下列取值
              * 基本数据类型
              * String
              * 枚举
              * 注解
              * 以上类型的数组
           2. 定义了属性,在使用时需要给属性赋值
              * 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
              * 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
              * 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略

   3.4.4 元注解

      元注解:用于描述注解的注解
        * @Target:描述注解能够作用的位置
           * ElementType取值:
              * TYPE:可以作用于类上
              * METHOD:可以作用于方法上
              * FIELD:可以作用于成员变量上
        * @Retention:描述注解被保留的阶段
            * RetentionPolicy取值:
            *CLASS:编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。
            * RUNTIME:编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
            * SOURCE:被修饰的注解只能存在源码中,字节码class没有。编译器要丢弃的注释。

        * @Documented:描述注解是否被抽取到api文档中
        * @Inherited:描述注解是否被子类继承



 面试题:描述一下JVM加载class文件的原理机制?

  JVM中类的装载是由ClassLoader和它的子类来实现的。
  Java ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入类文件的类。