这篇文章主要是整理了Java中的反射机制,包括:反射机制概念、反射机制访问构造方法、反射机制访问普通方法、反射机制访问属性,反射机制访问修饰符。

目录

一、反射机制概念

二、反射机制使用

(1)加载Class类对象的几种方式

(2)准备测试类

(3)反射访问属性

(4)反射访问方法

(5)反射访问构造方法

(6)反射创建对象

(7)反射访问私有属性或方法

三、反射机制的应用

四、反射机制优缺点

(1)优点

(2)缺点


文章包含的源代码地址如下:

本篇文章涉及的案例代码在Gitee仓库,点击【反射机制案例代码】可以查看。

一、反射机制概念

什么是反射???

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。

在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

  • Java中的反射机制,简单理解就是可以在程序运行的过程中,获取到某个类的内部结构信息,例如:类名称、属性、方法、构造方法等,并且可以动态的创建某个具体的对象实例的能力。

二、反射机制使用

(1)加载Class类对象的几种方式

我们在使用反射机制之前,第一步就是需要加载Class类对象,只有获取到Class类对象之后,我们才能根据Class类对象去访问相应类的内部结构信息,比如:属性、方法、构造方法、类名称、修饰符等等内容。

获取Class类对象一般有如下几种方式:

  • 第一种方式:通过类的class属性获取Class类对象
/**
**  语法格式:
**  Class<?> clazz = 类名称.class;
*/
public class ClassDemo {public static void main(String[] args) {// 1、类名称.class 获取Class类对象Class<String> clazz = String.class;// 输出看看效果System.out.println(clazz);}
}
  • 第二种方式:通过对象的getClass()方法获取Class类对象
/**** 语法格式:* Class<?> clazz = 对象名称.getClass();*/
public class ClassDemo {public static void main(String[] args) {// 2、对象.getClass() 获取Class类对象String str = "";Class<? extends String> clazz2 = str.getClass();// 输出看看效果System.out.println(clazz2);}
}
  • 第三种方式:通过Class.forName()获取Class类对象
/*** 语法格式:* Class<?> clazz = Class.forName("这里写类的全限定名称");* 类的全限定名称:包名称 + 类名称*/
public class ClassDemo {public static void main(String[] args) throws ClassNotFoundException {// 3、Class.forName() 获取Class类对象// 这种方式需要处理异常,因为根据包名称可能找不到类Class<?> clazz = Class.forName("java.lang.String");// 输出看看结果System.out.println(clazz);}
}

(2)准备测试类

为了测试反射机制获取类的内部结构信息,我们创建两个测试类,分别是:Person和Student类,并且Student类继承自Person,源代码大致如下。

  • Person类代码
public class Person {// 属性private String priVal;String defVal;protected String proVal;public String pubVal;// 父类构造方法private Person(String priVal, String defVal, String proVal){}Person(String defVal){}protected Person(String proVal, String defVal){}public Person(){}// 方法private void test01(){}void test02(){}protected void test03(){}public void test04(){}
}
  • Student类代码
public class Student extends Person {// 子类属性private String stuPriVal;String stuDefVal;protected String stuProVal;public String stuPubVal;// 子类构造方法private Student(String stuPriVal, String stuDefVal, String stuProVal){}Student(String stuDefVal){}protected Student(String stuProVal, String stuDefVal){}public Student(){}public Student(String name, Integer id){}// 子类方法private void subTest01(){System.out.println("Student类中的private私有方法");}void subTest02(){}protected void subTest03(){}{System.out.println("调用了Student类中的subTest04()方法,方法参数是:" + name);}
}

(3)反射访问属性

前面我们获取到了Class类对象之后,就可以通过Class类对象,去操作类的内部结构信息。

Field对象

  • Java中将类中每个属性都封装成了一个【Field】对象,并且提供了一些获取这些属性的方法。
  • Field属性,可以是当前类中的属性,也可以是父类中的属性。

反射机制获取类中的属性(Field对象):

