1、什么是反射技术?

  动态获取指定类以及类中的内容(成员),并运行其内容。

  应用程序已经运行,无法在其中进行new对象的建立,就无法使用对象。这时可以根据配置文件的类全名去找对应的字节码文件,并加载进内存,并创建该类对象实例。这就需要使用反射技术完成。反射技术最重要的就是Class字节码对象。其次有Constructor、Method、Field等类。

  其实,反射机制的非常重要的一个类就是Class字节码对象,获取方式有三种:

  1. class Parent {
  2. protected String name;
  3.  
  4. public String getName() {
  5. return name;
  6. }
  7.  
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. }
  12.  
  13. class Children extends Parent {
  14. private static final Integer age = new Integer(25);
  15.  
  16. public Children(String name) {
  17. this.name = name;
  18. }
  19.  
  20. public static Integer getAge() {
  21. return age;
  22. }
  23. }

测试获取Class对象的三种方式:

  1. public static void testClazz() throws ClassNotFoundException {
  2. Children children = new Children("zhangsan");
  3. Class<? extends Children> class1 = children.getClass();// 获取class对象的第一种方式
  4. System.out.println(class1);
  5. Class class2 = Children.class;// 获取class对象的第二种方式
  6. System.out.println(class2);
  7. Class class3 = Class.forName("cn.xm.exam.test.Children");// 获取class对象的第三种方式(要写全路径)
  8. System.out.println(class3);
  9. }

结果:

class cn.xm.exam.test.Children
class cn.xm.exam.test.Children
class cn.xm.exam.test.Children

总结:获取Class对象的三种方式:

  Class.forName("类的路径")

  类名.Class

  实例.getClass()

2. Class字节码对象的作用一: newInstance和获取Constructor对象

修改Children类:

  1. class Children extends Parent {
  2. private static final Integer age = new Integer(25);
  3.  
  4. public Children() {
  5. System.out.println("无参构造方法");
  6. }
  7.  
  8. private Children(String name) {
  9. System.out.println("有参构造方法");
  10. this.name = name;
  11. }
  12.  
  13. public static Integer getAge() {
  14. return age;
  15. }
  16. }

2.1  clazz.newInstance();// 其内部是调用无参的Constructor对象进行创建对象

  1. Class clazz = Children.class;// 获取class对象的第二种方式
  2. Object newInstance = clazz.newInstance();// 其内部是调用无参构造方法进行创建
  3. System.out.println(newInstance);

结果:

无参构造方法
cn.xm.exam.test.Children@4614ac54

如果没有无参构造方法或者无参构造方法的修饰符是private,调用此方法会报错java.lang.IllegalAccessException

2.2 获取Constructor对象

  1. public static void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
  2. NoSuchMethodException, SecurityException {
  3. // 1.获取所有的构造
  4. Class clazz = Children.class;// 获取class对象的第二种方式
  5. Constructor[] constructors = clazz.getConstructors();// 获取所有public声明的构造方法
  6. blConstructor(constructors);
  7. Constructor[] declaredConstructors = clazz.getDeclaredConstructors();// 获取所有public\private\protected\default声明的构造方法
  8. blConstructor(declaredConstructors);
  9.  
  10. // 2.根据参数类型获取构造方法
  11. Constructor constructor = clazz.getDeclaredConstructor(String.class);// 获取参数类型为string修饰符为private的构造方法(因为是private修饰,所以只能用此方法获取)
  12. blConstructor(new Constructor[] { constructor });
  13. Constructor declaredConstructor = clazz.getConstructor(null);// 获取无参构造方法,修饰符为只能为public
  14. blConstructor(new Constructor[] { declaredConstructor });
  15. }
  16.  
  17. public static void blConstructor(Constructor[] constructors) {
  18. System.out.println("=============");
  19. for (Constructor constructor : constructors) {
  20. System.out.println("name ->" + constructor.getName());
  21. Class[] parameterTypes = constructor.getParameterTypes();// 获取构造方法的参数类型数组
  22. for (Class clazz11 : parameterTypes) {
  23. System.out.println("clazz11->" + clazz11);
  24. }
  25. System.out.println("isAccessible ->" + constructor.isAccessible());// isAccessible返回的是是否是private声明的
  26. }
  27. }

结果:

=============
name ->cn.xm.exam.test.Children
isAccessible ->false
=============
name ->cn.xm.exam.test.Children
clazz11->class java.lang.String
isAccessible ->false
name ->cn.xm.exam.test.Children
isAccessible ->false
=============
name ->cn.xm.exam.test.Children
clazz11->class java.lang.String
isAccessible ->false
=============
name ->cn.xm.exam.test.Children
isAccessible ->false

