对JAVA反射的简单介绍

准备工作:创建一个类

package com.chengyu.reference;

public class ReferenceBean {
    private int age;
    public static final String NAME = "ko";
    public String phone;

    public ReferenceBean(int age, String phone) {
        this.age = age;
        this.phone = phone;
    }

    public ReferenceBean() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

获取Class对象的方式

1、Class.forName("类的权限定名"):返回对应的Class对象(多用于配置文件中)

2、类名.Class:通过类名的属性class来获取(多用于参数传递)

3、对象.getClass:getClass()方法在Object类中定义(多用于对象的获取字节码方式

下面上代码

    public static void classTest()throws Exception
    {
        /**
         * 1.使用Class.forName
         * 2.使用类名.class
         * 3.使用对象.getClass()
         */
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        Class<?> className = ReferenceBean.class;
        ReferenceBean r = new ReferenceBean();
        Class<?> classGet = r.getClass();
        System.out.println(forName.hashCode());
        System.out.println(className.hashCode());
        System.out.println(classGet.hashCode());
    }

执行结果

 我们发现打印的结果相同,所以同一个字节码文件(.class)在一次程序运行过程中,只会被加载一次,不论通过那种方式获取的Class对象都是同一个(所以在使用

synchronized (类名.class){}进行对对象加锁时,锁的是同一个Class对象)

获取成员变量

 public static void fieldGet() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        Field[] fields = forName.getFields(); //获取到所有public修饰的属性
        for(Field f : fields)
        {
            System.out.println("public 修饰的属性:" + f.getName());
        }
        System.out.println("======forName.getFields()======");
        Field phone = forName.getField("phone"); //根据属性名来获取public属性
        System.out.println("根据属性名获取public属性:" + phone.getName());
        System.out.println("==========forName.getField(\"phone\")==========");
        Field[] declaredFields = forName.getDeclaredFields(); //获取到所有的属性包括private的
        for(Field fs : declaredFields)
        {
            System.out.println("所有的属性:" + fs.getName());
        }
        System.out.println("==========forName.getDeclaredFields()==========");

        Field age = forName.getDeclaredField("age");   //根据指定的属性名获取属性包括private
        System.out.println("根据属性名获取属性:"+ age.getName());
        System.out.println("=======forName.getDeclaredField(\"age\")=====");

    }

执行结果

对属性的修改:我们对类进行一下修改 添加一个private的常量

package com.chengyu.reference;

public class ReferenceBean {
    private int age;
    public static final String NAME = "ko";
    public String phone;
    private  final String IDNO = "123456";

    public  String getIDNO() {
        return IDNO;
    }

    public ReferenceBean(int age, String phone) {
        this.age = age;
        this.phone = phone;
    }

    public ReferenceBean() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

下面对属性进行修改

    /**
     * 修改属性
     */
    public static void modifyField() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        //修改public 修饰的属性
        Field phone = forName.getField("phone");
        System.out.println("修改之前phone属性的值:" + bean.getPhone());
        phone.set(bean,"13088888888");               //使用反射进行修改public修饰的属性
        System.out.println("修改public修饰的属性phone:"+bean.getPhone());

        Field age = forName.getDeclaredField("age");
        System.out.println("修改之前age的值" + bean.getAge());
        age.setAccessible(true);                    //这里需要跳过修饰符检查 就是所谓的暴力获取权限
        age.set(bean,18);                             //修改private修饰的属性
        System.out.println("修改private修饰的属性age:" + bean.getAge());

        Field idno = forName.getDeclaredField("IDNO");
        System.out.println("修改之前IDNO属性的值:" + bean.getIDNO());
        idno.setAccessible(true);
        idno.set(bean,"987654321");               //修改private final修饰的常量
        System.out.println("修改private修饰的常量IDNO:" + bean.getIDNO());
    }

执行结果

我们发现对private final修饰的常量的修改好像并未成功,但真的是这样么?

 System.out.println("修改private修饰的常量IDNO:" + idno.get(bean));

我们在这里修改一下,使用反射的方式去获取修改后的值,运行结果如下:

这说明我们修改是成功的,其实主要原因是编译器优化造成的,在get方法中给我返回的值是修改之前的值,而并非常量的引用,所以在我们调用get方法去获取值的时候给我返回的就是没有修改的值,我们在这里将常量的声明稍作修改,骗一下编译器。

