一. 什么是反射

在运行状态中,对于任意一个类,都能够知道其所有属性和方法,对于任意一个对象,都能够调用其任意方法和属性,这种动态获取信息、动态调用方法的能力称为Java语言的反射机制,大部分框架都有用到反射机制,了解反射的使用方法非常重要。

一个类通常包含了属性、方法、构造函数等,而Java一般情况下是现有类再有对象,通过对象调用各种属性和方法,而Java反射则是通过已有的对象,反过来得到其所属类的相关信息,调用所属类的相关方法。

二. 反射的基础Class

2.1 Class类概述

我们知道在Java的世界中,万事万物皆对象。其实类本身也是对象,任何一个类都是Class类的实例对象。

  1. //定义了一个SuperHero的类
  2. public class SuperHero {}

如上面定义的SuperHero类,是类也是对象,

对象:SuperHero类是Class类的实例,Class类是SuperHero的类类型,故而为对象;

类:以类的方式创建,SuperHero本身可以调用SuperHero ironMan = new SuperHero ()被实例化,ironMan 就是创建的实体,故而也是类。

Class类很特殊,它表示了某个类的类类型,被不可被继承,每个类的Class对象仅有一个,Class类没有公共构造函数。 相反, Class对象由Java虚拟机自动构建,因为加载了类,并且通过调用类加载器中的defineClass方法,原始Java类型( booleanbytecharshortintlongfloatdouble ),和关键字void也表示为Class对象

  1. //Class源码,final修饰不可被继承,构造函数是private的,不可手动实例化
  2. public final class Class<T> {
  3. private Class(ClassLoader loader) {
  4. // Initialize final field for classLoader. The initialization value of non-null
  5. // prevents future JIT optimizations from assuming this final field is null.
  6. classLoader = loader;
  7. }
  8. }
  1. public static void main(String[] args) {
  2. try {
  3. Class clazz1 = Class.forName("java.lang.Integer");
  4. Class clazz2 = Class.forName("java.lang.Integer");
  5. System.out.println(clazz1 == clazz2);
  6. System.out.println(int.class);
  7. System.out.println(void.class);
  8. } catch (ClassNotFoundException e) {
  9. e.printStackTrace();
  10. }
  11. }

运行结果为:

  1. true
  2. int
  3. void

2.2 Class类对象获取的三种方式

先定义一个类

  1. package reflectdemo;
  2. import java.io.Serializable;
  3. /**
  4. * 超级英雄类
  5. */
  6. public class SuperHero implements Serializable {
  7. public static final String ADDRESS = "earth";
  8. private String id;
  9. private String name;
  10. private Integer age;
  11. private String skill;
  12. public SuperHero() {
  13. }
  14. public SuperHero(String id, String name, Integer age, String skill) {
  15. this.id = id;
  16. this.name = name;
  17. this.age = age;
  18. this.skill = skill;
  19. }
  20. public String getId() {
  21. return id;
  22. }
  23. public void setId(String id) {
  24. this.id = id;
  25. }
  26. public String getName() {
  27. return name;
  28. }
  29. public void setName(String name) {
  30. this.name = name;
  31. }
  32. public Integer getAge() {
  33. return age;
  34. }
  35. public void setAge(Integer age) {
  36. this.age = age;
  37. }
  38. public String getSkill() {
  39. return skill;
  40. }
  41. public void setSkill(String skill) {
  42. this.skill = skill;
  43. }
  44. public void print(){
  45. System.out.println("超级英雄:" + this.name);
  46. }
  47. }

2.2.1 通过对象获取Class

  1. public static void main(String[] args) {
  2. SuperHero ironMan = new SuperHero("1","钢铁侠",35, "战甲");
  3. Class clazz = ironMan.getClass();
  4. System.out.println(clazz.getName());
  5. }

输出结果:

  1. reflectdemo.SuperHero

2.2.2 通过类获取Class

  1. public static void main(String[] args) {
  2. Class clazz = SuperHero.getClass();
  3. System.out.println(clazz.getName());
  4. }

输出结果:

  1. reflectdemo.SuperHero

2.2.3 传入类路径获取Class

  1. public static void main(String[] args) {
  2. try {
  3. Class clazz = Class.forName("reflectdemo.SuperHero");
  4. System.out.println(clazz.getName());
  5. } catch (ClassNotFoundException e) {
  6. e.printStackTrace();
  7. }
  8. }

输出结果:

  1. reflectdemo.SuperHero

三种创建方式:

第一种方式对象已经有了,所有的操作直接通过该对象进行即可,

