• [01] 反射的基本概念和常用类



    1、什么是反射

    在了解反射之前,我们都是如何使用一个Java类的?
    • 已知一个类的类名,以及类中的方法、属性和构造方法等
    • 调用构造方法创建对象
    • 使用对象调用方法或者属性

    那么问题来了,如果我们只知道一个类的类名,能否动态得到类的信息,包括其方法和属性?
    • 通过反射

    所以反射的概念是:在运行状态中,对任意类都可知道其所有属性和方法,对任意对象都可调用其方法和属性。这种动态获取信息以及动态调用对象方法的功能,称之为Java的反射机制。

    如Spring框架只需要通过xml文件描述类的基本信息,就可以利用反射机制动态装配对象。

    2、反射的相关类

    和反射相关的类主要包括 Class、Constructor、Method、Field等,除了Class,其他的类都位于java.lang.reflect包中。其中最重要的类是Class,可以说,反射的使用都是从Class开始的。

    2.1 Class类

    2.1.1 Class实例的获取
    把一个类封装成为Class类,Class实例主要有三种方式获取:
    • //使用对象名获取
    • String str = "hello";
    • Class clazz = str.getClass();

    • //使用类名获取,在类名加后缀 .class
    • Class clazz = String.class;

    • //使用类名获取,通过Class的静态方法forName()
    • Class clazz = Class.forName("java.lang.String");

    2.1.2 Class类的主要方法
    Class类中的主要方法有:
    • getMethod:返回类中某个方法的实例
    • getMethods:返回类中所有方法的实例
    • getField:返回类中某个属性的实例
    • getFields:返回类中所有属性的实例
    • getConstructor:返回类中的一个构造方法的实例
    • getXXX:Class中还有若干get方法,获取类的基本信息

    需要注意的是,以上涉及的获取Method或Field实例的方法,实际上还有一个类似的方法,不过名字中多个词Declared,如getDeclaredMethods(),区别在于:
    • 包含Declared:它仅获取自身类声明的方法,包括公开的、私有的、保护的等
    • 没有Delcared的普通get方法:会获取某个类所有的公开(public)成员,包括自己定义的和继承下来的

    简单示例:
    public static void main(String[] args) { 
        Class clazz_str = String.class;
        Method[] methods = clazz_str.getMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }
    }

    2.2 Constructor类

    2.2.1 实例的获取
    Constructor类的对象是由Class对象获取,Class类中定义了如下方法:
    • Constructor<T> getConstructor(Class... parameterTypes):通过指定参数类型,返回构造方法实例
    • Constructor[] getConstructors():返回该类的所有构造方法实例

    这里所说的指定的参数类型,是指实际构造方法的形参。比如有构造方法 public Student(String name),那么需要:
    Class stuClazz = Student.class;
    Constructor stuCon = stuClazz.getConstructor(String.class);

    2.2.2 实例的基本信息获取
    该类可以通过getXXX的方法,获取构造方法的基本信息,如:
    • getName:返回构造方法的名字
    • getParameterTypes:返回构造方法的参数类型

    2.2.3 创建对象
    除了构造方法的基本信息,也可以通过该Constructor的实例创建对象:
    • newInstance(Object... initargs);

    示例:
    Class stuClazz = Student.class;
    Constructor stuCon = stuClazz.getConstructor(String.class);
    Student stu = (Student)stuCon.newInstance("zhangsan");

    2.3 Method类

    2.3.1 Method的获取
    Method类的实例由Class对象获取:
    • Method getMethod(String name, Class... parameterTypes):通过指定方法名,参数类型,返回Method实例
    • Method[] getMethods():返回该类中所有方法的Method实例

    2.3.2 Method获取基本信息
    Method封装了类中的方法,可以动态获取方法的信息,如:
    • getReturnType:获取方法的返回值类型
    • getName:获得方法名
    • getParameterTypes:获得方法参数类型

    2.3.3 Method动态调用方法
    除了动态获得方法信息,Method类还可以动态调用某个对象的具体方法:
    • invoke(Object obj, Object... args);

    示例:
    public static void main(String[] args) throws Exception {
        Class stuClazz = Student.class;
        Constructor stuCon = stuClazz.getConstructor(String.class);
        Student student = (Student)stuCon.newInstance("zhangsan");
    
        Method study = stuClazz.getMethod("study");
        study.invoke(student);
    
        Method studyWithOne = stuClazz.getMethod("studyWithOne", String.class);
        studyWithOne.invoke(student, "lisi");
    }

    2.4 Field类

    2.4.1 Field的获取
    获得Field实例,都是通过Class中的方法实现的:
    • public Field getField(String name)  
    • 通过指定Field的名字,返回Field实例
    • 注意Field的访问权限

    之前提到过,如果单纯地使用getField那么获取到的方法实例都是public的,如果要获取private方法,需要使用诸如getDeclaredField方法:
    //如有Student类,有private权限的属性name
    Class stuClazz = Student.class;
    Field name = stuClazz.getField("name"); // NG,报异常,找不到该方法
    Field name = stuClazz.getDeclaredField("name"); // OK

    备注:
    Java Field.get()取得对象的Field属性值,即field.get(Class clazz)可以获取对象属性的值,类似于调用无限制的getter方法

    3、反射的重要说明

    反射实际上将所有的类成分映射成为对应的的Class对象,这里的Class对象其实可以堪称是一种类型。并不知只有类才能转换成Class对象。

    也即是说,如果真的需要(比如某些方法中要求参数是Class类型),像基本的数据类型(boolean、byte、char、short、int、long、float、double)甚至关键字如 void 也可以表示为Class对象(形如 int.class)

    比如某些方法,如果你要用反射表示,可能参数可能会写成如 (String.class, int.class) 这种形式,这是sun公司定义的规则,不需要深刻去理解为什么。

    例如 getConstructor(Class<?>... parameterTypes):
    Class stuClazz = Student.class;
    Constructor stuCon = stuClazz.getConstructor(String.class);

  • 相关阅读:
    nginx2
    nginx1
    将Tomcat设置为自动启动的服务最快捷方法
    keepalived VS zookeeper
    Linux CentOS 7 下 Apache Tomcat 7 安装与配置
    使用curl 命令模拟POST/GET请求
    netty3---传统IO,NIO,nettyIO
    个人或小型企业站该如何选择服务器?
    如果你不懂备案,那我简单点跟你说
    SAE Java相关问题小结
  • 原文地址:https://www.cnblogs.com/deng-cc/p/7462557.html
Copyright © 2020-2023  润新知