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

 

黎明前最黑暗,成功前最绝望!
相关文章
|
8天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
31 2
|
1月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
48 4
|
22天前
|
JavaScript 前端开发 API
Vue 3新特性详解:Composition API的威力
【10月更文挑战第25天】Vue 3 引入的 Composition API 是一组用于组织和复用组件逻辑的新 API。相比 Options API,它提供了更灵活的结构,便于逻辑复用和代码组织,特别适合复杂组件。本文将探讨 Composition API 的优势,并通过示例代码展示其基本用法,帮助开发者更好地理解和应用这一强大工具。
26 1
|
24天前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。
|
1月前
|
存储 安全 Java
jdk21的外部函数和内存API(MemorySegment)(官方翻译)
本文介绍了JDK 21中引入的外部函数和内存API(MemorySegment),这些API使得Java程序能够更安全、高效地与JVM外部的代码和数据进行互操作,包括调用外部函数、访问外部内存,以及使用不同的Arena竞技场来分配和管理MemorySegment。
45 1
jdk21的外部函数和内存API(MemorySegment)(官方翻译)
|
1月前
|
缓存 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 的设计理念及其在构建现代前端应用中的优势。
33 0
深入理解 Vue 3 的 Composition API 与新特性
|
2月前
|
存储 JavaScript 前端开发
敲黑板!vue3重点!一文了解Composition API新特性:ref、toRef、toRefs
该文章深入探讨了Vue3中Composition API的关键特性,包括`ref`、`toRef`、`toRefs`的使用方法与场景,以及它们如何帮助开发者更好地管理组件状态和促进逻辑复用。
敲黑板!vue3重点!一文了解Composition API新特性:ref、toRef、toRefs
|
1月前
|
分布式计算 Java 大数据
大数据-147 Apache Kudu 常用 Java API 增删改查
大数据-147 Apache Kudu 常用 Java API 增删改查
32 1
|
2月前
|
安全 Java API
时间日期API(Date,SimpleDateFormat,Calendar)+java8新增日期API (LocalTime,LocalDate,LocalDateTime)
这篇文章介绍了Java中处理日期和时间的API,包括旧的日期API(Date、SimpleDateFormat、Calendar)和Java 8引入的新日期API(LocalTime、LocalDate、LocalDateTime)。文章详细解释了这些类/接口的方法和用途,并通过代码示例展示了如何使用它们。此外,还讨论了新旧API的区别,新API的不可变性和线程安全性,以及它们提供的操作日期时间的灵活性和简洁性。
|
2月前
|
Java 程序员 API
Java 8新特性之Lambda表达式与Stream API的探索
【9月更文挑战第24天】本文将深入浅出地介绍Java 8中的重要新特性——Lambda表达式和Stream API,通过实例解析其语法、用法及背后的设计哲学。我们将一探究竟,看看这些新特性如何让Java代码变得更加简洁、易读且富有表现力,同时提升程序的性能和开发效率。

热门文章

最新文章