总结:    getConstructors()返回所有声明为public的构造方法

    getDeclaredConstructors()获取所有的方法,不管修饰符

    getDeclaredConstructor(String.class);//获取单参数,且类型为String的构造方法,修饰符可以为public\private\protected\default

    getConstructor(null);// 获取无参构造方法,修饰符为只能为public

      带Declared的方法可以获取到private修饰的构造方法,isAccessible方法返回的是此对象的可访问标志的值(默认返回的是false)。

2.3 Constructor对象创建实例

  Constructor可以创建对象,也可以获取构造方法的参数类型等。

  1. public static void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
  2. NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
  3. Class clazz = Children.class;// 获取class对象的第二种方式
  4. // 2.根据参数类型获取构造方法
  5. Constructor constructor = clazz.getDeclaredConstructor(String.class);// 获取参数类型为string修饰符为private的构造方法(因为是private修饰,所以只能用此方法获取)
  6. Constructor declaredConstructor = clazz.getConstructor(null);// 获取无参构造方法,修饰符为只能为public
  7.  
  8. System.out.println("=====================");
  9. Object newInstance1 = declaredConstructor.newInstance();
  10.  
  11. System.out.println("=====================");
  12. Object newInstance = constructor.newInstance("111");
  13. }

结果:(由于带参数的构造是private修饰的,所以不能直接new)

=====================
无参构造方法
=====================
Exception in thread "main" java.lang.IllegalAccessException: Class cn.xm.exam.test.Test can not access a member of class cn.xm.exam.test.Children with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:110)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:262)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:254)
at java.lang.reflect.Constructor.newInstance(Constructor.java:517)
at cn.xm.exam.test.Test.test2(Test.java:31)
at cn.xm.exam.test.Test.main(Test.java:8)

  

解决办法:(调用创建对象之前设置可见性为true)

  1. public static void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
  2. NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
  3. Class clazz = Children.class;// 获取class对象的第二种方式
  4. // 2.根据参数类型获取构造方法
  5. Constructor constructor = clazz.getDeclaredConstructor(String.class);// 获取参数类型为string修饰符为private的构造方法(因为是private修饰,所以只能用此方法获取)
  6. Constructor declaredConstructor = clazz.getConstructor(null);// 获取无参构造方法,修饰符为只能为public
  7.  
  8. System.out.println("=====================");
  9. Object newInstance1 = declaredConstructor.newInstance();
  10.  
  11. System.out.println("=====================");
  12. constructor.setAccessible(true);// 暴力可见
  13. Object newInstance = constructor.newInstance("111");
  14. }

结果:

=====================
无参构造方法
=====================
有参构造方法

3. Method对象

修改Children类:

  1. class Children extends Parent {
  2. private static final Integer age = new Integer(25);
  3.  
  4. public Children() {
  5. System.out.println("无参构造方法");
  6. }
  7.  
  8. private Children(String name) {
  9. System.out.println("有参构造方法");
  10. this.name = name;
  11. }
  12.  
  13. public static Integer getAge() {
  14. return age;
  15. }
  16.  
  17. private void method1() {
  18. System.out.println("method1......");
  19. }
  20.  
  21. private void method1(String arg) {
  22. System.out.println("method1......" + arg);
  23. }
  24.  
  25. public void method2() {
  26. System.out.println("method1......");
  27. }
  28. }

3.1 Method对象的获取方式

  此对象也是有四种获取方式,带Declared的可以获取任意修饰符的。

  1. Class clazz = Children.class;// 获取class对象的第二种方式
  2. // 2.根据参数类型获取构造方法
  3. Constructor constructor = clazz.getDeclaredConstructor(String.class);// 获取参数类型为string修饰符为private的构造方法(因为是private修饰,所以只能用此方法获取)
  4. constructor.setAccessible(true);// 暴力可见
  5. Object newInstance = constructor.newInstance("111");
  6. Method[] methods = clazz.getMethods();
  7. Method[] declaredMethods = clazz.getDeclaredMethods();
  8. Method method = clazz.getMethod("method2", null);
  9. Method declaredMethod = clazz.getDeclaredMethod("method1", String.class);

3.1 Method对象的作用

  Method对象可以获取方法的名字、返回类型、参数类型、异常类型、注解等信息,另外可以通过此实例直接调用方法。调用静态方法传入第一个参数传入null即可。

  1. public static void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException,
  2. NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
  3. Class clazz = Children.class;// 获取class对象的第二种方式
  4. Constructor constructor = clazz.getDeclaredConstructor(String.class);// 获取参数类型为string修饰符为private的构造方法(因为是private修饰,所以只能用此方法获取)
  5. constructor.setAccessible(true);// 暴力可见
  6. Object newInstance = constructor.newInstance("111");
  7. // 2.根据参数类型获取方法
  8. Method method = clazz.getMethod("getAge", null);
  9. Method declaredMethod = clazz.getDeclaredMethod("method1", String.class);
  10. // 2.1获取方法名字、返回类型、参数类型
  11. System.out.println(
  12. method.getName() + "\t" + method.getReturnType() + "\t" + Arrays.toString(method.getParameterTypes()));
  13. // 2.2 .2执行private修饰的方法(第一个参数是对象,第二个是参数)
  14. declaredMethod.setAccessible(true);// 设置暴力可见
  15. declaredMethod.invoke(newInstance, "111");
  16. // 2.2 .2静态方法的执行
  17. System.out.println(method.invoke(null));
  18. }

