一、反射的介绍

JAVA反射机制是在运行状态中,能够获取任意一个类的所有属性和方法,对于任意一个对象,都能够调用它的任意
一个方法。这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。JAVA编译时是先获取到类,然
后才是类里边的属性和方法,而反射则和编译相反,他是先获取类里边的对象和方法然后在告诉他是哪个类里的。简单
来说, 就可以把.class文件比做动物的尸体, 而反射技术就是对尸体的一种解剖.通过反射技术, 我们可以拿到该字节码
文件中所有的东西, 例如成员变量, 成员方法, 构造方法, 而且还包括私有。想要反射首先要获取到程序的“尸体”也就
是.class文件。

二、字节码文件的获取

获取字节码对象有3种方式:
1、类名.class - 这是一个静态的属性, 只要知道类名, 就可以获取
2、对象名.getClass() - Object类里的getClass()方法,对象已经存在的情况下, 可以使用这种方式
3、Claire.forName("类的全类名(包名+类名)") - 通过Class类里的静态方法forName来获取节码对象
  举例:

  1. public static void main(String[] args) throws ClassNotFoundException {
  2. // 通过Object的getClass()方法获取,必须要有对象
  3. Student s = new Student();
  4. Class clazz = s.getClass();
  5. // 通过类名获取字节码对象
  6. Class clazz2 = Student.class;
  7. // 通过Class类里的静态方法forName来获取节码对象
  8. Class clazz3 = Class.forName("com.fanshe.Student");
  9. System.out.println(clazz == clazz2);
  10. System.out.println(clazz == clazz3);
  11. System.out.println(clazz);
  12.  
  13. }

字节码文件其实就是描述.class文件的对象。

三、对构造方法的操作

*通过反射获取公有构造方法的两种方式:
1、返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法,可以获取无参构造也可以
根据传入的类型来匹配对应的构造方法:getConstructor(Class<?>... parameterTypes)
2、返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法:
                                                               getConstructors()
3、创建此 Class 对象所表示的类的一个新实例:
                                                               newInstance()

*暴力获取(可以获取全部权限的):
1、返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法:
                                 getDeclaredConstructor(Class<?>... parameterTypes)
2、返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法:
                                 getDeclaredConstructors()
  举例:

  1. public static void main(String[] args) throws ReflectiveOperationException {
  2. // Class.forName()获取字节码对象
  3. Class<?> forName = Class.forName("com.fanshe.Student");
  4. // 获取所有公共构造方法
  5. Constructor<?>[] constructors = forName.getConstructors();
  6. // 遍历
  7. for (Constructor<?> constructor : constructors) {
  8. // 打印结果
  9. System.out.println(constructor);
  10. }
  11. System.out.println("--------------------------------------");
  12. // 暴力获取,可以获取所有的构造方法(包括私有的)
  13. Constructor<?> c1 = forName.getDeclaredConstructor();
  14. c1.setAccessible(true);
  15. System.out.println(c1);
  16. //获取有参构造
  17. Constructor<?> c2 = forName.getConstructor(String.class, int.class);
  18. System.out.println(c2);
  19. }

四、对成员变量和方法的操作

*公有成员变量获取方法:
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类

  1. public class Student01 {
  2. public String name;
  3. private int age;
  4.  
  5. public Student01() {
  6. super();
  7. // TODO Auto-generated constructor stub
  8. }
  9.  
  10. public Student01(String name, int age) {
  11. super();
  12. this.name = name;
  13. this.age = age;
  14. }
  15.  
  16. public void name() {
  17. System.out.println("测试");
  18.  
  19. }
  20.  
  21. public String getName() {
  22. return name;
  23. }
  24.  
  25. public void setName(String name) {
  26. this.name = name;
  27. }
  28.  
  29. public int getAge() {
  30. return age;
  31. }
  32.  
  33. public void setAge(int age) {
  34. this.age = age;
  35. }
  36.  
  37. private void mane1() {
  38. System.out.println("这是个萌萌哒私有的");
  39.  
  40. }
  41.  
  42. @Override
  43. public String toString() {
  44. return "Student01 [name=" + name + ", age=" + age + "]";
  45. }
  46.  
  47. }