 private  final String IDNO = ""==null?"":"123456";

然后将获取的方法改回之前使用get方式

System.out.println("修改private修饰的常量IDNO:" + bean.getIDNO());

然后我们在运行一下,看看运行的结果。

 完美!!!修改成功

接下来我们对private static final修饰的成员变量进行修改,代码如下

 public static void test07() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        //修改 被final和static修饰的属性
        Field name = forName.getField("NAME");
        System.out.println("修改前常量NAME:"+bean.getNAME());
        name.setAccessible(true);
        Field m = name.getClass().getDeclaredField("modifiers");
        m.setAccessible(true);
        int mod = name.getModifiers();  //保存修改之前NAME的访问权限
        m.setInt(name, name.getModifiers() & ~Modifier.FINAL);  //去掉final权限
        name.set(bean,"CY");
        m.setInt(name, mod);             //NAME常量的权限修改回之前的访问权限
        System.out.println("修改被static和final关键字修饰的常量NAME:"+bean.getNAME());
    }

在这里使用set方法是直接修改不了的,反射是不能修改被static和final同时修饰的常量,但是我们可以通过获取的Field来修改常量的访问权限,这里我们可以看一下Field类

这个类中有一个字段modifiers表示字段的访问权限,但是并没有给我们提供修改这个字段的方法,但是我们依然可以使用反射的方式进行修改这个字段,我们看到这个字段是int类型

我们在看一下具体的表示我们查看一下Modifier类

 我们可以看到我们设置的权限为public static final  使用的是16进制表示

如果是public权限 则int类型的最低位表示

如果是static权限 则int类型的从右边到左边第四位表示

如果是final权限 则int类型的从右边到左边第五位表示

所以public static final 权限使用二进制就是 00000000 00000000 00000000 00011001

最后的和就是25,然后我们使用代码来验证一下

    public static void test07() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        //修改 被final和static修饰的属性
        Field name = forName.getField("NAME");
        System.out.println("修改前常量NAME:"+bean.getNAME());
        name.setAccessible(true);
        Field m = name.getClass().getDeclaredField("modifiers");
        m.setAccessible(true);
        int mod = name.getModifiers();  //保存修改之前NAME的访问权限
        System.out.println("修改之前的权限:" + mod);
        m.setInt(name, name.getModifiers() & ~Modifier.FINAL);  //去掉final权限
        name.set(bean,"CY");
        System.out.println("修改后的权限:" + name.getModifiers());
        m.setInt(name, mod);             //NAME常量的权限修改回之前的访问权限
        System.out.println("修改被static和final关键字修饰的常量NAME:"+bean.getNAME());
    }

我们来看一下结果

所以我们可以知道这个字段上二进制的每一个位置所表示的权限。所以我们可以是用位运算进行修改权限。修改一下我们的代码

    public static void test07() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        //修改 被final和static修饰的属性
        Field name = forName.getField("NAME");
        System.out.println("修改前常量NAME:"+bean.getNAME());
        name.setAccessible(true);
        Field m = name.getClass().getDeclaredField("modifiers");
        m.setAccessible(true);
        System.out.println("修改之前的权限:" + name.getModifiers());
        m.setInt(name, name.getModifiers() & ~Modifier.FINAL);  //去掉final权限
        name.set(bean,"CY");
        System.out.println("修改后的权限:" + name.getModifiers());
        m.setInt(name, name.getModifiers() | Modifier.FINAL);             //NAME常量的权限修改回之前的访问权限
        System.out.println("修改回来的权限是:" + name.getModifiers());
        System.out.println("修改被static和final关键字修饰的常量NAME:"+bean.getNAME());
    }

然后我们看一下运行结果:

 OK!完全没有问题,这下我们可以看到反射的威力了吧!

接下来我们来看一下反射是如何来操作构造方法的,修改一下我们的类,添加构造方法和toString方法

package com.chengyu.reference;

public class ReferenceBean {
    private int age;
    public static final String NAME = ""==null?"":"ko";
    public String phone;
    private  final String IDNO = ""==null?"":"123456";

    public static String getNAME() {
        return NAME;
    }

    public  String getIDNO() {
        return IDNO;
    }

    public ReferenceBean(int age, String phone) {
        this.age = age;
        this.phone = phone;
    }
    private ReferenceBean(int age)
    {
        this.age = age;
    }
    public ReferenceBean() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "ReferenceBean{" +
                "age=" + age +
                ", phone='" + phone + '\'' +
                ", IDNO='" + IDNO + '\'' +
                '}';
    }
}

