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

 

黎明前最黑暗,成功前最绝望!
相关文章
|
19天前
|
安全 前端开发 Java
随着企业应用复杂度提升,Java Spring框架以其强大与灵活特性简化开发流程,成为构建高效、可维护应用的理想选择
随着企业应用复杂度提升,Java Spring框架以其强大与灵活特性简化开发流程,成为构建高效、可维护应用的理想选择。依赖注入使对象管理交由Spring容器处理,实现低耦合高内聚;AOP则分离横切关注点如事务管理,增强代码模块化。Spring还提供MVC、Data、Security等模块满足多样需求,并通过Spring Boot简化配置与部署,加速微服务架构构建。掌握这些核心概念与工具,开发者能更从容应对挑战,打造卓越应用。
31 1
|
9天前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
30 0
|
1天前
|
安全 Java API
【本地与Java无缝对接】JDK 22外部函数和内存API:JNI终结者,性能与安全双提升!
【9月更文挑战第6天】JDK 22的外部函数和内存API无疑是Java编程语言发展史上的一个重要里程碑。它不仅解决了JNI的诸多局限和挑战,还为Java与本地代码的互操作提供了更加高效、安全和简洁的解决方案。随着FFM API的逐渐成熟和完善,我们有理由相信,Java将在更多领域展现出其强大的生命力和竞争力。让我们共同期待Java编程新纪元的到来!
20 11
|
1天前
|
Java API 开发者
【Java字节码操控新篇章】JDK 22类文件API预览:解锁Java底层的无限可能!
【9月更文挑战第6天】JDK 22的类文件API为Java开发者们打开了一扇通往Java底层世界的大门。通过这个API,我们可以更加深入地理解Java程序的工作原理,实现更加灵活和强大的功能。虽然目前它还处于预览版阶段,但我们已经可以预见其在未来Java开发中的重要地位。让我们共同期待Java字节码操控新篇章的到来!
|
8天前
|
Java API
Java 8新特性:Lambda表达式与Stream API的深度解析
【7月更文挑战第61天】本文将深入探讨Java 8中的两个重要特性:Lambda表达式和Stream API。我们将首先介绍Lambda表达式的基本概念和语法,然后详细解析Stream API的使用和优势。最后,我们将通过实例代码演示如何结合使用Lambda表达式和Stream API,以提高Java编程的效率和可读性。
|
10天前
|
Java 开发者
Java 8新特性之Lambda表达式与函数式接口
【7月更文挑战第59天】本文将介绍Java 8中的一个重要新特性——Lambda表达式,以及与之密切相关的函数式接口。通过对比传统的匿名内部类,我们将探讨Lambda表达式的语法、使用方法和优势。同时,我们还将了解函数式接口的定义和用途,以及如何将Lambda表达式应用于函数式编程。
|
19天前
|
分布式计算 Java API
Java 8带来了流处理与函数式编程等新特性,极大提升了开发效率
Java 8带来了流处理与函数式编程等新特性,极大提升了开发效率。流处理采用声明式编程模型,通过filter、map等操作简化数据集处理,提高代码可读性。Lambda表达式支持轻量级函数定义,配合Predicate、Function等接口,使函数式编程无缝融入Java。此外,Optional类及新日期时间API等增强功能,让开发者能更优雅地处理潜在错误,编写出更健壮的应用程序。
22 1
|
22天前
|
Java API
JDK8到JDK25版本升级的新特性问题之使用Collectors.teeing()来计算一个列表中学生的平均分和总分如何操作
JDK8到JDK25版本升级的新特性问题之使用Collectors.teeing()来计算一个列表中学生的平均分和总分如何操作
|
22天前
|
Java API Apache
JDK8到JDK24版本升级的新特性问题之在Java中,HttpURLConnection有什么局限性,如何解决
JDK8到JDK24版本升级的新特性问题之在Java中,HttpURLConnection有什么局限性,如何解决
|
21天前
|
自然语言处理 Java 应用服务中间件
Java 18 新特性解析
Java 18 新特性解析
下一篇
DDNS