12_反射

作者: 真是个点子王 | 来源:发表于2020-12-07 10:03 被阅读0次

RTTI

  • RTTI(RunTime Type Information)运行时类型信息,能够在程序运行时发现和使用类型信息。

Class对象

  • 在介绍反射之前,首先需要明确Class对象的知识;
  • Class对象作为特殊的对象,它包含了与类有关的信息。实际上,Class对象就是用来创建该类所有“常规”对象的。Java使用Class对象来实现RTTI;
  • 类是程序的一部分,每个类都有一个Class对象。换言之,每当我们编写并且编译了一个新类,就会产生一个 Class 对象(更恰当的说,是被保存在一个同名的 .class 文件中)。为了生成这个类的对象,Java 虚拟机 (JVM) 先会调用"类加载器"子系统把这个类加载到内存中。所有的类都是第一次使用时动态加载到JVM中的,当程序创建第一个对类的静态成员的引用时,就会加载这个类。
    • 其实构造器也是类的静态方法,虽然构造器前面并没有static关键字。所以,使用new操作符创建类的新对象,这个操作也算作对类的静态成员引用。

反射


  • 反射是指对于任何一个类,在“运行的时候”都可以直接得到这个类的全部成分。
    • 在运行时,可以直接得到这个类的构造器对象。(Constructor)
    • 在运行时,可以直接得到这个类的成员变量对象。(Field)
    • 在运行时,可以直接得到这个类的成员方法对象。(Method)
  • 反射的前提是获得该类字节码文件对象,就是class对象;
  • 反射为一个类的全部成分都设计了一个类型来代表这个对象。
    • Class :字节码文件的类型
    • Constructor:构造器的类型
    • Field:成员变量的类型
    • Method:方法的类型

获取Class类对象

  • 反射的第一步都是获得Class类对象

获取Class类对象的三种方法

  • 1.类名.class
  • 2.通过类的对象.getClass()方法;
  • 3.Class.forName("类的全限名")

Class类下的方法

String getSimpleName();     //获得类名字符串:类名
String getName();      //获得类全名:包名+类名
T newInstance() ;      //创建Class对象关联类的对象,其实底层也是调用无参数构造器,已经被淘汰。

示例代码

public class ReflectDemo01 {
    public static void main(String[] args) throws Exception {
        // 反射的第一步永远是先得到类的Class文件对象: 字节码文件。
        // 1.类名.class
        Class c1 = Student.class;
        System.out.println(c1);

        // 2.对象.getClass()
        Student swk = new Student();
        Class c2 = swk.getClass();
        System.out.println(c2);

        // 3.Class.forName("类的全限名")
        // 直接去加载该类的class文件。
        Class c3 = Class.forName("com.itheima._03反射_获取Class类对象.Student");
        System.out.println(c3);

        System.out.println(c1.getSimpleName()); // 获取类名本身(简名)
        System.out.println(c1.getName()); // 获取类的全限名
        // Student s1 = (Student) c1.newInstance(); // 调用无参数构造器得到对象,被淘汰了
    }
}

获取构造器对象

Constructor类概述

  • 目的:获取构造器对象来创建类的对象;
  • 类中的每一个构造器都会有一个Constructor对象;

反射中Class类对象获取构造器的API

 1. Constructor getConstructor(Class... parameterTypes)
        * 根据参数类型获得对应的Constructor对象。
        * 只能获得public修饰的构造方法
 2. Constructor getDeclaredConstructor(Class... parameterTypes)
         * 根据参数类型获得对应的Constructor对象,包括private
 3. Constructor[] getConstructors()
        获得类中的所有构造方法对象,只能获得public的
 4. Constructor[] getDeclaredConstructors()
        获得类中的所有构造方法对象,包括private修饰的
  • 实例代码:
public class TestStudent {
    // 1. getConstructors
    // 获取全部的构造器:只能获取public修饰的构造器。
    // Constructor[] getConstructors()
    @Test
    public void getConstructors(){
        // a.反射第一步先得到Class类对象
        Class c = Student.class ;
        // b.getConstructors():定位全部构造器,只能拿public修饰的!
        Constructor[] cons = c.getConstructors();
        // c.遍历这些构造器
        for (Constructor con : cons) {
            System.out.println(con.getName()+"===>"+con.getParameterCount());
        }
    }

