细说java系列之反射

什么是反射

反射机制允许在Java代码中获取被JVM加载的类信息,如:成员变量,方法,构造函数等。

在Java包java.lang.reflect下提供了获取类和对象反射信息的相关工具类和接口,如:Field,Method,Constructor

使用反射可以做什么事情

反射通常被用于需要检查或修改应用程序运行时行为的编程中,它是一个非常有用的技术。

具体来讲,可以在如下场景中使用反射机制:

  • 功能扩展,应用程序可以通过反射创建一个具备完整限定名的类实例,从而使用一个外部的用户自定义的类。
  • 在可视化的开发环境中浏览类信息,其实在eclipse中通过快捷键Ctrl + O显示的类信息就是利用反射机制实现的。
  • 用于程序调试器和测试工具

反射的缺点

虽然反射机制可以增强应用程序的功能和使用场景,但并非在任何情况下都适合使用的,因为反射机制本身存在一些固有的缺点。

  1. 性能损耗,反射需要动态解析类型,相比起不使用反射的情况是存在性能损耗的,所以在性能比较敏感或重要的应用程序中不要使用反射。
  2. 安全限制,反射需要的运行时权限在安全管理器(SecurityManager)下是被禁止的,比Applet程序中。
  3. 类结构被暴露,由于反射允许在非反射代码中执行一些非法操作,打破了Java原本的抽象模型,可能会影响到平台的行为与升级。

应用实践

/**
 * 利用反射机制获取被JVM加载的类信息,实例化类对象。
 * @desc org.chench.test.java.UserReflector
 * @author [email protected]
 * @date 2017年11月30日
 */
public class UserReflector {
    public static void main(String[] args) throws Exception {
        String className = "org.chench.test.java.User";

        // 通过类的完整限定名获取其Class对象
        Class<?> userClass = Class.forName(className);

        // 使用反射机制获取类的构造函数列表
        Constructor[] constructorArr =  userClass.getConstructors();
        for(Constructor constructor : constructorArr) {
            // 构造函数的名称
            String name = constructor.getName();
            System.out.println("constructor name: " + name);

            // 构造函数的参数个数
            int count = constructor.getParameterCount();
            System.out.println("constructor parameter count: " + count);

            // 构造函数的参数列表
            Parameter[] parameters = constructor.getParameters();
            for(Parameter parameter : parameters) {
                // 获取参数类型
                Class<?> parameterType = parameter.getType();
                // 获取参数名
                String parameterName = parameter.getName();
                System.out.println(parameterName + " Type: " + parameterType);
            }

            // 通过构造函数实例化类对象
            if(count <= 0) {
                User user = (User) constructor.newInstance();
                System.out.println("user instance: " + user);
            }else if(count == 1) {
                User user = (User) constructor.newInstance(new Object[] {"Zhang San"});
                System.out.println("user instance: " + user);
            }else if(count == 2) {
                User user = (User) constructor.newInstance(new Object[] {"Li Si", 26});
                System.out.println("user instance: " + user);
            }
            System.out.println("----------");
        }

        // 使用反射机制获取类的成员变量
        Field[] fields = userClass.getDeclaredFields();
        for(Field field : fields) {
            // 变量类型
            Class<?> fieldType = field.getType();
            // 变量名称
            String fieldName =  field.getName();
            // 变量修饰符,private:2,public:1, protected: 4,默认类型: 0
            int fieldModifier = field.getModifiers();
            System.out.println("field info, name: " + fieldName + ", type: " + fieldType + ", modifier: " + fieldModifier);
        }

        // 使用反射机制获取类的方法
        Method[] methods = userClass.getDeclaredMethods();
        for(Method method : methods) {
            // 方法返回值类型
            Class<?> returnType = method.getReturnType();
            // 方法名
            String methodName = method.getName();
            // 方法参数个数
            int count = method.getParameterCount();
            System.out.println("method info, name: " + methodName + ", return type: " + returnType + ", parameter count: " +count);
        }
    }
}