  • getFields(): 获取当前类、父类中的所有public属性。
  • getDeclaredFields(): 获取当前类中的所有属性。
  • getField(String name): 获取当前类、父类中指定名称的一个public属性(如果不是public属性,则会抛出异常)。
  • getDeclaredField(String name): 获取当前类中指定名称的一个属性。

下面通过代码来看下这四个方法的具体使用。

public class FieldDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {// 1、获取Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、获取类的属性// getFields(): 获取当前类、父类中的所有public方法Field[] fields = clazz.getFields();System.out.println("===== getFields(): 获取当前类、父类中的所有public方法 =====");for (Field field : fields) {System.out.println(""+field);}System.out.println();// getDeclaredFields(): 获取当前类中的所有方法Field[] declaredFields = clazz.getDeclaredFields();System.out.println("===== getDeclaredFields(): 获取当前类中的所有方法 =====");for (Field declaredField : declaredFields) {System.out.println(declaredField);}System.out.println();// getField(String name): 获取当前类、父类中指定名称的一个public属性System.out.println("===== getField(String name): 获取当前类、父类中指定名称的一个属性 =====");Field pubVal = clazz.getField("pubVal"); // 父类public属性System.out.println(pubVal);Field stuPubVal = clazz.getField("stuPubVal"); // 子类public属性System.out.println(stuPubVal);System.out.println();// getDeclaredField(String name): 获取当前类中指定名称的一个属性System.out.println("===== getDeclaredField(String name): 获取当前类中指定名称的一个属性 =====");Field stuPriVal = clazz.getDeclaredField("stuPriVal"); // 子类private属性System.out.println(stuPriVal);}
}

上面代码的运行结果如下所示:

通过反射机制,我们获取到了类中的属性,那要如何给属性赋值呢???

Java中提供了如下方法,用于属性赋值和获取属性值:

  • set(Object obj,Object newValue)方法:用于属性赋值。参数obj表示实例对象,newValue表示赋值后的值。
  • get(Object obj)方法:用于获取属性值。参数obj表示实例对象。

上面两种方式,只能给【非private修饰】的属性进行赋值操作,对于private的属性,不能直接操作,如何操作private属性,请看本篇文章的第(7)部分。

通过反射机制给属性赋值、获取属性值:

public class FieldDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,InstantiationException, IllegalAccessException {// 1、获取Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建类对象Student student = (Student) clazz.newInstance();// 3、获取属性Field field = clazz.getDeclaredField("stuProVal");// 属性赋值field.set(student, "通过反射机制给属性赋值");// 获取属性值Object value = field.get(student);System.out.println(value);}
}

程序运行结果如下所示:

(4)反射访问方法

反射机制获取类中的方法(Method对象):

  • getMethods(): 获取当前类、父类中所有的public方法。
  • getDeclaredMethods(): 获取当前类中的所有方法。
  • getMethod(String name, Class<?> paramType): 获取当前类、父类中一个指定方法名称的public方法(如果类中没有指定的方法,则会抛出异常)。
  • getDeclaredMethod(String name, Class<?> paramType): 获取当前类中一个指定方法名称的方法(如果类中没有指定的方法,则会抛出异常)。

下面通过代码演示反射机制获取类中方法:

public class MethodDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {// 1、获取Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、获取类中方法// getMethods(): 获取当前类、父类中所有的public方法Method[] methods = clazz.getMethods();System.out.println("===== getMethods(): 获取当前类、父类中所有的public方法 =====");for (Method method : methods) {System.out.println(method);}System.out.println();// getDeclaredMethods(): 获取当前类中的所有方法Method[] declaredMethods = clazz.getDeclaredMethods();System.out.println("===== getDeclaredMethods(): 获取当前类中的所有方法 =====");for (Method declaredMethod : declaredMethods) {System.out.println(declaredMethod);}System.out.println();// getMethod(String name, Class<?> paramType): 获取当前类、父类中一个指定方法名称的public方法System.out.println("===== getMethod(String name, Class<?> paramType): 获取当前类、父类中一个指定方法名称的public方法 =====");// 方法没有参数,则设置null即可Method test04 = clazz.getMethod("test04", null);System.out.println("父类中public方法: "+test04);// 有参数,则传递参数类型Method subTest04 = clazz.getMethod("subTest04", String.class);System.out.println("子类中public方法: "+subTest04);System.out.println();// getDeclaredMethod(String name, Class<?> paramType): 获取当前类中一个指定方法名称的方法System.out.println("===== getDeclaredMethod(): 获取当前类中一个指定方法名称的方法 =====");Method subTest01 = clazz.getDeclaredMethod("subTest01", null);System.out.println("当前类中私有方法: "+subTest01);}
}

上面代码最终运行结果如下图所示:

上面介绍了如何通过反射机制获取类中的方法,方法获取之后,那么要如何调用方法呢???

反射调用方法步骤如下:

