欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

java反射机制

程序员文章站 2022-04-30 09:09:04
...

java 反射机制

反射机制概念

  • 在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。反射被视为动态语言的关键。简单来说反射就是java的各种成分映射成对应的java类。
  • 通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。包括构造方法,属性,方法。

java反射提供的功能

  • 在运行时判断任意一个对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时调用任意一个对象的方法;
  • 生成动态代理。

java不是动态语言,但是通过反射机制实现动态机制。

反射的基础Class类

类名 用途
Class类 代表类的实体,在运行的java应用程序中表示类和接口
Field类 代表类的成员变量(类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法
  • 类是Class类的实例对象,所以说Class类是所有类的类
  • 想要解剖一个类,必须先获取该类的字节码文件对象,而解剖使用的是Class类中的方法,所以先要获取每一个字节码文件对应的Class类型的对象。
  • Class类由于没有公共的构造方法,Class对象是在类加载的时候由Java虚拟机以及通过调用类加载器中的defineClass 方法自动构造的,因此不能显式地声明一个Class对象。

获取Class的三种方法(获取一个类的字节码对象)

  • 使用对象获取,使用对象的getClass获取

    Person person = new Person();
    Class clazz=person.getClass();
    
  • 使用静态属性class

    Class clazz =Person.class;
    
  • 使用Class类的静态方法forName(字符串的类名)

    • 类要写全名

      Class clazz = Class.forName("")
      

反射的用法

  • 获取Class

    • 使用上文中的三种方法
  • 通过Class获取任意一个类的属性

     //获取该类指定属性名的public成员变量,包括父类的
        Field field = clazzTwo.getField("number");
     //获取该类指定名称声明的变量,即不包括父类的
        Field deField = clazzTwo.getDeclaredField("name");
     //获取该类所有的public声明的成员变量
        Field fields[] = clazzTwo.getFields();
        //获取该对象的所有成员变量
        Field deFields[] = clazzTwo.getDeclaredFields();
    
  • 通过Class获取任意成员方法

    //根据方法名以及参数类型获取,只能获取public声明的方法,包括父类的
        Method method = clazzTwo.getMethod("setAge",Integer.class);
     //根据方法名以及参数名称获取该类声明的所有的属性方法,不包括父类的
        Method deMethod = clazzTwo.getDeclaredMethod("setAge", Integer.class);
    //获取该对象声明的所有的public方法,包括父类的
        Method methods[] = clazzTwo.getMethods();
        //获取该对象声明的所有的方法,但是不包含父类的方法
        Method deMethods[] = clazzTwo.getDeclaredMethods();
    
  • 方法调用

     public static void main(String[] args)throws Exception {
            //获取Class第二种方法
            Class clazzTwo = Test.class;
            //根据方法名以及参数类型获取,只能获取public声明的方法,包括父类的
            Method method = clazzTwo.getMethod("setAge",int.class);
            System.out.println(method);
            //利用Class创建一个对象的实例
            Test test = (Test) clazzTwo.newInstance();
            //函数调用
            Object value = method.invoke(test,20);
            //null
            System.out.println(value);
        }
    

    首先获取一个类的Class,然后通过这个Class获取该类的setAge方法,然后调用这个方法。我们在调用方法前先实例化一个对象(newInstance()),创建一个实例,这种方法需要改实例化的类具有一个无参构造方法。然后通过invoke对方法进行调用,第一个参数是一个实例化的对象,后面就是具体的参数。

  • 通过Class获取构造方法

    	//获取Class第二种方法
        Class clazzTwo = Test.class;
    
        //获取无参构造方法,public声明的,包括父类,加上参数时就是获取特定的构造方法
        Constructor constructor = clazzTwo.getConstructor();
    
     
        System.out.println(constructor);
    
        //获取该类所有的public声明的构造方法
        Constructor constructors[] = clazzTwo.getConstructors();
    
        //获取指定参数的构造方法
        Constructor deConstructor = clazzTwo.getDeclaredConstructor(String.class,Integer.class);
    
        //获取所有的该类的构造方法,不包括父类的
        Constructor deConstructors[] =clazzTwo.getDeclaredConstructors();
    
    Test test = (Test) deConstructor.newInstance("冢狐",21);
    
        System.out.println(student.getAge());
    

反射的用途

利用反射创建数组

public static void main(String[] args)throws ClassNotFoundException {
        Class<?> cls = Class.forName("java.lang.String");
        Object array = Array.newInstance(cls,5);
        // 向数组添加内容
        Array.set(array,0,"Hello");
        Array.set(array,1,"冢");
        Array.set(array,2,"狐");
        Array.set(array,3,"java");
        // 获取数组中指定位置的内容
        System.out.println(Array.get(array,2));
    }

开发各类通用框架

Spring:
  • XML配置bean

    <bean class="com.zhonghu.UserServiceImpl">
    </bean>
    
  • Spring在启动的时候便会利用反射机制去加载对于的类,然后实例化。如果不存在该类则会抛出异常,通常异常中还会出现invoke方法调用的堆栈信息。

  • 当Spring基于注解去实例化对象时,同样利用的是反射机制。下面通过一个简单demo示例,演示一下如何通过反射获得注解信息:

    static void initUser(User user) throws IllegalAccessException {
    
        // 获取User类中所有的属性(getFields无法获得private属性)
        Field[] fields = User.class.getDeclaredFields();
    
        // 遍历所有属性
        for (Field field : fields) {
            // 如果属性上有此注解,则进行赋值操作
            if (field.isAnnotationPresent(InitSex.class)) {
                InitSex init = field.getAnnotation(InitSex.class);
                field.setAccessible(true);
                // 设置属性的性别值
                field.set(user, init.sex().toString());
                System.out.println("完成属性值的修改,修改值为:" + init.sex().toString());
            }
        }
    }
    
相关标签: 所有文章 Java