实际上,在应用编程中使用反射机制最多的场景主要是如下2个方面:

  1. 在注解解析器中通过反射获取类,方法或成员变量的注解信息。
  2. 在动态代理类中使用反射机制调用方法执行。

【参考】

https://docs.oracle.com/javase/tutorial/reflect/TOC.html

时间: 2024-08-03 10:34:11

细说java系列之反射的相关文章

细说java系列之HashMap原理

类图 在正式分析HashMap实现原理之前,先来看看其类图. 源码解读 下面集合HashMap的put(K key, V value)方法探究其实现原理. // 在HashMap内部用于存放插入数据的是一个名为"table"的一维Node对象数组 // Node对象为实际存放插入数据Key和Value的数据结构 transient Node<K,V>[] table; // 外部调用插入数据的接口方法 public V put(K key, V value) { retur

Java系列笔记(2) - Java RTTI和反射机制

目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这就是RTTI(Runtime Type Information,运行时类型信息). 在java中,有两种RTTI的方式,一种是传统的,即假设在编译时已经知道了所有的类型:还有一种,是利用反射机制,在运行时再尝试确定类型信息. 本文主要讲反射方式实现的RTTI,建议在阅读本文之前,先了解类的加载机制(

Java学习系列(二十)Java面向对象之反射详解

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45289391 前言 今天讲讲Java中的反射.我们常见的反射多用于JDBC中的加载驱动程序Class.forName("com.mysql.jdbc.Driver");.Struts的MVC.Hibernate中的ORM.Spring中的IOC还有一些其他框架等等.那它有什么好处呢?它的好处就是能够动态的创建对象和编译且能够访问某个类中的所有(包括私有)属性方法及对象的属性方法

Java系列文章(全)

JVM JVM系列:类装载器的体系结构 JVM系列:Class文件检验器 JVM系列:安全管理器 JVM系列:策略文件 Java垃圾回收机制 深入剖析Classloader(一)--类的主动使用与被动使用 深入剖析Classloader(二)-根类加载器,扩展类加载器与系统类加载器 深入理解JVM-JVM内存模型 JVM-堆与栈 JVM调优总结-基本垃圾回收算法 JVM调优总结-垃圾回收面临的问题 JVM调优总结-分代垃圾回收详述 JVM架构解析 触发JVM进行Full GC的情况及应对策略 J

Java系列笔记(1) - Java 类加载与初始化

目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一个原生的类加载器,它只加载Java API等可信类,通常只是在本地磁盘中加载,这些类一般就够我们使用了.如果我们需要从远

【转载】Java系列笔记(1) - Java 类加载与初始化

Java系列笔记(1) - Java 类加载与初始化 原文地址:http://www.cnblogs.com/zhguang/p/3154584.html 目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一

Java系列笔记 - 线程

1,线程原理和概念 当代操作系统,大多数都支持多任务处理.对于多任务的处理,有两个常见的概念:进程和线程.      进程是操作系统分配资源的单位,这里的资源包括CPU.内存.IO.磁盘等等设备,进程之间切换时,操作系统需要分配和回收这些资源,所以其开销相对较大(远大于线程切换):      线程是CPU分配时间的单位,理论上,每个进程至少包含一个线程,每个线程都寄托在一个进程中.一个线程相当于是一个进程在内存中的某个代码段,多个线程在切换时,CPU会根据其优先级和相互关系分配时间片.除时间切换

Java 基础总结--反射的基本操作

一.反射的概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制.要想解剖一个类,必须先要获取到该类的字节码文件对象.而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象. 通俗的说,java虚拟机在加载类的时候会找到对应的class文件,并生成一个class对象,每个类class对象只会生成一次,

我爱java系列---【自定义注解】

一.注解概述 1.定义:注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类. 接口.枚举是在同一个层次.它可以声明在包.类.字段.方法.局部变量.方法参数等的前面,用来对这些元素 进行说明,注释. 2.作用分类: 编写文档:通过代码里标识的注解生成文档[例如,生成文档doc文档] 代码分析:通过代码里标识的注解对代码进行分析[例如,注解的反射] 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查[例如,Override] 3.常