Java基础(9)-----反射

思维导图

一.体系介绍

Java反射的目的是在运行时获得某个类的所有成员,然后使用.其原理是将一个类的成员进行抽象并通过Class对象获得,然后使用.

在Java的反射jar包,即reflect包中,有三个功能性接口:

  1. Member:一个类中的组成成员的抽象.一个类中,主要有四种成员>>>修饰符,变量,构造方法,普通方法.
  2. AnnotatedElement:表示此成员元素可以被注解,此接口定义了获得注解的方法.
  3. GenericDeclaration:表示这个成员可以配合泛型使用.

此外,由于Java中有一种不太像是OOP的对象,数组,此jar包中有Array对象用以表示数组.

二.具体使用

首先,Class对象是获得各个成员对象的基础,也是媒介.通过Class对象可以获得public成员,指定成员或者所有成员.

举例用的类:
 

//举例用的类,有公共的,私有的,有参数的,无参数的方法,字段,构造方法
class Student{
    public String name;
    private int age;

    public Student(){

    }
    private Student(String name,int age){
        this.name = name;
        this.age = age;
    }

    public void pubInfo(){
        System.out.println("Studnet:" + name + ">>>" + age);
    }
    private void priInfo(String school){
        System.out.println("Studnet:" + name + ">>>" + age + ">>>" + school);
    }
}

Class对象有三种生成方法:

//测试获得Class对象的方法
    public void testBuildClass() throws Exception{
        //通过实例对象获得Class对象,因为反射一般要生成对象,所以不常用
        Student s1 = new Student();
        Class clazz1 = s1.getClass();
        //通过类字面常量获得Class对象,因为必须要导入引用,所以不太常用
        Class clazz2 = Student.class;
        //通过特殊方法获得Class对象,这是最常用的,但必须写全路径的包名
        Class clazz3 = Class.forName("reflectdemo.Student");
    }

接下来说三种主要的成员对象:

2.1Constructor对象 

Constructor对象是对构造方法的抽象,利用他可以在运行时创建对象.

//测试Constructor对象
    public void testConstructor() throws Exception{
        //获得Class对象作为获取的媒介
        Class clazz = Class.forName("reflectdemo.Student");

        //以下方法对于Method,Field对象是通用的,后面介绍时不再重复叙述

        //获得单个指定的public Constructor无参构造器
        Constructor c1 = clazz.getConstructor();
        //获得对象,必须向下转型,newInstance()只会返回Object对象
        Student s1 = (Student)c1.newInstance();
        s1.pubInfo();

        //获得特定的private构造方法
        // 注意,在这里,方法申明里用了int而不是Integer,这里就只能用int.class,用Integer.class会报异常.
        //反射获取方法不支持自动装箱机制
        Constructor c2 = clazz.getDeclaredConstructor(String.class,int.class);
        //私有的访问权限必须先设置为可访问
        c2.setAccessible(true);
        Student s2 = (Student)c2.newInstance("XIAOHAO",21);
        s2.pubInfo();


        //获得所有的构造器
        clazz.getDeclaredConstructors();
        //获得所有的public 构造器
        clazz.getConstructors();
    }

2.2Method对象

Method对象是对方法的抽象,获取方法同Contructor对象大同小异,使用上有些微差别

//测试Method对象
    public void testMothod() throws Exception{
        //获得Class对象作为获取的媒介
        Class clazz = Class.forName("reflectdemo.Student");

        //获取方法时同Constructor有一点差别,需要指定方法名
        Method m1 = clazz.getDeclaredMethod("priInfo", String.class);
        m1.setAccessible(true);
        //输入参数进行调用,注意,调用方法时必须有实例对象,不然会报错
        //静态方法可以不用
        m1.invoke(new Student(),"长春理工大学");
        m1 = clazz.getDeclaredMethod("priStatic",String.class);
        m1.setAccessible(true);
        //也会报异常
        //m1.invoke("xiaohao");
    }

2.3Field对象

Field对象是字段(成员变量)的抽象,获得的方法也差不多,使用则不同于方法,毕竟是字段嘛.

 //测试Field对象
    public void testField() throws Exception{
        //获得Class对象作为获取的媒介
        Class clazz = Class.forName("reflectdemo.Student");

        //获取age字段的对象
        Field f1 = clazz.getDeclaredField("age");
        f1.setAccessible(true);

        Student s1 = new Student();
        //设置指定对象的字段的值
        f1.set(s1,21);
        s1.pubInfo();
        s1.name = "xiaohao";
        //获取指定对象的字段的值
        f1 = clazz.getDeclaredField("name");
        System.out.println(f1.get(s1));
    }

 2.4Modifer对象

是不是觉得还缺了点什么,访问修饰符啊,Modefier就是访问修饰符的抽象,获取和使用都不同于其他三个成员

//测试Modifer对象
    public void testModifier() throws Exception{
        //获得Class对象作为获取的媒介
        Class clazz = Class.forName("reflectdemo.Student");

        //获取age字段的对象
        Field f1 = clazz.getDeclaredField("age");
        f1.setAccessible(true);
        //Class,Field,Constructor,Method都有此方法,获取表示Modifier对象特定数值.
        int x = f1.getModifiers();
        //使用Modifier对象进行解释,toStirng(x)会输出所有修饰符,可以使用Modifier.isPublic()等其他方法进行验证.
        System.out.println(Modifier.toString(x));
    }

最后补充一点,有reflect包的体系可以看出三个主要的成员是实现了获取泛型和注解的功能接口的,这篇文章里就不多说了.使用大同小异.

猜你喜欢

转载自blog.csdn.net/zh328271057/article/details/81878288