第二种方式需要import将类引入,也不是常用的方式,

第三种仅需传入类的路径,即可得到类的相关信息,是最常用的方式。

2.2.4 获取类信息的常用方法

  1. public static void main(String[] args) {
  2. try {
  3. Class clazz = Class.forName("reflectdemo.SuperHero");
  4. //获取类名称(含路径)
  5. System.out.println(clazz.getName());
  6. //获取类名称(不含路径)
  7. System.out.println(clazz.getSimpleName());
  8. //获取所在包
  9. System.out.println(clazz.getPackage());
  10. //通过Class创建对象
  11. SuperHero hero = (SuperHero)clazz.newInstance();
  12. } catch (ClassNotFoundException e) {
  13. e.printStackTrace();
  14. }
  15. }

输出结果:

  1. reflectdemo.SuperHero
  2. SuperHero
  3. package reflectdemo

这里提前说明一下:Class中两个功能相同的方法,若其中一个带有Declared字样,表示针对类中所有声明的变量、方法、构造函数等,而对应不带Declared字样的方法,则表示仅对公有(public)成员变量、方法起作用,下面不再重复描述,下面仅对带有Declared字样的方法进行讲解。

三. 反射-构造函数

3.1 getDeclaredConstructor(Class<?>...parameterTypes)

  1. public class ClassUtils {
  2. /**
  3. * 获取构造函数
  4. * @param clazz 类
  5. * @param params 构造函数参数类型
  6. * @throws NoSuchMethodException
  7. */
  8. public static void getDeclaredConstructor(Class clazz, Class[] params) throws NoSuchMethodException {
  9. System.out.println(clazz.getDeclaredConstructor(params));
  10. }
  11. }
  12. public class ClassTest {
  13. public static void main(String[] args) {
  14. try {
  15. Class clazz = Class.forName("reflectdemo.SuperHero");
  16. //打印无参构造函数
  17. ClassUtils.getDeclaredConstructor(clazz, null);
  18. //打印有参构造函数
  19. ClassUtils.getDeclaredConstructor(clazz, new Class[]{String.class, String.class, Integer.class, String.class});
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

输出结果为:

  1. public reflectdemo.SuperHero()
  2. public reflectdemo.SuperHero(java.lang.String,java.lang.String,java.lang.Integer,java.lang.String)

3.2 getDeclaredConstructors()

  1. public class ClassUtils {
  2. /**
  3. * 遍历构造函数
  4. * @param clazz 类
  5. */
  6. public static void getDeclaredConstructors(Class clazz){
  7. //获取所有的构造函数
  8. Constructor[] constructors = clazz.getDeclaredConstructors();
  9. for (Constructor constructor : constructors) {
  10. //直接打印构造函数
  11. System.out.println(constructor);
  12. //打印构造函数名称
  13. System.out.println(constructor.getName());
  14. //打印构造函数参数
  15. Parameter[] parameters = constructor.getParameters();
  16. for(Parameter parameter : parameters){
  17. System.out.print(parameter);
  18. System.out.print(", ");
  19. }
  20. System.out.println("---------------------");
  21. }
  22. }
  23. }
  24. public class ClassTest {
  25. public static void main(String[] args) {
  26. try {
  27. Class clazz = Class.forName("reflectdemo.SuperHero");
  28. //遍历构造函数
  29. ClassUtils.getDeclaredConstructors(clazz);
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. }

输出结果为:

  1. public reflectdemo.SuperHero()
  2. reflectdemo.SuperHero
  3. ---------------------
  4. public reflectdemo.SuperHero(java.lang.String,java.lang.String,java.lang.Integer,java.lang.String)
  5. reflectdemo.SuperHero
  6. java.lang.String arg0, java.lang.String arg1, java.lang.Integer arg2, java.lang.String arg3, ---------------------

四. 反射-成员变量

4.1 getDeclaredField(String name)

  1. public class ClassUtils {
  2. /**
  3. * 获取属性字段
  4. * @param clazz 类
  5. * @param fieldName 属性名称
  6. * @throws Exception
  7. */
  8. public static void getDeclaredField(Class clazz, String fieldName) throws Exception{
  9. System.out.println(clazz.getDeclaredField(fieldName));
  10. }
  11. }
  12. public class ClassTest {
  13. public static void main(String[] args) {
  14. try {
  15. Class clazz = Class.forName("reflectdemo.SuperHero");
  16. //测试公有属性
  17. ClassUtils.getDeclaredField(clazz, "ADDRESS");
  18. //测试私有属性
  19. ClassUtils.getDeclaredField(clazz, "name");
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

输出结果为:

  1. public static final java.lang.String reflectdemo.SuperHero.ADDRESS
  2. private java.lang.String reflectdemo.SuperHero.name

4.3 getDeclaredFields()

  1. public class ClassUtils {
  2. /**
  3. * 遍历clazz对象已有的成员变量
  4. * @param clazz
  5. */
  6. public static void getDeclaredFields(Class clazz){
  7. Field[] fields = clazz.getDeclaredFields();
  8. for (Field field: fields) {
  9. //如果要设置值,需要加入下面这句,反射对象在使用时不使用Java语言访问检查
  10. //field.setAccessible(true);
  11. //直接打印Field
  12. System.out.println(field);
  13. //手动获取变量类型和变量名称
  14. System.out.println(field.getType().getName() + " " +field.getName());
  15. System.out.println("--------------------");
  16. }
  17. }
  18. }
  19. public class ClassTest {
  20. public static void main(String[] args) {
  21. try {
  22. Class clazz = Class.forName("reflectdemo.SuperHero");
  23. //遍历成员变量
  24. ClassUtils.getDeclaredFields(clazz);
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }

输出结果为:

  1. public static final java.lang.String reflectdemo.SuperHero.ADDRESS
  2. java.lang.String ADDRESS
  3. --------------------
  4. private java.lang.String reflectdemo.SuperHero.id
  5. java.lang.String id
  6. --------------------
  7. private java.lang.String reflectdemo.SuperHero.name
  8. java.lang.String name
  9. --------------------
  10. private java.lang.Integer reflectdemo.SuperHero.age
  11. java.lang.Integer age
  12. --------------------
  13. private java.lang.String reflectdemo.SuperHero.skill
  14. java.lang.String skill
  15. --------------------

五. 反射-成员方法

5.1 getDeclaredMethod(String name, Class<?>... parameterTypes)

  1. public class ClassUtils {
  2. /**
  3. * 获取成员方法
  4. * @param clazz 类
  5. * @param methodName 方法名称
  6. * @param params 参数列表
  7. * @throws Exception
  8. */
  9. public static void getDeclaredMethod(Class clazz, String methodName, Class[] params) throws Exception{
  10. Method method = clazz.getDeclaredMethod(methodName, params);
  11. System.out.println("直接打印");
  12. System.out.println(method);
  13. System.out.println("手动构建");
  14. //获取返回类型
  15. System.out.print(method.getReturnType().getSimpleName() + " ");
  16. //获取方法名称
  17. System.out.print(method.getName() + "(");
  18. //获取参数类型
  19. Class[] paramTypes = method.getParameterTypes();
  20. for(int i = 0; i < paramTypes.length; i++){
  21. Class param = paramTypes[i];
  22. if(i < paramTypes.length - 1){
  23. System.out.print(param.getSimpleName() + ", ");
  24. }else {
  25. System.out.print(param.getSimpleName());
  26. }
  27. }
  28. System.out.print(")");
  29. System.out.println();
  30. }
  31. }
  32. public class ClassTest {
  33. public static void main(String[] args) {
  34. try {
  35. Class clazz = Class.forName("reflectdemo.SuperHero");
  36. //打印无参数方法
  37. ClassUtils.getDeclaredMethod(clazz, "getName", null);
  38. //打印有参数方法
  39. ClassUtils.getDeclaredMethod(clazz, "setName", new Class[]{String.class});
  40. } catch (Exception e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. }

输出结果为:

  1. 直接打印
  2. public java.lang.String reflectdemo.SuperHero.getName()
  3. 手动构建
  4. String getName()
  5. 直接打印
  6. public void reflectdemo.SuperHero.setName(java.lang.String)
  7. 手动构建
  8. void setName(String)

5.2 getDeclaredMethods()

  1. public class ClassUtils {
  2. /**
  3. * 遍历方法
  4. * @param clazz
  5. */
  6. public static void getDeclaredMethods(Class clazz){
  7. //获取类中所有声明的方法
  8. Method[] methods = clazz.getDeclaredMethods();
  9. for (Method method : methods){
  10. System.out.println(method);
  11. }
  12. }
  13. }
  14. public class ClassTest {
  15. public static void main(String[] args) {
  16. try {
  17. Class clazz = Class.forName("reflectdemo.SuperHero");
  18. //遍历方法
  19. ClassUtils.getDeclaredMethods(clazz);
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. }

输出结果为:

  1. public java.lang.String reflectdemo.SuperHero.getName()
  2. public java.lang.String reflectdemo.SuperHero.getId()
  3. public void reflectdemo.SuperHero.setName(java.lang.String)
  4. public void reflectdemo.SuperHero.print()
  5. public java.lang.String reflectdemo.SuperHero.getSkill()
  6. public void reflectdemo.SuperHero.setAge(java.lang.Integer)
  7. public void reflectdemo.SuperHero.setSkill(java.lang.String)
  8. public void reflectdemo.SuperHero.setId(java.lang.String)
  9. public java.lang.Integer reflectdemo.SuperHero.getAge()

5.3 方法执行

  1. public class ClassUtils {
  2. /**
  3. * 执行set方法(通过Method的invoke方法)
  4. * @param o 待执行的实体
  5. * @param methodName 方法名称
  6. * @param params 方法参数类型
  7. * @throws Exception
  8. */
  9. public static void invokeSetMethod(Object o, String methodName, Class[] params) throws Exception {
  10. Method method = o.getClass().getDeclaredMethod(methodName, params);
  11. method.invoke(o, "钢铁侠");
  12. }
  13. /**
  14. * 执行get方法(通过Method的invoke方法)
  15. * @param o 待执行的实体
  16. * @param methodName 方法名称
  17. * @throws Exception
  18. */
  19. public static void invokeGetMethod(Object o, String methodName) throws Exception{
  20. Method method = o.getClass().getDeclaredMethod(methodName);
  21. Object obj = method.invoke(o);
  22. System.out.println(obj);
  23. }
  24. }
  25. public class ClassTest {
  26. public static void main(String[] args) {
  27. try {
  28. Class clazz = Class.forName("reflectdemo.SuperHero");
  29. //创建实体
  30. Object o = clazz.newInstance();
  31. //调用set方法
  32. ClassUtils.invokeSetMethod(o, "setName", new Class[]{String.class});
  33. //调用get方法
  34. ClassUtils.invokeGetMethod(o, "getName");
  35. } catch (Exception e) {
  36. e.printStackTrace();
  37. }
  38. }
  39. }

输出结果为:

  1. 钢铁侠

下面是对invoke方法的API说明

  1. public Object invoke(Object obj, Object... args) throws IllegalAccessException,
  2. IllegalArgumentException, InvocationTargetException

在具有指定参数的方法对象上调用此方法对象表示的基础方法。

如果底层方法是静态的,则指定的obj参数将被忽略。 它可能为null。

如果底层方法所需的形式参数的数量为0,则提供的args数组的长度为0或为空。

如果底层方法是一个实例方法,它将使用动态方法查找来调用,如“Java语言规范”第二版,第15.12.4.4节所述; 特别是将会发生基于目标对象的运行时类型的覆盖。

如果底层方法是静态的,则如果尚未初始化该方法,那么声明该方法的类将被初始化。

如果方法正常完成,则返回的值将返回给调用者; 如果值具有原始类型,则首先将其适当地包装在对象中。 但是,如果该值具有基本类型的数组的类型,则该数组的元素不会包含在对象中; 换句话说,返回一个原始类型的数组。 如果底层方法返回类型为void,则调用返回null。

  • 参数

    obj - 从底层方法被调用的对象

    args - 用于方法调用的参数

  • 结果

    由该对象表示的方法在 obj上调用 args

  • 异常

    IllegalAccessException - 如果这个 方法对象正在强制执行Java语言访问控制,并且底层方法是无法访问的。

    IllegalArgumentException - 如果方法是一个实例方法,并且指定的对象参数不是声明底层方法(或其子类或实现者)的类或接口的实例; 如果实际和正式参数的数量不同; 如果原始参数的解包转换失败; 或者如果在可能的展开之后,通过方法调用转换,参数值不能转换为相应的形式参数类型。

    InvocationTargetException - 如果底层方法抛出异常。

    NullPointerException - 如果指定的对象为空,该方法为实例方法。

    ExceptionInInitializerError - 如果由此方法引发的初始化失败。

六. 总结

本文对反射的定义,反射使用过程中重要的、常用的类和方法进行了讲解,包括Class类,Constructor类,Field类,Method类的说明及使用。反射机制允许在运行时判断任意一个对象所属的类、构造任意一个类的对象、判断任意一个类所具有的成员变量和方法、调用任意一个对象的方法。大大提高了系统的灵活性和扩展性,不过凡事都有两面性,反射破坏了Java封装的特性,相对来说不安全,需要根据场景酌情考虑,若有不对之处,请批评指正,望共同进步,谢谢!

Java反射Reflect的使用详解的更多相关文章

  1. JAVA反射概念及使用详解(超详细)

    JAVA反射概念及使用详解 一.什么是反射? 反射:框架设计的灵魂 框架:半成品软件.可以在框架的基础上进行软件开发,简化编码 反射:将类的各个组成部分封装为其他对象,这就是反射机制 ​ 好处: ​ ...

  2. Java基础-反射(reflect)技术详解

    Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制  如下图所示,JVM类加载机制分为五个部分 ...

  3. Scala进阶之路-反射(reflect)技术详解

    Scala进阶之路-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Scala中的反射技术和Java反射用法类似,我这里就不一一介绍反射是啥了,如果对 ...

  4. Java中的main()方法详解

    在Java中,main()方法是Java应用程序的入口方法,也就是说,程序在运行的时候,第一个执行的方法就是main()方法,这个方法和其他的方法有很大的不同,比如方法的名字必须是main,方法必须是 ...

  5. Java基础-面向接口编程-JDBC详解

    Java基础-面向接口编程-JDBC详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.JDBC概念和数据库驱动程序 JDBC(Java Data Base Connectiv ...

  6. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

  7. java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET

    java中的io系统详解 - ilibaba的专栏 - 博客频道 - CSDN.NET 亲,“社区之星”已经一周岁了!      社区福利快来领取免费参加MDCC大会机会哦    Tag功能介绍—我们 ...

  8. Java开发利器Myeclipse全面详解

    Java开发利器Myeclipse全面详解: Ctrl+1:修改代码错误 Alt+Shift+S:Source命令 Ctrl+7:单行注释 Ctrl+Shift+/ :多行注释 Ctrl+I :缩进( ...

  9. [译]Java Thread join示例与详解

    Java Thread join示例与详解 Java Thread join方法用来暂停当前线程直到join操作上的线程结束.java中有三个重载的join方法: public final void ...

随机推荐

  1. 项目心得——mybatisplus注解

    最近在做的项目中使用了mybatisplus,遇到了一些小问题,特此记录. 1.在sql查询后返回的数据中,会存在一些实体类中本没有的字段: 遇到这个问题时,我理所当然的就去实体类中添加了这个字段,但 ...

  2. Creating a Manager for Multiple Threads_翻译

    The previous lesson showed how to define a task that executes on a separate thread. If you only want ...

  3. C#跟Lua如何超高性能传递数据

    前言 在UWA学堂上线那天,我买了招文勇这篇Lua交互的课程,19块还算值,但是前段时间太忙,一直没空研究,他的demo是基于xlua的,今天终于花了大半天时间在tolua下跑起来了,记录一下我的理解 ...

  4. spring applicationContext.xml文件移到resources目录下

    SpringMVC的框架默认目录结构 修改后的目录结构及web.xml 同时在pom里的配置:将resources目录打包到web-inf/classes目录下<resources>   ...

  5. GitLab-CI 来自动创建 Docker 镜像

    1.what is gitlab-ci docker image CI/CD 自动化集成,自动化部署.简单的说就是把代码提交到gitlab管理的同时部署到指定的server,打成docker imag ...

  6. [译].Net中的内存

    原文链接:https://jonskeet.uk/csharp/memory.html 人们在理解值类型和引用类型之间的差异时因为“值类型在栈上分配,引用类型在堆上分配”这句话造成了很多混乱.这完全是 ...

  7. 动手造轮子:基于 Redis 实现 EventBus

    动手造轮子:基于 Redis 实现 EventBus Intro 上次我们造了一个简单的基于内存的 EventBus,但是如果要跨系统的话就不合适了,所以有了这篇基于 Redis 的 EventBus ...

  8. SSM-员工管理系统Demo---带分页和校验(含源码)

    页面展示: 前端JSP: <%@ page language="java" contentType="text/html; charset=UTF-8" ...

  9. Linux平台 Oracle 19c RAC安装Part2:GI配置

    三.GI(Grid Infrastructure)安装 3.1 解压GI的安装包 3.2 安装配置Xmanager软件 3.3 共享存储LUN的赋权 3.4 使用Xmanager图形化界面配置GI 3 ...

  10. 跟着阿里p7一起学java高并发 - 第19天:JUC中的Executor框架详解1,全面掌握java并发核心技术

    这是java高并发系列第19篇文章. 本文主要内容 介绍Executor框架相关内容 介绍Executor 介绍ExecutorService 介绍线程池ThreadPoolExecutor及案例 介 ...