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() default "";
}

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

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

 

 

 

 

posted @ 2022-08-18 15:30  Tmillion  阅读(706)  评论(0编辑  收藏  举报