结果:

有参构造方法
getAge class java.lang.Integer []
method1......111
25

4. Field对象

  Field相当于成员属性、字段。

修改Children类:

  1. class Children extends Parent {
  2. private static final Integer age = new Integer(25);
  3. private String sex;
  4. public int score;
  5.  
  6. public Children() {
  7. System.out.println("无参构造方法");
  8. }
  9.  
  10. private Children(String name) {
  11. System.out.println("有参构造方法");
  12. this.name = name;
  13. }
  14.  
  15. public static Integer getAge() {
  16. return age;
  17. }
  18. }

4.1 Field的获取方式

  1. Class clazz = Children.class;// 获取class对象的第二种方式
  2. Constructor constructor = clazz.getDeclaredConstructor(String.class);// 获取参数类型为string修饰符为private的构造方法(因为是private修饰,所以只能用此方法获取)
  3. constructor.setAccessible(true);// 暴力可见
  4. Object newInstance = constructor.newInstance("111");
  5. // 获取Field对象
  6. Field[] fields = clazz.getFields();
  7. System.out.println(Arrays.toString(fields));
  8. Field[] declaredFields = clazz.getDeclaredFields();
  9. System.out.println(Arrays.toString(declaredFields));
  10. Field field = clazz.getField("score");
  11. System.out.println(field);
  12. Field declaredField = clazz.getDeclaredField("age");
  13. System.out.println(declaredField);

结果:

有参构造方法
[public int cn.xm.exam.test.Children.score]
[private static final java.lang.Integer cn.xm.exam.test.Children.age, private java.lang.String cn.xm.exam.test.Children.sex, public int cn.xm.exam.test.Children.score]
public int cn.xm.exam.test.Children.score
private static final java.lang.Integer cn.xm.exam.test.Children.age

4.2 Field的作用

  Field实例可以获取字段的类型、值,也可以修改字段的值。

  1. Class clazz = Children.class;// 获取class对象的第二种方式
  2. Constructor constructor = clazz.getDeclaredConstructor(String.class);// 获取参数类型为string修饰符为private的构造方法(因为是private修饰,所以只能用此方法获取)
  3. constructor.setAccessible(true);// 暴力可见
  4. Object newInstance = constructor.newInstance("111");
  5. // 获取Field对象
  6. Field field = clazz.getField("score");
  7. System.out.println(field.getType() + "\t" + field.get(newInstance));
  8. // 修改成员属性的值
  9. field.set(newInstance, 80);
  10. System.out.println(field.getType() + "\t" + field.get(newInstance));
  11. // 获取静态成员属性
  12. Field declaredField = clazz.getDeclaredField("age");
  13. declaredField.setAccessible(true);// 暴力可见
  14. System.out.println(declaredField.getType() + "\t" + declaredField.get(null));

结果:

有参构造方法
int 0
int 80
class java.lang.Integer 25

field提供了获取字段基本类型的值与引用类型的值get方法,也提供了修改基本类型与引用类型值的set方法:(第一个参数是实例对象,如果是静态属性传入null就可以)

      

总结:

1.三种方法可以获取到Class类:

  Class.forName("类的路径")

  类名.Class

  实例.getClass()

2.五种创建对象的方法:

  通过new语句实例化一个对象

  通过反射机制创建对象,class.newInstance()

  通过反射机制创建对象,constructor.newInstance()

  通过clone()方法创建一个对象

  通过反序列化方式创建对象

3.获取构造方法对象Constructor、方法对象Method、字段对象Field都有四种方法。(两个返回数组、两个返回单个实例)

  直接调用getXXX方法例如  getConstructors 返回的是public修饰的方法,而且包括从父类继承的方法

  调用getDeclaredXXX方法获取的不管修饰符,但是不包括从父类继承的方法。

  也可以根据方法名称与类型或者字段名称来获取对应的单个实例。

