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月前
|
Java API 数据处理
Java新特性:使用Stream API重构你的数据处理
Java新特性:使用Stream API重构你的数据处理
|
11月前
|
人工智能 自然语言处理 测试技术
Apipost智能搜索:只需用业务语言描述需求,就能精准定位目标接口,API 搜索的下一代形态!
在大型项目中,API 数量庞大、命名不一,导致“找接口”耗时费力。传统工具依赖关键词搜索,难以应对语义模糊或命名不规范的场景。Apipost AI 智能搜索功能,支持自然语言查询,如“和用户登录有关的接口”,系统可理解语义并精准匹配目标接口。无论是新人上手、模糊查找还是批量定位,都能大幅提升检索效率,降低协作成本。从关键词到语义理解,智能搜索让开发者少花时间找接口,多专注核心开发,真正实现高效协作。
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
719 4
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
JSON JavaScript 前端开发
Python+JAVA+PHP语言,苏宁商品详情API
调用苏宁商品详情API,可通过HTTP/HTTPS发送请求并解析响应数据,支持多种编程语言,如JavaScript、Java、PHP、C#、Ruby等。核心步骤包括构造请求URL、发送GET/POST请求及解析JSON/XML响应。不同语言示例展示了如何获取商品名称与价格等信息,实际使用时请参考苏宁开放平台最新文档以确保兼容性。
|
安全 Java 编译器
JDK 10中的局部变量类型推断:Java编程的简化与革新
JDK 10引入的局部变量类型推断通过`var`关键字简化了代码编写,提高了可读性。编译器根据初始化表达式自动推断变量类型,减少了冗长的类型声明。虽然带来了诸多优点,但也有一些限制,如只能用于局部变量声明,并需立即初始化。这一特性使Java更接近动态类型语言,增强了灵活性和易用性。
437 53
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
5281 5
|
缓存 JavaScript 前端开发
深入理解 Vue 3 的 Composition API 与新特性
本文详细探讨了 Vue 3 中的 Composition API,包括 setup 函数的使用、响应式数据管理(ref、reactive、toRefs 和 toRef)、侦听器(watch 和 watchEffect)以及计算属性(computed)。我们还介绍了自定义 Hooks 的创建与使用,分析了 Vue 2 与 Vue 3 在响应式系统上的重要区别,并概述了组件生命周期钩子、Fragments、Teleport 和 Suspense 等新特性。通过这些内容,读者将能更深入地理解 Vue 3 的设计理念及其在构建现代前端应用中的优势。
942 1
深入理解 Vue 3 的 Composition API 与新特性
|
存储 安全 Java
jdk21的外部函数和内存API(MemorySegment)(官方翻译)
本文介绍了JDK 21中引入的外部函数和内存API(MemorySegment),这些API使得Java程序能够更安全、高效地与JVM外部的代码和数据进行互操作,包括调用外部函数、访问外部内存,以及使用不同的Arena竞技场来分配和管理MemorySegment。
900 2
jdk21的外部函数和内存API(MemorySegment)(官方翻译)
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
639 6