1 Star 0 Fork 1

wow / java-notes

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
反射.md 7.30 KB
一键复制 编辑 原始数据 按行查看 历史
wow 提交于 2021-02-25 11:45 . 工程和笔记

定义

Java 反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能调用它的方法和属性;这种动态获取信息以及调用对象方法的功能称之为Java语言的反射机制。

反射提供的功能

  • 在运行时 - 判断任意一个对象所属的类

  • 在运行时 - 构造任意一个类的实例

  • 在运行时 - 判断任意一个类的成员变量和方法

  • 在运行时 - 调用任意对象的方法

java Reflection API简介

类名 用途
Class 代表类的实体,在运行的Java应用程序中表示类和接口
Field 代表类的成员变量/属性
Method 代表类的方法
Constructor 代表类的构造方法

Class对象

Class对象是Java反射的基础,它包含了与类相关的信息,事实上,Class对象就是用来创建类的所有对象的。Class对象是java.lang.Class<T>这个类生成的对象,其中类型参数T表示由此 Class 对象建模的类的类型。例如,String.class的类型是 Class<String>;如果将被建模的类未知,则使用Class<?>。以下是Java API的描述:

Class类的实例表示正在运行的 Java应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。基本的Java类型(boolean、byte、char、short、int、long、float和double)和关键字void也表示为Class对象。

Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。

实际上,每个类都有一个Class对象。换言之,每当编写并且编译了一个新类,就会产生一个Class对象(更恰当的说,是被保存在一个同名的.class文件中)。如果我们想生成这个类的对象,运行这个程序的Java虚拟机(JVM)将使用类加载器子系统,类加载器首先检查这个类的Class对象是否已经加载。如果尚未加载,默认的类加载器就会根据类名查找.class文件,并将其载入,一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有实例。

获取Class对象

  • 通过实例变量的getClass()方法。例如:

    Class c1 = new String("abc").getClass();
  • 通过Class类的静态方法——forName()来实现,例如:

    Class class =Class.forName("com.class");

    注意:当使用Class.forName()方法时,你必须提供完全限定类名。即类名要包括所有包

  • 推荐 - 使用类字面常量或TYPE字段,例如:

    Class myObjectClass= MyObject.class

    (类字面常量不仅可以应用于普通的类,也可以应用于接口、数组以及基本数据类型),这种方式不仅更简单,而且更安全,因为它在编译时就会受到检查,并且根除了对forName方法的调用,所以也更高效,建议使用“.class”的形式。

基本数据类型与Class对象

Class c = Integer.TYPE;TYPE是基本数据类型的包装类型的一个标准字段,它是一

个引用,指向对应的基本数据类型的Class对象,附表如下,两边等价

基本类型 包装类
boolean.class Boolean.TYPE
char.class Character.TYPE
byte.class Byte.TYPE
short.class Short.TYPE
int.class Integer.TYPE
long.class Long.TYPE
float.class Float.TYPE
double.class Double.TYPE
void.class Void.TYPE

代码示例

下面我们使用代码来演示一下反射:

基础类

package com;

public class TargetObject {

    private String value;

    public TargetObject() {
        value = "TargetObject";
    }

    public void publicMethod(String s) {
        System.out.println("publicMethod " + s);
    }

    private void privateMethod() {
        System.out.println("privateMethod " + value);
    }
}

主类

public static void main(String[] args) 
    throws ClassNotFoundException, IllegalAccessException, 
        InstantiationException, NoSuchMethodException, 
        InvocationTargetException, NoSuchFieldException {

        /**
         * 获取TargetObject类的Class对象并且创建TargetObject类实例
         */
        Class<?> tagetClass = Class.forName("com.TargetObject");
        TargetObject targetObject = (TargetObject) tagetClass.newInstance();

        /**
         * 获取所有类中所有定义的方法
         */
        Method[] methods = tagetClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        /**
         * 获取指定方法并调用
         */
        Method publicMethod = tagetClass.getDeclaredMethod("publicMethod",
                String.class);

        publicMethod.invoke(targetObject, "JavaGuide");

        /**
         * 获取指定参数并对参数进行修改
         */
        Field field = tagetClass.getDeclaredField("value");
        //为了对类中的参数进行修改我们取消安全检查
        field.setAccessible(true);
        field.set(targetObject, "JavaGuide");

        /**
         * 调用 private 方法
         */
        Method privateMethod = tagetClass.getDeclaredMethod("privateMethod");
        //为了调用private方法我们取消安全检查
        privateMethod.setAccessible(true);
        privateMethod.invoke(targetObject);
    }

测试工程:reflection-demo

反射机制优缺点

  • 优点: 运行期类型的判断,动态加载类,提高代码灵活度。

  • 缺点

    1. 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。

    2. 安全问题,让我们可以动态操作改变类的属性同时也增加了类的安全隐患。

反射的应用场景

反射是框架设计的灵魂。

在模块化或者是通用性的开发中,我们经常通过反射来创建实例并使用。在我们日常使用spring框架中大量使用到了反射机制

示例:

  1. 在使用原生的JDBC连接数据库时,采用 Class.forName() 通过反射加载数据库的驱动程序。

  2. Spring 框架的IoC(动态创建管理Bean)以及AOP功能都和反射有关系

其他
1
https://gitee.com/superwow/java-notes.git
git@gitee.com:superwow/java-notes.git
superwow
java-notes
java-notes
master

搜索帮助