接下来我们看看如何操作构造函数

    public static void constuctorTest() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");

        Constructor<?>[] constructors = forName.getConstructors(); //获取所有的被public修饰的构造方法
        for(Constructor c: constructors)
        {
            System.out.println("获取到的所有被public修饰的构造方法: " + c);
        }
        Constructor<?> constructor = forName.getConstructor(int.class, String.class); //根据参数列表获取指定的public修饰的构造方法
        Object o = constructor.newInstance(18, "13584789546");  //创建对象
        System.out.println("根据参数列表获取指定的public修饰的构造方法创建的对象: " + o);

        Constructor<?> [] declaredConstructor = forName.getDeclaredConstructors();//获取到所有的构造函数包括private修饰的
        for(Constructor cc : declaredConstructor)
        {
            System.out.println("获取到的所有的构造函数包括private修饰的: " + cc);
        }
        Constructor<?> declaredConstructor1 = forName.getDeclaredConstructor(int.class);//获取到指定参数列表的构造函数,包括private修饰的
        declaredConstructor1.setAccessible(true);  //跳过权限检查
        Object o1 = declaredConstructor1.newInstance(18); //创建对象
        System.out.println("根据指定参数获取到的private修饰的构造函数创建的对象 : " + o1);

    }

然后我们来看看运行的结果

 完全没有问题

这里如果我们如果使用无参的构造函数我们可以直接使用

forName.getClass().newInstance();这种方式来创建对象

接下来我们看看怎样使用反射对方法进行操作

首先修改一下我们的类

package com.chengyu.reference;

public class ReferenceBean {
    private int age;
    public static final String NAME = ""==null?"":"ko";
    public String phone;
    private  final String IDNO = ""==null?"":"123456";

    public static String getNAME() {
        return NAME;
    }

    public  String getIDNO() {
        return IDNO;
    }

    public ReferenceBean(int age, String phone) {
        this.age = age;
        this.phone = phone;
    }
    private ReferenceBean(int age)
    {
        this.age = age;
    }
    public ReferenceBean() {
    }

    private String study(String name)
    {
        System.out.println(name + "在学习。。。。。");
        return name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "ReferenceBean{" +
                "age=" + age +
                ", phone='" + phone + '\'' +
                ", IDNO='" + IDNO + '\'' +
                '}';
    }
}

然后上代码

    public static void methodTest()throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        Method[] methods = forName.getMethods();//获取所有被public修饰的方法包含父类的方法
        for(Method m : methods)
        {
            System.out.println("获取所有被public修饰的方法包含父类的方法 : " + m);
        }
        Method setAge = forName.getMethod("setAge", int.class); //根据方法名称和参数列表获取指定方法
        setAge.invoke(bean, 18); //方法调用第一个参数是对象的实例,第二个参数是给setAge方法传入的参数
        System.out.println("根据方法名称和参数列表获取指定方法,然后调用方法: " + bean.getAge()); //这里我们进行一下验证看看age是否设置进去了

        Method[] declaredMethods = forName.getDeclaredMethods(); //获取所有的方法包括被private的修饰的不包含父类的方法
        for(Method mm : declaredMethods)
        {
            System.out.println("获取所有的方法包括被private的修饰的不包含父类的方法" + mm);
        }
        Method study = forName.getDeclaredMethod("study", String.class);//根据方法名和参数列表获取指定的方法(可以获取到private修饰的方法)
        study.setAccessible(true); //跳过访问权限检查
        Object ss = study.invoke(bean, "学生"); //在这里我们可以获取到方法的返回值
        System.out.println("根据方法名和参数列表获取指定的方法(可以获取到private修饰的方法),获取到的返回值是 : " + String.valueOf(ss));

    }

看一下我们的运行结果

 接下来我们看看怎么利用反射对注解进行解析

添加一个自定义注解

package com.chengyu.reference;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) //这里是元注解,表示我自定义的注解可以在类、方法、属性上使用
@Retention(RetentionPolicy.RUNTIME)   //这个表示注解保留的阶段为运行时 我们要是反射来获取所有不能将注解保留在其他阶段 否者就获取不到注解了
public @interface MyAnn {
    int age() default 18;
    String name() default "KO";
}

修改一下我们的类 在类、方法、属性上添加注解

package com.chengyu.reference;