*对学生01类进行反射

  1. public static void main(String[] args) throws ReflectiveOperationException {
  2. // 获取字节码对象
  3. Class<?> clazz = Class.forName("com.fanshe.Student01");
  4. // 创建该类的对象
  5. Object stu = clazz.newInstance();
  6. // System.out.println(stu);
  7. // 获取学生类的name变量
  8. Field f1 = clazz.getField("name");
  9. /*
  10. * set将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
  11. * 为stu对象里的name变量赋值
  12. */
  13. f1.set(stu, "李四");
  14. // get()返回指定对象上此 Field 表示的字段的值。
  15. Object name = f1.get(stu);
  16. // 暴力获取age字段
  17. Field f2 = clazz.getDeclaredField("age");
  18. System.out.println(f2);
  19. // 让jvm不检查权限
  20. f2.setAccessible(true);
  21. // 为其赋值
  22. f2.set(stu, 24);
  23. // 获取stu对象的f2字段的值
  24. Object age = f2.get(stu);
  25. System.out.println(name);
  26. System.out.println(age);
  27. // 公有无参无返回值,name()
  28. Method method = clazz.getMethod("name");
  29. // 使用Method类的invoke方法执行name方法
  30. method.invoke(stu);
  31. // 公有代参无返回值,参数为String类型
  32. Method m2 = clazz.getMethod("setName", String.class);
  33. // 执行stu对象的setName方法,传入参数
  34. m2.invoke(stu, "李晨宇");
  35. // 公有无参有返回值
  36. Method m3 = clazz.getMethod("getName");
  37. // 返回值为invoke
  38. Object invoke = m3.invoke(stu);
  39. System.out.println(invoke);
  40. // 私有
  41. Method m4 = clazz.getDeclaredMethod("mane1");
  42. // 让jvm不检查权限
  43. m4.setAccessible(true);
  44. // 执行stu对象的mane1方法
  45. m4.invoke(stu);
  46. }

需要注意的是,反射无参构造时被反射的类一定要有无参构造方法,默认生成的也算。
五、反射的应用

我们在开发的时候,由于要考虑到代码的重用性,就会用反射来处理一些问题。而JAVA的一些常用jar包和主流框架的配置
都用到了反射的原理,学习反射有助于我们对源码的阅读和理解。BeanUtils工具类(Apache开发的便于操作JavaBeen的工具类)
就用到了反射的方法。
  *BeanUtils的部分实现:

  1. public class MyBeanUtils {
  2. //因为是工具类,不需要实例化。所以私有构造方法
  3. private MyBeanUtils() {
  4. super();
  5. // TODO Auto-generated constructor stub
  6. }
  7.  
  8. /*
  9. * 给对象中的属性赋值 传入类的对象类型,和要修改的属性的值不确定所以用Object类型,属性名用String类型
  10. */
  11. public static void setProrerty(Object object, String name, Object values)
  12. throws ReflectiveOperationException, SecurityException {
  13. // 获取传入对象的字节码文件
  14. Class clazz = object.getClass();
  15. // 根据传入的属性获取Field对象,因为不确定属性的权限,用的暴力反射
  16. Field field = clazz.getDeclaredField(name);
  17. // 让jvm不检查权限
  18. field.setAccessible(true);
  19. // 为object对象里的name属性赋值
  20. field.set(object, values);
  21.  
  22. }
  23.  
  24. // 获取对象中的属性
  25. public static String getProrerty(Object object, String name)
  26. throws ReflectiveOperationException, SecurityException {
  27. // 获取传入对象的字节码文件
  28. Class clazz = object.getClass();
  29. // 根据传入的属性获取Field对象,因为不确定属性的权限,用的暴力反射
  30. Field field = clazz.getDeclaredField(name);
  31. // 让jvm不检查权限
  32. field.setAccessible(true);
  33. // 获取name属性的值
  34. Object object2 = field.get(object);
  35. // System.out.println(object);
  36. // 将值返回
  37. return object2.toString();
  38. }
  39.  
  40. // 给对象中的属性赋值(通过Map的方式),Map里key存的是属性名,value存的是要赋的值
  41. public static void populat(Object object, Map map) throws ReflectiveOperationException, SecurityException {
  42. // 获取传入对象的字节码文件
  43. Class clazz = object.getClass();
  44. // 返回此集合中的key集合
  45. Set keySet = map.keySet();
  46. // 遍历key
  47. for (Object object2 : keySet) {
  48. // 获得value值
  49. Object value = map.get(object2);
  50. try {
  51. // 根据传入的key(属性)获取Field对象,因为不确定属性的权限,用的暴力反射
  52. Field field = clazz.getDeclaredField(object2.toString());
  53. // 让jvm不检查权限
  54. field.setAccessible(true);
  55. // 赋值
  56. field.set(object, value);
  57. } catch (NoSuchFieldException e) {
  58. // 出现异常,给出友好型提示
  59. System.out.println("Mdzz,属性都记不住");
  60. }
  61. }
  62. }
  63. }