    // 2.getDeclaredConstructors():
    // 获取全部的构造器:只要你敢写,这里就能拿到,无所谓权限是否可及。
    @Test
    public void getDeclaredConstructors(){
        // a.反射第一步先得到Class类对象
        Class c = Student.class ;
        // b.getDeclaredConstructors():定位全部构造器,只要申明了就可以拿到
        Constructor[] cons = c.getDeclaredConstructors();
        // c.遍历这些构造器
        for (Constructor con : cons) {
            System.out.println(con.getName()+"===>"+con.getParameterCount());
        }
    }

    // 3.getConstructor(Class... parameterTypes)
    // 获取某个构造器:只能拿public修饰的某个构造器
    @Test
    public void getConstructor() throws Exception {
        // a.反射第一步先得到Class类对象
        Class c = Student.class ;
        // b.getConstructor():定位某个构造器,根据参数匹配,只能拿public修饰的!
        // Constructor con = c.getConstructor(); // 报错!
        Constructor con = c.getConstructor(String.class  , int.class); // 有参数的!!
        // c.构造器名称和参数
        System.out.println(con.getName()+"===>"+con.getParameterCount());
    }

    // 4.getDeclaredConstructor
    // 获取某个构造器:只要你敢写,这里就能拿到,无所谓权限是否可及。
    @Test
    public void getDeclaredConstructor() throws Exception {
        // a.反射第一步先得到Class类对象
        Class c = Student.class ;
        // b.getDeclaredConstructor():定位某个构造器,根据参数匹配,只要申明了就可以获取
        Constructor con = c.getDeclaredConstructor(); // 可以拿到!定位无参数构造器!
        //Constructor con = c.getDeclaredConstructor(String.class  , int.class); // 有参数的!!
        // c.构造器名称和参数
        System.out.println(con.getName()+"===>"+con.getParameterCount());
    }
}

Constructor类对象的API

1. T newInstance(Object... initargs)
    根据指定的参数创建对象
2. void setAccessible(true)
   设置是否取消权限检查,true取消权限检查,false表示不取消(暴力反射)
  • 示例代码:
public class TestStudent02 {
    // 1.调用无参数构造器得到一个类的对象返回。
    @Test
    public void createObj01() throws Exception {
        // a.反射第一步是先得到Class类对象
        Class c = Student.class ;
        // b.定位无参数构造器对象
        Constructor constructor = c.getDeclaredConstructor();
        // c.暴力打开私有构造器的访问权限
        constructor.setAccessible(true);
        // d.通过无参数构造器初始化对象返回
        Student swk = (Student) constructor.newInstance(); // 最终还是调用无参数构造器的!
        System.out.println(swk);
    }

    // 2.调用有参数构造器得到一个类的对象返回。
    @Test
    public void createObj02() throws Exception {
        // a.反射第一步是先得到Class类对象
        Class c = Student.class ;
        // b.定位有参数构造器对象
        Constructor constructor = c.getDeclaredConstructor(String.class , int.class);
        // c.通过无参数构造器初始化对象返回
        Student swk = (Student) constructor.newInstance("孙悟空",10000); // 最终还是调用有参数构造器的!
        System.out.println(swk);
    }
}

获取Method方法

  • 目的:操作Method对象来调用成员方法,每个成员方法都是一个Method类对象。

反射中Class类对象获取MethodAPI

* Method getMethod(String name,Class...args);
    * 根据方法名和参数类型获得对应的构造方法对象,只能获得public的

* Method getDeclaredMethod(String name,Class...args);
    * 根据方法名和参数类型获得对应的构造方法对象,包括private的

* Method[] getMethods();
    * 获得类中的所有成员方法对象,返回数组,只能获得public修饰的且包含父类的

* Method[] getDeclaredMethods();
    * 获得类中的所有成员方法对象,返回数组,只获得本类的,包含private修饰的

Method对象常用的API

*  Object invoke(Object obj, Object... args)
    * 调用指定对象obj的该方法
    * args:调用方法时传递的参数
*  void setAccessible(true)
    设置是否取消权限检查,true取消权限检查,false表示不取消(暴力反射)
  • 示例代码
