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

 

黎明前最黑暗,成功前最绝望!
相关文章
|
24天前
|
数据采集 分布式计算 大数据
Java语言在大数据处理中的应用
传统的大数据处理往往依赖于庞大的数据中心和高性能的服务器,然而随着大数据时代的到来,Java作为一种强大的编程语言正在被广泛应用于大数据处理领域。本文将探讨Java语言在大数据处理中的优势和应用,以及其在分布式计算、数据处理和系统集成等方面的重要作用。
|
4天前
|
安全 Java API
RESTful API设计与实现:Java后台开发指南
【4月更文挑战第15天】本文介绍了如何使用Java开发RESTful API,重点是Spring Boot框架和Spring MVC。遵循无状态、统一接口、资源标识和JSON数据格式的设计原则,通过创建控制器处理HTTP请求,如示例中的用户管理操作。此外,文章还提及数据绑定、验证、异常处理和跨域支持。最后,提出了版本控制、安全性、文档测试以及限流和缓存的最佳实践,以确保API的稳定、安全和高效。
|
5天前
|
Java Android开发 C++
Kotlin vs Java:选择最佳语言进行安卓开发
【4月更文挑战第13天】Java曾是安卓开发的主流语言,但Kotlin的崛起改变了这一局面。Google在2017年支持Kotlin,引发两者优劣讨论。Java以其成熟稳定、强大生态和跨平台能力占优,但代码冗长、开发效率低和语言特性过时是短板。Kotlin则以简洁语法、空安全设计和高度兼容Java脱颖而出,但社区和生态系统仍在发展中,可能存在学习曲线和性能问题。选择语言应考虑项目需求、团队熟悉度、维护性、性能和生态系统。无论选择哪种,理解其差异并适应新技术至关重要。
|
6天前
|
Java
代码的魔法师:Java反射工厂模式详解
代码的魔法师:Java反射工厂模式详解
18 0
|
6天前
|
存储 Java 关系型数据库
掌握Java 8 Stream API的艺术:详解流式编程(一)
掌握Java 8 Stream API的艺术:详解流式编程
35 1
|
9天前
|
Java API 开发者
Java 8新特性之函数式编程实战
【4月更文挑战第9天】本文将深入探讨Java 8的新特性之一——函数式编程,通过实例演示如何运用Lambda表达式、Stream API等技术,提高代码的简洁性和执行效率。
|
16天前
|
前端开发 Java API
构建RESTful API:Java中的RESTful服务开发
【4月更文挑战第3天】本文介绍了在Java环境中构建RESTful API的重要性及方法。遵循REST原则,利用HTTP方法处理资源,实现CRUD操作。在Java中,常用框架如Spring MVC简化了RESTful服务开发,包括定义资源、设计表示层、实现CRUD、考虑安全性、文档和测试。通过Spring MVC示例展示了创建RESTful服务的步骤,强调了其在现代Web服务开发中的关键角色,有助于提升互操作性和用户体验。
构建RESTful API:Java中的RESTful服务开发
|
16天前
|
Java
Java通过反射获取类调用方法
Java通过反射获取类调用方法
18 0
|
16天前
|
Java
Java语言打印九九乘法表(详解)
Java语言打印九九乘法表(详解)
15 1
Java语言打印九九乘法表(详解)
|
24天前
|
Java API 开发工具
【软件设计师备考 专题 】C、C++、Java、Visual Basic、Visual C++等语言的基础知识和应用(三)
【软件设计师备考 专题 】C、C++、Java、Visual Basic、Visual C++等语言的基础知识和应用
30 0