@MyAnn
public class ReferenceBean {
    private int age;
    public static final String NAME = ""==null?"":"ko";
    @MyAnn(age = 15,name = "小小")
    public String phone;
    private  final String IDNO = ""==null?"":"123456";

    public static String getNAME() {
        return NAME;
    }

    public  String getIDNO() {
        return IDNO;
    }

    public ReferenceBean(int age, String phone) {
        this.age = age;
        this.phone = phone;
    }
    private ReferenceBean(int age)
    {
        this.age = age;
    }
    public ReferenceBean() {
    }

    @MyAnn(age = 20,name = "KO大师")
    private String study(String name)
    {
        System.out.println(name + "在学习。。。。。");
        return name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "ReferenceBean{" +
                "age=" + age +
                ", phone='" + phone + '\'' +
                ", IDNO='" + IDNO + '\'' +
                '}';
    }
}

然后我们来看看如何使用反射来解析注解

 public static void annTest() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        boolean annotationPresent = forName.isAnnotationPresent(MyAnn.class);//首先判断我们类上面是否使用了MyAnn注解
        Annotation[] annotations = forName.getAnnotations(); //这里是获取所有的注解
        for(Annotation a : annotations)
        {
            System.out.println("获取类上所有的注解: " + a);
        }
        if(annotationPresent)
        {
            MyAnn annotation = forName.getAnnotation(MyAnn.class); //在指定获取注解是需要进行判断是否使用了这个注解
            System.out.println("指定获取类上面的注解: name = " + annotation.name() + " age = " + annotation.age() );

        }
        Field phone = forName.getField("phone");
        Annotation[] annotations1 = phone.getAnnotations(); //获取成员变量上所有的注解
        for(Annotation a : annotations1)
        {
            System.out.println("获取指定成员变量上所有的注解:" + a);
        }
        boolean annotationPresent1 = phone.isAnnotationPresent(MyAnn.class);
        if(annotationPresent1)
        {
            MyAnn annotation = phone.getAnnotation(MyAnn.class);//指定获取成员变量上的注解
            int age = annotation.age();
            String name = annotation.name();
            phone.set(bean,name);   //将注解上的name赋值给phone字段
            System.out.println("指定获取成员变量上的注解 : " + bean.getPhone());
        }

        Method study = forName.getDeclaredMethod("study", String.class);
        Annotation[] annotations2 = study.getAnnotations(); //获取方法上所有的注解
        for(Annotation aa : annotations2)
        {
            System.out.println("获取方法上所有的注解:" + aa);
        }
        boolean annotationPresent2 = study.isAnnotationPresent(MyAnn.class);
        if(annotationPresent2)
        {
            MyAnn annotation = study.getAnnotation(MyAnn.class);//指定获取方法上的注解
            int age = annotation.age();
            String name = annotation.name();
            study.setAccessible(true); //跳过权限检查
            Object invoke = study.invoke(bean, name);//将注解的name信息作为study方法的入参,调用study方法,获取到返回信息进行打印
            System.out.println("指定获取方法上的注解:" + String.valueOf(invoke));

        }

    }

然后看一下执行结果

 到此为止,反射的基本用法已经介绍完了,我们可以看得到反射的强大,写这篇文章希望能够帮助大家更好的理解反射,java的反射使用的地方很多很多,在很多的框架中都使用到了反射。

最后上传一下最终版本的代码,供大家测试使用