  • 获取Class类对象
  • 通过Class创建一个实例对象
  • 通过Class获取需要调用的Method对象
  • 通过Method对象的invoke()进行方法调用

反射机制调用方法代码:

public class MethodDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {// 1、获取Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建实例对象// 这里先默认通过构造方法创建实例对象,后面会继续介绍如何创建对象Student student = (Student) clazz.newInstance();// 3、获取需要调用的方法Method method = clazz.getDeclaredMethod("subTest04", String.class);// 调用invoke(Object obj, Object... args)方法, obj表示实例对象,args表示调用方法的参数Object ret = method.invoke(student, "这是一个方法参数");System.out.println("方法的返回值是:" + ret);}
}

程序运行结果如下所示:

invoke(Object obj, Object... args)方法:

  • 参数obj:实例对象,因为我们调用方法需要知道调用哪个具体实例对象的方法。
  • 参数args:方法参数,这是我们调用那个方法需要的参数值。

(5)反射访问构造方法

反射机制提供了如下四个方法,用于获取类的构造方法:

  • getConstructors(): 获取当前类中所有public的构造方法。
  • getDeclaredConstructors(): 获取当前类中的所有构造方法(不限制修饰符)。
  • getConstructor(Class... args): 获取当前类中指定的参数个数的public构造方法(如果没有指定的构造方法,会抛出异常)。
  • getDeclaredConstructor(Class... args): 获取当前类中指定参数个数的构造方法(修饰符不限制如果没有指定的构造方法,会抛出异常)。

下面给出演示代码:

public class ConstructorDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {// 1、创建 Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、获取构造方法// getConstructors(): 获取当前类中所有public的构造方法System.out.println("===== getConstructors(): 获取当前类中所有public的构造方法 =====");Constructor<?>[] constructors = clazz.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor);}System.out.println();// getDeclaredConstructors(): 获取当前类中的所有构造方法System.out.println("===== getDeclaredConstructors(): 获取当前类中的所有构造方法 =====");Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor);}System.out.println();// getConstructor(Class... args): 获取当前类中指定的参数个数的public构造方法System.out.println("===== getConstructor(Class... args): 获取当前类中指定参数个数的public构造方法 =====");// 获取指定参数的构造方法Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);System.out.println(constructor);System.out.println();// getDeclaredConstructor(Class... args): 获取当前类中指定参数个数的构造方法(修饰符不限制)System.out.println("===== getDeclaredConstructor(Class... args): 获取当前类中指定参数个数的构造方法(修饰符不限制) =====");Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(String.class);System.out.println(declaredConstructor);}
}

代码运行结果如下图所示:

(6)反射创建对象

在前面,我们调用方法的时候,创建了一个实例对象,这里我们介绍一下通过反射机制如何创建一个对象。

创建对象,本质上就是通过new关键字,然后根据不同的构造方法创建对象实例。

反射机制中,提供了如下两种方式创建对象实例:

  • 第一种方式:调用【newInstance()】方法(本质上是通过无参构造方法创建对象
  • 第二种方式:首先获取有参构造方法,然后通过有参构造方法去调用【newInstance(Object... args)】方法(通过有参构造方法创建对象)。
  • 第一种方式:无参构造方法创建对象
public class InstanceDemo {public static void main(String[] args) throws ClassNotFoundException,InstantiationException, IllegalAccessException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、通过 newInstance() 创建对象// 通过 Student 类的无参构造方法创建对象Student student = (Student) clazz.newInstance();System.out.println(student);}
}

注意:这种创建对象的方式,要求对应的类中具有无参构造方法,如果没有无参构造方法,则会创建失败。

  • 第二种方式:首先获取有参构造方法,然后通过有参构造方法去调用【newInstance(Object... args)】方法

第一种方式创建对象是有限制条件的,类必须具备无参构造方法,否则无法创建,这里在介绍一下通过有参构造方法创建对象。

public class InstanceDemo {public static void main(String[] args) throws ClassNotFoundException,InstantiationException, IllegalAccessException,NoSuchMethodException, InvocationTargetException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、获取有参构造方法Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, String.class);// 通过有参构造方法创建对象Student student = (Student) constructor.newInstance("参数1", "参数2");System.out.println(student);}
}

以上,就是通过反射机制创建对象的两种方式。

(7)反射访问私有属性或方法

setAccessible(boolean flag)方法。

我们前面介绍了通过反射获取属性、获取方法,但是反射对于私有属性、私有方法,是不能直接调用的。