*测试工具类:

  1. public static void main(String[] args) throws RuntimeException, ReflectiveOperationException {
  2. // 创建学生01对象
  3. Student01 s1 = new Student01();
  4. // 使用MyBeanUtils工具类为学生01对象赋值
  5. MyBeanUtils.setProrerty(s1, "name", "啦啦");
  6. MyBeanUtils.setProrerty(s1, "age", 15);
  7. // 使用MyBeanUtils工具类为学生01对象取值
  8. String name = MyBeanUtils.getProrerty(s1, "name");
  9. String age = MyBeanUtils.getProrerty(s1, "age");
  10. // 打印出来
  11. System.out.println(name);
  12. System.out.println(age);
  13. System.out.println("------------------------------------ ");
  14. // 创建HashMap作为数据源
  15. HashMap<String, Object> hashMap = new HashMap<>();
  16. // 为HashMap赋值
  17. hashMap.put("qqqqq", "大大的"); // 属性不存在会给出友好型提示
  18. hashMap.put("name", "大大的");
  19. hashMap.put("age", 110);
  20. // 使用MyBeanUtils工具类为学生01对象赋值
  21. MyBeanUtils.populat(s1, hashMap);
  22. System.out.println(s1);
  23. }

JAVA基础-反射的更多相关文章

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

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

  2. Java基础——反射

    今天学到Java基础中的反反射.依照我学习后的个人理解呢,反射就是一套获取类.属性.方法等的工具吧.(其实,感觉学完反射后,有点像喝凉水,解渴但确实我也没体会出它有什么味道,我可能没有学到精髓吧.自己 ...

  3. Java基础反射(二)

    原文地址http://blog.csdn.net/sinat_38259539/article/details/71799078 反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Cla ...

  4. java基础(反射,注解,多线程,juc)

    JAVA基础 java反射 class对象 三种方式获取class加载时对象 1.class.forName("全类名"):将字节码文件加载进内存,返回class对象 2.类名.c ...

  5. [java 基础]反射入门

    原文 概况 使用java的反射,可以让我们检查(或者修改)类,接口,字段,方法的特性.当你在编译期不知道他们的名字的时候非常有用. 除此之外,可以使用反射来创建实例,调用方法或者get/set 字段值 ...

  6. JAVA基础-反射机制

    什么是JAVA的反射机制 Java反射是Java被视为动态(或准动态)语言的一个关键性质.这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其 ...

  7. java基础-反射(细节)

    java面试题--java反射机制? Java反射机制的作用:1)在运行时判断任意一个对象所属的类.2)在运行时判断任意一个类所具有的成员变量和方法.3)在运行时任意调用一个对象的方法4)在运行时构造 ...

  8. Java基础—反射(转载)

    转载自: JAVA反射与注解 JAVA反射 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射机制是什么 反射 ...

  9. java基础——反射机制

    反射机制是什么 反射机制就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为jav ...

  10. Java基础—反射与代理(新手向)

    第1章 反射与代理 1.1 反射定义 一般情况下,需要一个功能的前提是遇到了某个问题,这里先列举一些问题,然后再通过反射是如何解决了这些问题,来引出反射的定义. 普通开发人员工作中最常见的问题:需要生 ...

随机推荐

  1. 201521123105 第8周Java学习总结

    1.本周学习总结 1.1思维导图 2. 书面作业 本次作业题集集合 1.List中指定元素的删除(题目4-1) 1.1 实验总结 1.删除元素的时候从最后一个元素开始,避免删除元素后位置发生变化而导致 ...

  2. 201521123100 《Java程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  3. 201521123026 《Java程序设计》第三周学习总结

    1. 本章学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...

  4. 201521123042 《Java程序设计》第3周学习总结

    1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 2. 书面作 ...

  5. 201521123075 《Java程序设计》第2周学习总结

    1. 本周学习总结 各种数据类型,运算符,表达式的使用: 字符串String类; 对数组对象和字符串对象的运用. 2. 书面作业 1.使用Eclipse关联jdk源代码,并查看String对象的源代码 ...

  6. Java中的基本数据类型和基本数据类型之间的转换

    在Java中有8中基本数据类型,分别为: 整型: byte.short.int.long 浮点型:float.double 布尔型:boolean 字符型:char. byte:    8位,  封装 ...

  7. java第十周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常与多线程相关内容. 2. 书面作业 1.finally 题目4-2 1.1 截图你的提交结果(出现学号) 1.2 4-2中fin ...

  8. 201521123003《Java程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  9. 纳税服务系统【自动受理,Quartz任务调度】

    需求 回到我们的需求: 自动投诉受理:在每个月月底最后一天对本月之前的投诉进行自动处理:将投诉信息的状态改为 已失效.在后台管理中不能对该类型投诉进行回复. 这个需求需求我们要怎么弄呢????要在每个 ...

  10. JavaScript中的位置屬性

    屏幕中的位置(直接使用,無需前綴): screenLeft.screenTop:除了火狐都支持 screenX.screenY: 窗口的大小(谷歌的inner=outer,直接使用,無需前綴): in ...