package com.chengyu.reference;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ReferenceTest
{
    public static void main(String[] args) throws Exception {
        //classTest();
        //fieldGet();
        //modifyField();
        //test07();
        //constuctorTest();
        //methodTest();
        annTest();
    }

    /**
     * 获取Class对象
     */
    public static void classTest()throws Exception
    {
        /**
         * 1.使用Class.forName
         * 2.使用类名.class
         * 3.使用对象.getClass()
         */
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        Class<?> className = ReferenceBean.class;
        ReferenceBean r = new ReferenceBean();
        Class<?> classGet = r.getClass();
        System.out.println(forName.hashCode());
        System.out.println(className.hashCode());
        System.out.println(classGet.hashCode());
    }

    /**
     * 获取属性
     */
    public static void fieldGet() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        Field[] fields = forName.getFields(); //获取到所有public修饰的属性
        for(Field f : fields)
        {
            System.out.println("public 修饰的属性:" + f.getName());
        }
        System.out.println("======forName.getFields()======");
        Field phone = forName.getField("phone"); //根据属性名来获取public属性
        System.out.println("根据属性名获取public属性:" + phone.getName());
        System.out.println("==========forName.getField(\"phone\")==========");
        Field[] declaredFields = forName.getDeclaredFields(); //获取到所有的属性包括private的
        for(Field fs : declaredFields)
        {
            System.out.println("所有的属性:" + fs.getName());
        }
        System.out.println("==========forName.getDeclaredFields()==========");

        Field age = forName.getDeclaredField("age");   //根据指定的属性名获取属性包括private
        System.out.println("根据属性名获取属性:"+ age.getName());
        System.out.println("=======forName.getDeclaredField(\"age\")=====");
    }

    /**
     * 修改属性
     */
    public static void modifyField() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        //修改public 修饰的属性
        Field phone = forName.getField("phone");
        System.out.println("修改之前phone属性的值:" + bean.getPhone());
        phone.set(bean,"13088888888");               //使用反射进行修改public修饰的属性
        System.out.println("修改public修饰的属性phone:"+bean.getPhone());

        Field age = forName.getDeclaredField("age");
        System.out.println("修改之前age的值" + bean.getAge());
        age.setAccessible(true);                    //这里需要跳过修饰符检查 就是所谓的暴力获取权限
        age.set(bean,18);                             //修改private修饰的属性
        System.out.println("修改private修饰的属性age:" + bean.getAge());

        Field idno = forName.getDeclaredField("IDNO");
        System.out.println("修改之前IDNO属性的值:" + bean.getIDNO());
        idno.setAccessible(true);
        idno.set(bean,"987654321");               //修改private final修饰的常量
        System.out.println("修改private修饰的常量IDNO:" + bean.getIDNO());



    }


    public static void test07() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        //修改 被final和static修饰的属性
        Field name = forName.getField("NAME");
        System.out.println("修改前常量NAME:"+bean.getNAME());
        name.setAccessible(true);
        Field m = name.getClass().getDeclaredField("modifiers");
        m.setAccessible(true);
        System.out.println("修改之前的权限:" + name.getModifiers());
        m.setInt(name, name.getModifiers() & ~Modifier.FINAL);  //去掉final权限
        name.set(bean,"CY");
        System.out.println("修改后的权限:" + name.getModifiers());
        m.setInt(name, name.getModifiers() | Modifier.FINAL);             //NAME常量的权限修改回之前的访问权限
        System.out.println("修改回来的权限是:" + name.getModifiers());
        System.out.println("修改被static和final关键字修饰的常量NAME:"+bean.getNAME());
    }

    public static void constuctorTest() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");


        Constructor<?>[] constructors = forName.getConstructors(); //获取所有的被public修饰的构造方法
        for(Constructor c: constructors)
        {
            System.out.println("获取到的所有被public修饰的构造方法: " + c);
        }
        Constructor<?> constructor = forName.getConstructor(int.class, String.class); //根据参数列表获取指定的public修饰的构造方法
        Object o = constructor.newInstance(18, "13584789546");  //创建对象
        System.out.println("根据参数列表获取指定的public修饰的构造方法创建的对象: " + o);

        Constructor<?> [] declaredConstructor = forName.getDeclaredConstructors();//获取到所有的构造函数包括private修饰的
        for(Constructor cc : declaredConstructor)
        {
            System.out.println("获取到的所有的构造函数包括private修饰的: " + cc);
        }
        Constructor<?> declaredConstructor1 = forName.getDeclaredConstructor(int.class);//获取到指定参数列表的构造函数,包括private修饰的
        declaredConstructor1.setAccessible(true);  //跳过权限检查
        Object o1 = declaredConstructor1.newInstance(18); //创建对象
        System.out.println("根据指定参数获取到的private修饰的构造函数创建的对象 : " + o1);

    }

    public static void methodTest()throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        Method[] methods = forName.getMethods();//获取所有被public修饰的方法包含父类的方法
        for(Method m : methods)
        {
            System.out.println("获取所有被public修饰的方法包含父类的方法 : " + m);
        }
        Method setAge = forName.getMethod("setAge", int.class); //根据方法名称和参数列表获取指定方法
        setAge.invoke(bean, 18); //方法调用第一个参数是对象的实例,第二个参数是给setAge方法传入的参数
        System.out.println("根据方法名称和参数列表获取指定方法,然后调用方法: " + bean.getAge()); //这里我们进行一下验证看看age是否设置进去了

        Method[] declaredMethods = forName.getDeclaredMethods(); //获取所有的方法包括被private的修饰的不包含父类的方法
        for(Method mm : declaredMethods)
        {
            System.out.println("获取所有的方法包括被private的修饰的不包含父类的方法" + mm);
        }
        Method study = forName.getDeclaredMethod("study", String.class);//根据方法名和参数列表获取指定的方法(可以获取到private修饰的方法)
        study.setAccessible(true); //跳过访问权限检查
        Object ss = study.invoke(bean, "学生"); //在这里我们可以获取到方法的返回值
        System.out.println("根据方法名和参数列表获取指定的方法(可以获取到private修饰的方法),获取到的返回值是 : " + String.valueOf(ss));

    }

    public static void annTest() throws Exception
    {
        Class<?> forName = Class.forName("com.chengyu.reference.ReferenceBean");
        ReferenceBean bean = (ReferenceBean)forName.newInstance();
        boolean annotationPresent = forName.isAnnotationPresent(MyAnn.class);//首先判断我们类上面是否使用了MyAnn注解
        Annotation[] annotations = forName.getAnnotations(); //这里是获取所有的注解
        for(Annotation a : annotations)
        {
            System.out.println("获取类上所有的注解: " + a);
        }
        if(annotationPresent)
        {
            MyAnn annotation = forName.getAnnotation(MyAnn.class); //在指定获取注解是需要进行判断是否使用了这个注解
            System.out.println("指定获取类上面的注解: name = " + annotation.name() + " age = " + annotation.age() );

        }
        Field phone = forName.getField("phone");
        Annotation[] annotations1 = phone.getAnnotations(); //获取成员变量上所有的注解
        for(Annotation a : annotations1)
        {
            System.out.println("获取指定成员变量上所有的注解:" + a);
        }
        boolean annotationPresent1 = phone.isAnnotationPresent(MyAnn.class);
        if(annotationPresent1)
        {
            MyAnn annotation = phone.getAnnotation(MyAnn.class);//指定获取成员变量上的注解
            int age = annotation.age();
            String name = annotation.name();
            phone.set(bean,name);   //将注解上的name赋值给phone字段
            System.out.println("指定获取成员变量上的注解 : " + bean.getPhone());
        }

        Method study = forName.getDeclaredMethod("study", String.class);
        Annotation[] annotations2 = study.getAnnotations(); //获取方法上所有的注解
        for(Annotation aa : annotations2)
        {
            System.out.println("获取方法上所有的注解:" + aa);
        }
        boolean annotationPresent2 = study.isAnnotationPresent(MyAnn.class);
        if(annotationPresent2)
        {
            MyAnn annotation = study.getAnnotation(MyAnn.class);//指定获取方法上的注解
            int age = annotation.age();
            String name = annotation.name();
            study.setAccessible(true); //跳过权限检查
            Object invoke = study.invoke(bean, name);//将注解的name信息作为study方法的入参,调用study方法,获取到返回信息进行打印
            System.out.println("指定获取方法上的注解:" + String.valueOf(invoke));

        }

    }


}
package com.chengyu.reference;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) //这里是元注解,表示我自定义的注解可以在类、方法、属性上使用
@Retention(RetentionPolicy.RUNTIME)   //这个表示注解保留的阶段为运行时 我们要是反射来获取所有不能将注解保留在其他阶段 否者就获取不到注解了
public @interface MyAnn {
    int age() default 18;
    String name() default "KO";
}
package com.chengyu.reference;


@MyAnn
public class ReferenceBean {
    private int age;
    public static final String NAME = ""==null?"":"ko";
    @MyAnn(age = 15,name = "小小")
    public String phone;
    private  final String IDNO = ""==null?"":"123456";

    public static String getNAME() {
        return NAME;
    }

    public  String getIDNO() {
        return IDNO;
    }

    public ReferenceBean(int age, String phone) {
        this.age = age;
        this.phone = phone;
    }
    private ReferenceBean(int age)
    {
        this.age = age;
    }
    public ReferenceBean() {
    }

    @MyAnn(age = 20,name = "KO大师")
    private String study(String name)
    {
        System.out.println(name + "在学习。。。。。");
        return name;
    }
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "ReferenceBean{" +
                "age=" + age +
                ", phone='" + phone + '\'' +
                ", IDNO='" + IDNO + '\'' +
                '}';
    }
}

代码中有很多注释,所以就不在啰嗦了,欢迎大家留言。

原创不易,不喜勿喷,有更好的建议,欢迎留言!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

执念向往

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值