  • 反射机制访问私有属性

下面举个例子,我们直接操作私有的属性或者方法,然后查看运行结果:

public class AccessPrivateDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,InstantiationException, IllegalAccessException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建对象Student student = (Student) clazz.newInstance();// 3、获取私有属性Field field = clazz.getDeclaredField("stuPriVal");// 给私有属性重新赋值field.set(student, "私有属性赋值新值");System.out.println("赋值后的值:" + field.get(student));}
}

程序运行之后,可以发现,控制台报错了,如下所示:

可以发现报错提示中,会出现了如下内容:

上面意思,大致就是:不能够访问private修饰符的类成员。

反射机制中,我们不能直接访问私有的成员、私有的方法,需要在调用之前,解除方法的安全性检查,这样我们就可以操作私有属性、私有方法了。

解除私有属性和方法的安全性检查:

  • setAccessible(boolean flag):解除或者开启安全性检查。true表示解除安全性检查。

我们在访问私有属性之前,调用【setAccessible()】方法,再次查看结果。

public class AccessPrivateDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,InstantiationException, IllegalAccessException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建对象Student student = (Student) clazz.newInstance();// 3、获取私有属性Field field = clazz.getDeclaredField("stuPriVal");// 解除安全性检查field.setAccessible(true); // true表示解除安全性检查// 给私有属性重新赋值field.set(student, "私有属性赋值新值");System.out.println("赋值后的值:" + field.get(student));}
}

程序运行结果如下所示:

  • 反射机制访问私有方法

访问私有方法案例代码:

public class AccessPrivateDemo {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,InstantiationException, IllegalAccessException,NoSuchMethodException, InvocationTargetException {// 1、创建Class类对象Class<?> clazz = Class.forName("org.example.reflection.Student");// 2、创建对象Student student = (Student) clazz.newInstance();// 3、获取私有方法Method method = clazz.getDeclaredMethod("subTest01", null);// 解除安全性检查method.setAccessible(true);// 调用方法Object ret = method.invoke(student, null);System.out.println("方法返回值:" + ret);}
}

程序运行结果如下所示:

以上,就是通过反射机制访问私有属性或者方法。

三、反射机制的应用

反射机制在很多地方都被使用到了,比如下面这些场景都采用反射机制实现的。

  • JDBC获取数据库连接:通过反射机制加载数据库驱动程序。
  • Spring中的IOC容器:根据xml配置文件的bean标签,然后采用反射机制创建实例对象。
  • MyBatis中mapper接口执行SQL语句:动态代理中使用反射机制调用目标对象方法。
  • AOP动态代理:动态代理中就需要通过反射机制创建对象。
  • 等等。。。

四、反射机制优缺点

(1)优点

  • 反射机制提高了程序的可扩展性、灵活性。
  • 降低了程序的耦合性。

(2)缺点

  • 反射机制会破环面向对象的封装性,因为通过反射可以访问private私有属性或方法。
  • 反射机制会降低程序的运行效率。

以上,就是我个人对反射机制相关内容的总结,包括:获取类对象、反射机制访问属性、方法、构造方法、访问私有成员、以及反射机制的应用场景和优缺点。​​​​​​​

【反射机制】Java中的反射机制,使用反射机制创建对象、访问属性、方法、构造方法等相关推荐

  1. java为何重复调用方法_通过反射调用Java中的getter:重复调用它的最快方法是什么(在性能和可伸缩性方面)?...

