JAVA基础-反射
一、反射的介绍
JAVA反射机制是在运行状态中,能够获取任意一个类的所有属性和方法,对于任意一个对象,都能够调用它的任意
一个方法。这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。JAVA编译时是先获取到类,然
后才是类里边的属性和方法,而反射则和编译相反,他是先获取类里边的对象和方法然后在告诉他是哪个类里的。简单
来说, 就可以把.class文件比做动物的尸体, 而反射技术就是对尸体的一种解剖.通过反射技术, 我们可以拿到该字节码
文件中所有的东西, 例如成员变量, 成员方法, 构造方法, 而且还包括私有。想要反射首先要获取到程序的“尸体”也就
是.class文件。
二、字节码文件的获取
获取字节码对象有3种方式:
1、类名.class - 这是一个静态的属性, 只要知道类名, 就可以获取
2、对象名.getClass() - Object类里的getClass()方法,对象已经存在的情况下, 可以使用这种方式
3、Claire.forName("类的全类名(包名+类名)") - 通过Class类里的静态方法forName来获取节码对象
举例:
- public static void main(String[] args) throws ClassNotFoundException {
- // 通过Object的getClass()方法获取,必须要有对象
- Student s = new Student();
- Class clazz = s.getClass();
- // 通过类名获取字节码对象
- Class clazz2 = Student.class;
- // 通过Class类里的静态方法forName来获取节码对象
- Class clazz3 = Class.forName("com.fanshe.Student");
- System.out.println(clazz == clazz2);
- System.out.println(clazz == clazz3);
- System.out.println(clazz);
- }
字节码文件其实就是描述.class文件的对象。
三、对构造方法的操作
*通过反射获取公有构造方法的两种方式:
1、返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法,可以获取无参构造也可以
根据传入的类型来匹配对应的构造方法:getConstructor(Class<?>... parameterTypes)
2、返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法:
getConstructors()
3、创建此 Class 对象所表示的类的一个新实例:
newInstance()
*暴力获取(可以获取全部权限的):
1、返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法:
getDeclaredConstructor(Class<?>... parameterTypes)
2、返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法:
getDeclaredConstructors()
举例:
- public static void main(String[] args) throws ReflectiveOperationException {
- // Class.forName()获取字节码对象
- Class<?> forName = Class.forName("com.fanshe.Student");
- // 获取所有公共构造方法
- Constructor<?>[] constructors = forName.getConstructors();
- // 遍历
- for (Constructor<?> constructor : constructors) {
- // 打印结果
- System.out.println(constructor);
- }
- System.out.println("--------------------------------------");
- // 暴力获取,可以获取所有的构造方法(包括私有的)
- Constructor<?> c1 = forName.getDeclaredConstructor();
- c1.setAccessible(true);
- System.out.println(c1);
- //获取有参构造
- Constructor<?> c2 = forName.getConstructor(String.class, int.class);
- System.out.println(c2);
- }
四、对成员变量和方法的操作
*公有成员变量获取方法:
1、返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段:
getField(String name) - 参数为要返回的变量名
2、返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段:
getFields() - 参数为要返回的变量名
*任意成员变量获取方法:
1、返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段:
getDeclaredField(String name) - 参数为要返回的变量名
2、返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段:
getDeclaredFields() - 参数为要返回的变量名
*获取公有的方法:
1、返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法:
getMethod(String name, Class<?>... parameterTypes) - name 方法名、parameterTypes 参数列表
2、返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口
声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法:
getMethods()
*暴力获取方法:
1、 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法:
getDeclaredMethod(String name, Class<?>... parameterTypes) - name 方法名、parameterTypes
参数列表
2、返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、
默认(包)访问和私有方法,但不包括继承的方法:
getDeclaredMethods()
需要注意的是想要获取私有的变量或者方法时应使用AccessibleObject类里的setAccessible(boolean flag)方法 - 参数
值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问
检查。
Constructor, Field, Method都是AccessibleObject的子类所以可以直接使用父类的setAccessible(boolean flag)方法。
**通过反射获得变量的流程:
1. 通过反射获取该类的字节码对象
2. 创建该类对象
3. 获取该类中需要操作的字段(成员变量)
4. 通过字段对象中的方法修改属性值
**通过反射执行方法的流程
1. 通过反射获取该类的字节码对象
2. 创建该类对象
3. 调用getMethod方法获取Method对象, 方法形参接受方法的名字
4. 调用Method方法中的invoke()将方法运行
举例:
*被反射的学生01类
- public class Student01 {
- public String name;
- private int age;
- public Student01() {
- super();
- // TODO Auto-generated constructor stub
- }
- public Student01(String name, int age) {
- super();
- this.name = name;
- this.age = age;
- }
- public void name() {
- System.out.println("测试");
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- private void mane1() {
- System.out.println("这是个萌萌哒私有的");
- }
- @Override
- public String toString() {
- return "Student01 [name=" + name + ", age=" + age + "]";
- }
- }
*对学生01类进行反射
- public static void main(String[] args) throws ReflectiveOperationException {
- // 获取字节码对象
- Class<?> clazz = Class.forName("com.fanshe.Student01");
- // 创建该类的对象
- Object stu = clazz.newInstance();
- // System.out.println(stu);
- // 获取学生类的name变量
- Field f1 = clazz.getField("name");
- /*
- * set将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
- * 为stu对象里的name变量赋值
- */
- f1.set(stu, "李四");
- // get()返回指定对象上此 Field 表示的字段的值。
- Object name = f1.get(stu);
- // 暴力获取age字段
- Field f2 = clazz.getDeclaredField("age");
- System.out.println(f2);
- // 让jvm不检查权限
- f2.setAccessible(true);
- // 为其赋值
- f2.set(stu, 24);
- // 获取stu对象的f2字段的值
- Object age = f2.get(stu);
- System.out.println(name);
- System.out.println(age);
- // 公有无参无返回值,name()
- Method method = clazz.getMethod("name");
- // 使用Method类的invoke方法执行name方法
- method.invoke(stu);
- // 公有代参无返回值,参数为String类型
- Method m2 = clazz.getMethod("setName", String.class);
- // 执行stu对象的setName方法,传入参数
- m2.invoke(stu, "李晨宇");
- // 公有无参有返回值
- Method m3 = clazz.getMethod("getName");
- // 返回值为invoke
- Object invoke = m3.invoke(stu);
- System.out.println(invoke);
- // 私有
- Method m4 = clazz.getDeclaredMethod("mane1");
- // 让jvm不检查权限
- m4.setAccessible(true);
- // 执行stu对象的mane1方法
- m4.invoke(stu);
- }
需要注意的是,反射无参构造时被反射的类一定要有无参构造方法,默认生成的也算。
五、反射的应用
我们在开发的时候,由于要考虑到代码的重用性,就会用反射来处理一些问题。而JAVA的一些常用jar包和主流框架的配置
都用到了反射的原理,学习反射有助于我们对源码的阅读和理解。BeanUtils工具类(Apache开发的便于操作JavaBeen的工具类)
就用到了反射的方法。
*BeanUtils的部分实现:
- public class MyBeanUtils {
- //因为是工具类,不需要实例化。所以私有构造方法
- private MyBeanUtils() {
- super();
- // TODO Auto-generated constructor stub
- }
- /*
- * 给对象中的属性赋值 传入类的对象类型,和要修改的属性的值不确定所以用Object类型,属性名用String类型
- */
- public static void setProrerty(Object object, String name, Object values)
- throws ReflectiveOperationException, SecurityException {
- // 获取传入对象的字节码文件
- Class clazz = object.getClass();
- // 根据传入的属性获取Field对象,因为不确定属性的权限,用的暴力反射
- Field field = clazz.getDeclaredField(name);
- // 让jvm不检查权限
- field.setAccessible(true);
- // 为object对象里的name属性赋值
- field.set(object, values);
- }
- // 获取对象中的属性
- public static String getProrerty(Object object, String name)
- throws ReflectiveOperationException, SecurityException {
- // 获取传入对象的字节码文件
- Class clazz = object.getClass();
- // 根据传入的属性获取Field对象,因为不确定属性的权限,用的暴力反射
- Field field = clazz.getDeclaredField(name);
- // 让jvm不检查权限
- field.setAccessible(true);
- // 获取name属性的值
- Object object2 = field.get(object);
- // System.out.println(object);
- // 将值返回
- return object2.toString();
- }
- // 给对象中的属性赋值(通过Map的方式),Map里key存的是属性名,value存的是要赋的值
- public static void populat(Object object, Map map) throws ReflectiveOperationException, SecurityException {
- // 获取传入对象的字节码文件
- Class clazz = object.getClass();
- // 返回此集合中的key集合
- Set keySet = map.keySet();
- // 遍历key
- for (Object object2 : keySet) {
- // 获得value值
- Object value = map.get(object2);
- try {
- // 根据传入的key(属性)获取Field对象,因为不确定属性的权限,用的暴力反射
- Field field = clazz.getDeclaredField(object2.toString());
- // 让jvm不检查权限
- field.setAccessible(true);
- // 赋值
- field.set(object, value);
- } catch (NoSuchFieldException e) {
- // 出现异常,给出友好型提示
- System.out.println("Mdzz,属性都记不住");
- }
- }
- }
- }
*测试工具类:
- public static void main(String[] args) throws RuntimeException, ReflectiveOperationException {
- // 创建学生01对象
- Student01 s1 = new Student01();
- // 使用MyBeanUtils工具类为学生01对象赋值
- MyBeanUtils.setProrerty(s1, "name", "啦啦");
- MyBeanUtils.setProrerty(s1, "age", 15);
- // 使用MyBeanUtils工具类为学生01对象取值
- String name = MyBeanUtils.getProrerty(s1, "name");
- String age = MyBeanUtils.getProrerty(s1, "age");
- // 打印出来
- System.out.println(name);
- System.out.println(age);
- System.out.println("------------------------------------ ");
- // 创建HashMap作为数据源
- HashMap<String, Object> hashMap = new HashMap<>();
- // 为HashMap赋值
- hashMap.put("qqqqq", "大大的"); // 属性不存在会给出友好型提示
- hashMap.put("name", "大大的");
- hashMap.put("age", 110);
- // 使用MyBeanUtils工具类为学生01对象赋值
- MyBeanUtils.populat(s1, hashMap);
- System.out.println(s1);
- }
JAVA基础-反射的更多相关文章
- Java基础-反射(reflect)技术详解
Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制 如下图所示,JVM类加载机制分为五个部分 ...
- Java基础——反射
今天学到Java基础中的反反射.依照我学习后的个人理解呢,反射就是一套获取类.属性.方法等的工具吧.(其实,感觉学完反射后,有点像喝凉水,解渴但确实我也没体会出它有什么味道,我可能没有学到精髓吧.自己 ...
- Java基础反射(二)
原文地址http://blog.csdn.net/sinat_38259539/article/details/71799078 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Cla ...
- java基础(反射,注解,多线程,juc)
JAVA基础 java反射 class对象 三种方式获取class加载时对象 1.class.forName("全类名"):将字节码文件加载进内存,返回class对象 2.类名.c ...
- [java 基础]反射入门
原文 概况 使用java的反射,可以让我们检查(或者修改)类,接口,字段,方法的特性.当你在编译期不知道他们的名字的时候非常有用. 除此之外,可以使用反射来创建实例,调用方法或者get/set 字段值 ...
- JAVA基础-反射机制
什么是JAVA的反射机制 Java反射是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其 ...
- java基础-反射(细节)
java面试题--java反射机制? Java反射机制的作用:1)在运行时判断任意一个对象所属的类.2)在运行时判断任意一个类所具有的成员变量和方法.3)在运行时任意调用一个对象的方法4)在运行时构造 ...
- Java基础—反射(转载)
转载自: JAVA反射与注解 JAVA反射 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射机制是什么 反射 ...
- java基础——反射机制
反射机制是什么 反射机制就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...
- Java基础—反射与代理(新手向)
第1章 反射与代理 1.1 反射定义 一般情况下,需要一个功能的前提是遇到了某个问题,这里先列举一些问题,然后再通过反射是如何解决了这些问题,来引出反射的定义. 普通开发人员工作中最常见的问题:需要生 ...
随机推荐
- 201521123105 第8周Java学习总结
1.本周学习总结 1.1思维导图 2. 书面作业 本次作业题集集合 1.List中指定元素的删除(题目4-1) 1.1 实验总结 1.删除元素的时候从最后一个元素开始,避免删除元素后位置发生变化而导致 ...
- 201521123100 《Java程序设计》第6周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...
- 201521123026 《Java程序设计》第三周学习总结
1. 本章学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...
- 201521123042 《Java程序设计》第3周学习总结
1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...
- 201521123075 《Java程序设计》第2周学习总结
1. 本周学习总结 各种数据类型,运算符,表达式的使用: 字符串String类; 对数组对象和字符串对象的运用. 2. 书面作业 1.使用Eclipse关联jdk源代码,并查看String对象的源代码 ...
- Java中的基本数据类型和基本数据类型之间的转换
在Java中有8中基本数据类型,分别为: 整型: byte.short.int.long 浮点型:float.double 布尔型:boolean 字符型:char. byte: 8位, 封装 ...
- java第十周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 1.finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中fin ...
- 201521123003《Java程序设计》第14周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...
- 纳税服务系统【自动受理,Quartz任务调度】
需求 回到我们的需求: 自动投诉受理:在每个月月底最后一天对本月之前的投诉进行自动处理:将投诉信息的状态改为 已失效.在后台管理中不能对该类型投诉进行回复. 这个需求需求我们要怎么弄呢????要在每个 ...
- JavaScript中的位置屬性
屏幕中的位置(直接使用,無需前綴): screenLeft.screenTop:除了火狐都支持 screenX.screenY: 窗口的大小(谷歌的inner=outer,直接使用,無需前綴): in ...