反射的基本使用以及原理(Class获取方式)的更多相关文章

  1. 反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性、字段),而不去使用Invoke方法)

    反射-优化及程序集等(用委托的方式调用需要反射调用的方法(或者属性.字段),而不去使用Invoke方法)   创建Delegate (1).Delegate.CreateDelegate(Type, ...

  2. MFC中 SDI/MDI框架各部分指针获取方式

    VC MFC SDI/MDI框架各部分指针获取方式   整理总结一下,希望能帮助到别人.   获得CWinApp 获得CMainFrame 获得CChildFrame 获得CDocument 获得CV ...

  3. geohash 算法原理及实现方式

    转自:http://www.cnblogs.com/dengxinglin/archive/2012/12/14/2817761.html geohash 算法原理及实现方式 1.geohash 特点 ...

  4. 爬虫 xpath 获取方式

    回顾 bs4 实例化bs对象,将页面源码数据加载到该对象中 定位标签:find('name',class_='xxx') findall() select() 将标签中的文本内容获取 string t ...

  5. CPU使用率原理及计算方式

    本文转载自CPU使用率原理及计算方式 CPU:超线程和多核 超线程(Hyper-Threading ) 超线程是Intel最早提出一项技术,最早出现在2002年的Pentium4上.单个采用超线程的C ...

  6. [转]Android SHA1与Package获取方式

    转自高德地图LBS Android SHA1与Package获取方式 获取应用包名 打开Android 应用工程的 AndroidManifest.xml配置文件,package 属性所对应的内容为应 ...

  7. JQ关于浏览器宽高的获取方式

    JQ关于浏览器宽高的获取方式 alert($(window).height()); //浏览器时下窗口可视区域高度alert($(document).height()); //浏览器时下窗口文档的高度 ...

  8. Unity---资源管理中不同资源的路径获取方式

    1.首先需要先了解两个知识点: Unity内置的文件路径获取方式.windows的Directory.GetFiles文件获取方式:   1>Unity内置的文件路径获取方式,一下是官方解释:h ...

  9. RabbitMQ消费端消息的获取方式(.Net Core)

    1[短链接]:BasicGet(String queue, Boolean autoAck) 通过request的方式独自去获取消息,断开式,一次次获取,如果返回null,则说明队列中没有消息. 隐患 ...

随机推荐

  1. jenkins+svn+pipeline+kubernetes部署java应用(三)

    将jar包.Dockerfile.kubernetes部署yaml文件上传至svn自定义目录 一.生成流水线脚本 二.配置jenkins pipeline构建语句 三.点击构建java工程

  2. 【JAVA】mac配置java环境变量

    如果用bash,修改~/.bash_profile 或 ~/.profile: 如果用zsh,修改-/.zshrc 修改这些文件之后,重修打开terminal,配置不会丢 首先确保已经安装了jdk: ...

  3. 裸奔着造房子——对政府禁止采购Win8系统的一些看法

    前段时间有消息称政府招标的项目将禁止使用Win8系统,原因是Win8系统的安全架构将有利于暴露敏感信息给微软,而微软的老子是美利坚,老子想要知道什么,儿子当然不敢不从.因此Win8也被打入冷宫,微软多 ...

  4. GBDT算法简述

    提升决策树GBDT 梯度提升决策树算法是近年来被提及较多的一个算法,这主要得益于其算法的性能,以及该算法在各类数据挖掘以及机器学习比赛中的卓越表现,有很多人对GBDT算法进行了开源代码的开发,比较火的 ...

  5. Hive官方文档

    Hive官方文档     内容列表 Cloudera制作的Hive介绍视频 安装与配置 系统需求 安装Hive发行版 从Hive源码编译 运行Hive 配置管理概览 运行时配置 Hive, Map-R ...

  6. 51、如何提取android代码中的字符串为系统资源文件 (I18N)

    工具:android studio 步骤1:找到要转为资源文件的字符串并选中,同时按下option+enter,弹出菜单,我们选中extract string resource 步骤2:在弹窗中输入你 ...

  7. 使用 Pinup,PinupManager 在 XNA 中创建贴图(十七)

    平方已经开发了一些 Windows Phone 上的一些游戏,算不上什么技术大牛.在这里分享一下经验,仅为了和各位朋友交流经验.平方会逐步将自己编写的类上传到托管项目中,没有什么好名字,就叫 WPXN ...

  8. 设置CMD默认代码页为65001或936

    之前不知道怎么改的,CMD的代码页被默认设置成了65001   但我右击CMD标题,选择‘默认值’,显示默认却是936,但为何每次打开都是65001呢   上网找到设置默认值的方法 1 win键+R打 ...

  9. 第一章:前端布局之display属性

    css布局学习网站:http://zh.learnlayout.com

  10. MCMC 浅谈

    # MCMC 浅谈 1. 采样(sampling)是什么 MCMC在采样算法中有着举足轻重的地位,那么什么是采样?采样就是根据某种分布生成样本.举个例子,线性同余发生器就是根据均匀分布生成样本,这就很 ...