    小编典典 您可以使用MethodHandle.其Javadoc写道: 使用Lookup API中的工厂方法,可以将Core Reflection API对象表示的任何类成员转换为行为等效的方法句柄.例 ...

  2. java实现分发_关于JAVA中事件分发和监听机制实现的代码实例

    [实例简介] 关于JAVA中事件分发和监听机制实现的代码实例,绝对实用代码,有说明. [实例截图] [核心代码] JavaEventDispatch ├── bin │   └── com │   └ ...

  3. Java基础-Java中的内存分配与回收机制

    Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二. 转载于:https://www.cnblogs.com/yinzhengji ...

  4. 关于JAVA中事件分发和监听机制实现的代码实例-绝对原创实用

    转载:http://blog.csdn.net/5iasp/article/details/37054171 谢谢博主 ======================================== ...

  5. 转:Java中子类是否可以继承父类的static变量和方法而呈现多态特性

    原文地址:Java中子类是否可以继承父类的static变量和方法而呈现多态特性 静态方法 通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法,关于static方法,声明 ...

  6. java整型转换为数组_基于java中byte数组与int类型的转换(两种方法)

    java中byte数组与int类型的转换,在网络编程中这个算法是最基本的算法,我们都知道,在socket传输中,发送.者接收的数据都是 byte数组,但是int类型是4个byte组成的,如何把一个整形 ...

  7. Java中url传递中文参数取值乱码的解决方法

    Java中url传递中文参数取值乱码的解决方法 参考文章: (1)Java中url传递中文参数取值乱码的解决方法 (2)https://www.cnblogs.com/liwenjuan/p/3211 ...

  8. JAVA中的多线程(八):线程的优先级和yield方法

    JAVA中的多线程(八):线程的优先级和yield方法 优先级代表着抢资源的频率 所有线程默认优先级是5 yield()临时释放线程的执行权 1 class Demo implements Runna ...

  9. java中给对象的List集合去重的几种方法(Lambda)

    java中给对象的List集合去重的几种方法 前言 一.lambda表达式的去重方式 二.Stream API中的collect去重方法 三.Stream API 中的distinct方法去重 前言 ...

  10. Java中的反射和Java中的访问修饰符

    什么是反射? ①在运行状态中,对于任何一个类,我们都能够知道这个类有哪些方法和属性 ②对于任何一个对象,我们都能够对它的方法和属性进行调用 总而言之:它反射Java语言中的一种机制,通过这种机制可以动 ...

最新文章

  1. android消息池,回转寿司你一定吃过!——Android消息机制(构造)
  2. BOM的window对象的属性及其方法
  3. java常见的报错_Java中常见的错误有哪些?
  4. 关于Oracle RAC节点间免密码策略
  5. qs.parse和qs.stringify
  6. 商户网站使用第三方支付的大致原理和实现
  7. 12.4scrum report
  8. 算法训练营 重编码_参加编码训练营之前要考虑的7件事
  9. 电机入门之路系列1--减速步进电机的原理
  10. linux的grub界面退出,linux退出 grub
  11. php 随机生成ip
  12. 根据列值删除Pandas中的DataFrame行
  13. RestTemplate 了解和学习
  14. 如何在CentOS/RedHat下实现根据源码包创建rpm包
  15. 送你一份有态度的红包封面!
  16. oracle中外键的使用方法,Oracle数据库中外键的相关操作整理
  17. 【学习笔记】尚硅谷大数据项目之Flink实时数仓---数据采集
  18. 在uniapp中配置并colorui及阿里图标
  19. cuda10.0及其驱动纯净卸载(笔记)
  20. php计算器源码,php 简单计算器

热门文章

  1. 旧上海黑社会老大杜月笙的名言 蛮有道理
  2. tp5 创建直播频道
  3. 把几个视频文件(mov)拼成一个视频文件
  4. ORA-01861: literal does not match format string
  5. 全国计算机考试考ms还是wps,计算机wps和ms哪个简单?
  6. 最全解析:部署跨境电商erp系统前需要做哪些准备?
  7. 共享办公室租赁,激发创新
  8. java 微信 qq 登录_拾人牙慧篇之———QQ微信的第三方登录实现
  9. 3t硬盘 xp_怎么让xp支持3T硬盘
  10. VR时代的游戏“涉赌”困境