JDK1.7新特性(4):java语言动态性之反射API

简介: 直接通过一个代码示例来熟悉java中通过反射来对构造函数/域以及方法处理的相关API: 1 package com.rampage.jdk7.chapter2; 2 3 import java.

直接通过一个代码示例来熟悉java中通过反射来对构造函数/域以及方法处理的相关API:

  1 package com.rampage.jdk7.chapter2;
  2 
  3 import java.lang.reflect.Array;
  4 import java.lang.reflect.Constructor;
  5 import java.lang.reflect.Field;
  6 import java.lang.reflect.InvocationTargetException;
  7 import java.lang.reflect.Method;
  8 
  9 import com.rampage.jdk7.chapter2.NonStaticNestedClass.NestedClass;
 10 
 11 /**
 12  * 这是java反射API的程序代码示例,其中包括java7以及java7之前的一些API
 13  * @author zyq
 14  *
 15  */
 16 public class ReflectionAPI {
 17     public static void main(String[] args) throws Exception {
 18         ReflectionAPI api = new ReflectionAPI();
 19         api.testConstructors();
 20         api.testFields();
 21         api.testMethods();
 22         api.testArrays();
 23     }
 24     
 25     /**
 26      * 使用java.lang.reflect.Array来操作和创建数组
 27      */
 28     private void testArrays() {
 29         // 这个包下的Array类提供了一个newInstance方法来创建新的数组,第一个参数是数组中的元素类型,后面的参数是数组的维度信息
 30         // 创建一个String类型的长度为10的数组
 31         String[] names = (String[]) Array.newInstance(String.class, 10);
 32         names[0] = "KiDe";
 33         // 设置数组中下标为1的元素的值
 34         Array.set(names, 1, "Kid");
 35         
 36         // 创建两个三维数组
 37         int[][][] matrix1 = (int[][][]) Array.newInstance(int.class, 3, 3, 3);
 38         matrix1[0][0][0] = 12;
 39         int[][][] matrix2 = (int[][][]) Array.newInstance(int[].class, 3, 4);  // 这个其实也是三维数组,因为数组的类型是int[]
 40         matrix2[0][0][0] = 11;
 41         matrix2[0][1] = new int[3];
 42         
 43         
 44     }
 45 
 46     /**
 47      * 反射获取构造方法的测试例子
 48      */
 49     @SuppressWarnings("unchecked")
 50     private void testConstructors() {
 51         try {
 52             // Part1: 测试getConstructors方法,直接调用该方法,不会返回父类的构造方法。只会返回当前类的public类型的构造函数。
 53             Constructor<Child>[] childConstructors = (Constructor<Child>[]) Child.class.getConstructors();
 54             /**
 55              * 输出为:
 56                com.rampage.jdk7.chapter2.Child
 57                [Ljava.lang.reflect.Parameter;@15db9742
 58                1
 59              */
 60             for (Constructor<Child> constructor : childConstructors) {
 61                 System.out.println(constructor.getName());
 62                 System.out.println(constructor.getParameters());
 63                 System.out.println(constructor.getParameterCount());
 64             }
 65             
 66             Constructor<Parent>[] parentConstructors = (Constructor<Parent>[]) Parent.class.getConstructors();
 67             /**
 68              * 输出为:
 69                com.rampage.jdk7.chapter2.Parent
 70                [Ljava.lang.Class;@6d06d69c
 71                1
 72                com.rampage.jdk7.chapter2.Parent
 73                [Ljava.lang.Class;@7852e922
 74                0
 75               发现其实不管该构造函数是否有参数getParameterTypes或者getParameters都会返回值
 76              */
 77             for (Constructor<Parent> constructor : parentConstructors) {
 78                 System.out.println(constructor.getName());
 79                 System.out.println(constructor.getParameterTypes());
 80                 System.out.println(constructor.getParameterCount());
 81             }
 82             Parent.class.getConstructor();
 83             Parent.class.getConstructor(double.class);
 84             // Parent.class.getConstructor(void.class);   会抛出异常,当构造函数没有参数的时候直接不传即可,而不能传void.class
 85             // Parent.class.getConstructor(int.class);    会抛出异常,因为以int为参数的构造函数是不存在的
 86         
 87             // Part2: 测试getDeclaredConstruct,该方法能够得到当前类的所有构造函数,不管是public/protected还是private。
 88             childConstructors = (Constructor<Child>[]) Child.class.getDeclaredConstructors();
 89             /**
 90              * 输出为:
 91                  com.rampage.jdk7.chapter2.Child
 92                 [Ljava.lang.reflect.Parameter;@4e25154f
 93                 1
 94                 com.rampage.jdk7.chapter2.Child
 95                 [Ljava.lang.reflect.Parameter;@70dea4e
 96                 1
 97              */
 98             for (Constructor<Child> constructor : childConstructors) {
 99                 System.out.println(constructor.getName());
100                 System.out.println(constructor.getParameters());
101                 System.out.println(constructor.getParameterCount());
102                 // 私有的构造函数实例化对象的时候需要先调用 setAccessible(true),否则会报权限错误。
103             }
104             
105             // Part3: 参数长度可变的构造函数
106             // 获取构造函数的时候指定构造函数的参数应当当作数组来指定
107             Constructor<VaragsConstructor> constructor = VaragsConstructor.class.getDeclaredConstructor(int[].class);
108             System.out.println(constructor.getName());        // com.rampage.jdk7.chapter2.VaragsConstructor
109             // 利用得到的Constructor创建对象的实例时,可以把传入的参数转换成Object类型,也可以使用参数类型的数组
110             VaragsConstructor obj = constructor.newInstance((Object) (new int[] {1, 2, 3, 4}));
111             obj = constructor.newInstance(new int[] {1, 2, 3, 4});
112             
113             // Part4: 嵌套类的构造方法
114             // 嵌套类需要区分静态嵌套类和非静态嵌套类,对于静态嵌套类,获得其构造函数的方法和其他的非嵌套类没有区别,对于非静态的嵌套类,
115             // 因为必须先初始化外部类才能使用非静态的嵌套类, 因此在获取构造函数以及使用得到的构造函数实例化对象的时候第一个参数必须是外部类class和外部类实例
116             Constructor<NestedClass> constructor2 = NestedClass.class.getDeclaredConstructor(NonStaticNestedClass.class, int.class);
117             NonStaticNestedClass object = new NonStaticNestedClass();
118             constructor2.newInstance(object, 12);
119         } catch (ReflectiveOperationException e) {  // 在java6中各种反射的异常需要逐个捕获。而java7提供了一个新的异常类: ReflectiveOperationException,该类可以捕获所有反射操作的异常(因为他是所有反射操作异常的父类) 
120             System.out.println(e.getCause());  // 得到异常的具体信息
121         }
122         
123     }
124     
125     /**
126      * 反射进行域处理的例子
127      */
128     private void testFields() {
129         // 同样测试getField和getDeclareField的区别
130         Field[] fields = Child.class.getFields();
131         System.out.println();
132         /**
133          * 输出为:
134              field3
135             field3
136            可以看出这时候获得了父和子中所有的public的field
137          */
138         for (Field field : fields) {
139             System.out.println(field.getName());
140         }
141         
142         fields = Child.class.getDeclaredFields();
143         System.out.println();
144         /**
145          * 输出为:
146             field0
147             field1
148             field2
149             field3
150             可以看出此时输出了自己本身这个类中的所有域而不仅仅是public的
151          */
152         for (Field field : fields) {
153             System.out.println(field.getName());
154             // 给私有的域设置值需要先调用 setAccessible(true),否则会报权限错误。
155         }
156     }
157     
158     private void testMethods() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
159         Method[] methods = Child.class.getMethods();
160         System.out.println();
161         /**
162          * 输出为:
163               parentMethod
164             wait
165             wait
166             wait
167             equals
168             toString
169             hashCode
170             getClass
171             notify
172             notifyAll
173             可以看出把所有继承层次中(包括Object)的public方法都或得到了
174          */
175         for (Method method : methods) {
176             System.out.println(method.getName());
177         }
178         
179         methods = Child.class.getDeclaredMethods();
180         System.out.println();
181         /**
182          * 输出为:
183              ChildMethod
184              只是获得了当前类中的所有方法
185          */
186         for (Method method : methods) {
187             System.out.println(method.getName());
188             // 对于私有的method如果直接调用会抛出异常但是通过 method.setAccessible(true)就可以解决这一问题。
189         }
190     }
191     
192     /**
193      * 用反射实现的设置某个属性值的方法
194      * 通过反射API,java也可以应用在灵活性很高的场景中,最长见的Servlet中http请求参数值的填充。
195      * 虽然随着java虚拟机性能的改进,反射API的性能有所提升。但是反射方法和非反射方法的性能差距还是客观存在的。
196      * 因此在一些性能要求很高的场景中要慎用反射API或者将常调用的反射获得的方法先缓存起来。
197      */
198     void invokeSetter(Object obj, String field, Object value) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
199         String methodName = "set" + field.substring(0, 1).toUpperCase() + field.substring(1);
200         Class<?> clazz = obj.getClass();
201         Method setMethod = clazz.getMethod(    methodName, value.getClass());
202         setMethod.invoke(obj, value);
203     }
204 }
205 
206 class Parent {
207     String field0;
208     private String field1;
209     protected String field2;
210     public String field3;
211     
212     public Parent(double a) {}
213     public Parent() {}
214     public void parentMethod() {}
215 }
216 
217 class Child extends Parent  {
218     String field0;
219     private String field1;
220     protected String field2;
221     public String field3;
222     
223     // 如果父类没有同样的构造函数,则默认会调用父类的无参构造函数,如果父类没有无参构造函数,则编译会报错,会要求显示调用父类的某一个构造函数,以确保父类会在子类被实例化之前被实例化。
224     public Child(int i) {}
225     private Child(long l) {}
226     private void ChildMethod() {}
227 }
228 
229 class VaragsConstructor {
230     public VaragsConstructor(int... varags) {};
231 }
232 
233 class NonStaticNestedClass {
234     class NestedClass {
235         NestedClass(int i) {}
236     }
237 }
ReflectionAPI

 