public class MethodDemo01 {
    /**
     * 1.获得类中的所有成员方法对象
     */
    @Test
    public void getDeclaredMethods(){
        // a.先获取class类对象
        Class c = Dog.class ;
        // b.获取全部申明的方法!
        Method[] methods = c.getDeclaredMethods();
        // c.遍历这些方法
        for (Method method : methods) {
            System.out.println(method.getName()+"====>"
                    + method.getParameterCount()+"===>" + method.getReturnType());
        }

    }
    /**
     * 2. 获取某个方法对象
     */
    @Test
    public void getDeclardMethod() throws Exception {
        // a.先获取class类对象
        Class c = Dog.class;
        // b.定位它的某个方法
        Method run = c.getDeclaredMethod("run");
        // c.触发方法执行!
        Dog jinMao = new Dog();
        Object rs = run.invoke(jinMao); // 触发jinMao对象的run()方法执行!
        System.out.println(rs);// 如果方法没有返回值,结果是null

        /**
         * 参数一:方法名称
         * 参数二:方法的参数个数和类型(可变参数!)
         */
        Method eat = c.getDeclaredMethod("eat",String.class);
        eat.setAccessible(true); // 暴力反射!
        /**
         * 参数一:被触发方法所在的对象
         * 参数二:方法需要的入参值
         */
        Object rs1 = eat.invoke(jinMao,"肉");
        System.out.println(rs1);// 如果方法没有返回值,结果是null
    }
}

获取Field成员变量对象

  • 目的:通过Field对象给对应的成员变量赋值和取值,每一个成员变量都是一个Field类对象

反射中Class类对象获取FieldAPI

* Field getField(String name);
    *  根据成员变量名获得对应Field对象,只能获得public修饰
* Field getDeclaredField(String name);
    *  根据成员变量名获得对应Field对象,包含private修饰的
* Field[] getFields();
    * 获得所有的成员变量对应的Field对象,只能获得public的
* Field[] getDeclaredFields();
    * 获得所有的成员变量对应的Field对象,包含private的

Field对象中的API

void set(Object obj, Object value) 
void setInt(Object obj, int i)  
void setLong(Object obj, long l)
void setBoolean(Object obj, boolean z) 
void setDouble(Object obj, double d) 

Object get(Object obj)  
int getInt(Object obj) 
long getLong(Object obj) 
boolean getBoolean(Object ob)
double getDouble(Object obj) 

void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性。
Class getType(); 获取属性的类型,返回Class对象。
  • 示例代码
public class FieldDemo02 {
    @Test
    public void setField() throws Exception {
        // a.反射的第一步获取Class类对象
        Class c = Dog.class ;
        // b.定位name成员变量
        Field nameF = c.getDeclaredField("name");
        // c.为这个成员变量赋值!
        Dog taiDi = new Dog();
        nameF.setAccessible(true); // 暴力反射!
        /**
         * 参数一:被赋值的对象。
         * 参数二:该成员变量的值。
         */
        nameF.set(taiDi , "勇敢的泰迪");
        System.out.println(taiDi);

        // d.获取成员变量的值
        String value = nameF.get(taiDi)+"";
        System.out.println(value);
    }
}

相关文章

  • 12_反射

    RTTI RTTI(RunTime Type Information)运行时类型信息,能够在程序运行时发现和使用类...

  • 2022.6.24(晴)

    今天值班。歌咏比赛。12_

  • Android Chart框架 MPAndroidChart学习

    Android Chart框架 MPAndroidChart学习笔记12_自定义图例 源码demo看这里 这里是项...

  • 12_下标

    下标 可以定义在类、结构体和枚举中,是访问集合、列表或序列中元素的快捷方式。可以使用下标的索引,设置和获取值,而不...

  • 12_复习

    暂无内容

  • 12_脱壳

    什么是加壳? 利用特殊的算法,对可执行文件的编码进行改变(比如压缩、加密),以达到保护程序代码的目的 什么是脱壳?...

  • 第05天(异常、文本文件处理)_03

    11_通过结构体生成json.go 12_通过map生成json.go 13_json解析到结构体.go 14_j...

  • 12_注释符号

    关键词:注释规则 1. 注释规则 编译器在编译过程中使用空格替换整个注释 字符串字面量的//和/*...*/不代表...

  • 12_组合模式

    1.是什么 组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使...

  • 12_快速排序

网友评论

      本文标题:12_反射

      本文链接:https://www.haomeiwen.com/subject/kosowktx.html