java反射与注解

 反射

我们都知道, 计算机运行代码, 需要经过编译 - 运行这两个步骤, 而反射就是当程序运行状态时, 通过类名, 就知道这个类有什么属性, 有什么方法在里面. 简而言之, 在 Java 中, 只要给定类的名字, 就可以通过反射机制来获得类的所有信息。

反射的使用

 首先要获取到每一个字节码文件(.class)对应的 Class 类型的对象.

//3 种方法获取对象名
a. 通过现有的对象来获取:
​    Class cls = master.getClass();//这里的 master 是一个现有的对象

b. 通过现有的类来获取:
​    Class cls = Master.class;//Master 是一个现有的能够拿到的类

c. 通过字符串, 来得到 Class 对象, 这种方式是我们使用最广泛的一种方式, 如 Hibernate,mybatis 的映射文件
​    Class cls = Class.forName("cn.sz.gl.pojo.Master");//双引号中是 Master 类的  包. 类名

根据以下方法来获取类中的构造方法

//获得所有的构造方法,private 修饰的构造不能获得
Constructor[] cons = cls.getConstructors();

//获得本类所有的构造方法,包括 private 修饰的构造
Constructor[] cons = cls.getDeclaredConstructors();
//得到指定的构造 方法, 如果有多个参数, 中间用 "," 隔开

Constructor con
= cls.getDeclaredConstructor(String.class,Integer.class);
//也可以使用另一种方式来获得:cls.getConstructor(parameterTypes)

获取属性

//获得所有的 public 修饰的属性 (继承自父类的属性也能获得),private 修饰的属性不能获得
Field [] fs = cls.getFields();

//获得本类所有的属性 (继承自父类的属性不能获得),private 修饰的属性也能获得
Field [] fs = cls.getDeclaredFields();

//获得指定的属性
Field f = cls.getDeclaredField("mastername");
//但是,mastername 属性为私有的, 所以要先解除封装
f.setAccessible(true);

//修改指定的属性
f.set(obj, "lisi");

获取方法

//获得所有的方法, 包括继承自父类的方法, 但只能是 public 修饰的方法
Method[] ms =  cls.getMethods();

//获得本类所有的方法, 不包括继承自父类的方法, 但 private 修饰的方法也能获得
Method[] ms = cls.getDeclaredMethods();

//获得指定方法 (无参),show 为方法名
Method ms = cls.getDeclaredMethod("show");

//获得指定方法 (有参)
Method ms = cls.getMethod("print", String.class);

如果为 private 修饰,在调用该方法之前,需要先解除封装:
ms.setAccessible(true);

//通过 invoke 调用方法,obj 表示在哪个对象里调用方法, 后续的参数是方法的传入参数
String str = (String) ms.invoke(obj, "测试有参方法");

注解

注解并不能改变程序的运行结果,也不会影响程序运行的性能。有些注解可以在编译时给用户提示或警告,有的注解可以在运行时读写字节码文件信息。

1. 注解的作用

1、生成文档。这是最常见的,也是 java 最早提供的注解。常用的有 @param @return2、跟踪代码依赖性,实现替代配置文件功能。比如 Spring 的注入,未来 java 开发,将大量注解配置,具有很大用处;
3、在编译时进行格式检查。如 @override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出

2. 下面三个是 java 中的内置注解:

@Deprecated: 当程序使用过时的元素时, 会发出警告

@Override: 用来修饰对父类进行重写的方法

@SuppressWarnings:用来抑制编译器生成警告信息

 

 3.java.lang.annotation 提供了四种元注解

@Documented:表示是否将注解信息添加在 javadoc 文档中

@Retention 用于描述注解的生命周期, 也就是该注解被保留的时间长短

@Target–注解用于什么地方

ElementType.CONSTRUCTOR: 用于描述构造器
ElementType.FIELD: 成员变量、对象、属性(包括 enum 实例)
ElementType.LOCAL_VARIABLE: 用于描述局部变量
ElementType.METHOD: 用于描述方法
ElementType.PACKAGE: 用于描述包
ElementType.PARAMETER: 用于描述参数
ElementType.TYPE: 用于描述类、接口 (包括注解类型) 或 enum 声明

@Inherited – 定义该注释和子类的关系

4. 自定义注解

声明 Test 注解

// 使用 @interface 关键字
public @interface Test {
}

定义成员变量

public @interface Test {
    // 定义带两个成员变量的注解
    // 注解中的成员变量以方法的形式来定义
    String name();
    int age();
    //参数成员只能用 public 或缺省这两个访问权修饰
   //参数成员只能用八种基本数据类型和 String、Enum、Class、annotations 等数据类型, 以及这一些类型的数组.
}

要获取类方法和字段的注解信息,必须通过 Java 的反射技术来获取 Annotation 对象.

例子

自定义一个注解 @FruitName

@Target(ElementType.FIELD)//可以用来修饰对象,属性
@Retention(RetentionPolicy.RUNTIME)//什么时候都不丢弃
@Documented//用于生成 javadoc 文档
public @interface FruitName {
String value() </span><span style="color: rgba(0, 0, 255, 1)">default</span> ""<span style="color: rgba(0, 0, 0, 1)">;

}

创建一个工具类用来处理注解:

public class AnnotationUtil {
    public static Object findInfo(Class clazz){
        Object obj = clazz.newInstance();// 获得对象
        Field fs [] = clazz.getDeclaredFields();// 获得全部的属性
    </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; fs.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">判断该属性上是否有FruitName类型的注解</span>
        <span style="color: rgba(0, 0, 255, 1)">if</span>(fs[i].isAnnotationPresent(FruitName.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)){
            FruitName fn </span>= fs[i].getAnnotation(FruitName.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">为属性赋值</span>
            fs[i].setAccessible(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
            fs[i].set(obj, fn.value());
        }
    }
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> obj;
}

}