黎明前最黑暗,成功前最绝望!
相关文章
|
12月前
|
JSON Java API
【干货满满】分享京东API接口到手价,用Java语言实现
本示例使用 Java 调用京东开放平台商品价格及优惠信息 API,通过商品详情和促销接口获取到手价(含优惠券、满减等),包含签名生成、HTTP 请求及响应解析逻辑,适用于比价工具、电商系统集成等场景。
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
477 5
|
10月前
|
Java
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
562 18
|
10月前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
413 4
|
11月前
|
存储 Java Apache
Java语言操作INI配置文件策略
以上步骤展示了基本策略,在实际项目中可能需要根据具体需求进行调整优化。例如,在多线程环境中操作同一份配置时需要考虑线程安全问题;大型项目可能还需考虑性能问题等等。
392 15
|
监控 Java API
Java语言按文件创建日期排序及获取最新文件的技术
这段代码实现了文件创建时间的读取、文件列表的获取与排序以及获取最新文件的需求。它具备良好的效率和可读性,对于绝大多数处理文件属性相关的需求来说足够健壮。在实际应用中,根据具体情况,可能还需要进一步处理如访问权限不足、文件系统不支持某些属性等边界情况。
530 14
|
12月前
|
算法 Java
Java语言实现链表反转的方法
这种反转方法不需要使用额外的存储空间,因此空间复杂度为,它只需要遍历一次链表,所以时间复杂度为,其中为链表的长度。这使得这种反转链表的方法既高效又实用。
695 0
|
12月前
|
JSON Java API
【干货满满】分享拼多多API接口到手价,用Java语言实现
本方案基于 Java 实现调用拼多多开放平台商品详情 API,通过联盟接口获取商品到手价(含拼团折扣与优惠券),包含签名生成、HTTP 请求及响应解析逻辑,适用于电商比价、导购系统集成。
|
12月前
|
JSON Java API
【干货满满】分享淘宝API接口到手价,用Java语言实现
本文介绍了如何使用 Java 调用淘宝开放平台 API 获取商品到手价,涵盖依赖配置、签名生成、HTTP 请求与响应解析等核心实现步骤。
|
Java 编译器 应用服务中间件
为什么说 Java 语言编译与解释并存的原因
在编程语言的世界里,Java以其独特的“编译与解释并存”特性独树一帜。这一特性不仅赋予了Java强大的跨平台能力,还使其在性能和灵活性上达到了很好的平衡。接下来,我们将深入探讨Java语言这一特性的本质、原理以及在实际应用中的体现。
407 6

热门文章

最新文章