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

 package com.rampage.jdk7.chapter2;

 import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import com.rampage.jdk7.chapter2.NonStaticNestedClass.NestedClass; /**
* 这是java反射API的程序代码示例,其中包括java7以及java7之前的一些API
* @author zyq
*
*/
public class ReflectionAPI {
public static void main(String[] args) throws Exception {
ReflectionAPI api = new ReflectionAPI();
api.testConstructors();
api.testFields();
api.testMethods();
api.testArrays();
} /**
* 使用java.lang.reflect.Array来操作和创建数组
*/
private void testArrays() {
// 这个包下的Array类提供了一个newInstance方法来创建新的数组,第一个参数是数组中的元素类型,后面的参数是数组的维度信息
// 创建一个String类型的长度为10的数组
String[] names = (String[]) Array.newInstance(String.class, 10);
names[0] = "KiDe";
// 设置数组中下标为1的元素的值
Array.set(names, 1, "Kid"); // 创建两个三维数组
int[][][] matrix1 = (int[][][]) Array.newInstance(int.class, 3, 3, 3);
matrix1[0][0][0] = 12;
int[][][] matrix2 = (int[][][]) Array.newInstance(int[].class, 3, 4); // 这个其实也是三维数组,因为数组的类型是int[]
matrix2[0][0][0] = 11;
matrix2[0][1] = new int[3]; } /**
* 反射获取构造方法的测试例子
*/
@SuppressWarnings("unchecked")
private void testConstructors() {
try {
// Part1: 测试getConstructors方法,直接调用该方法,不会返回父类的构造方法。只会返回当前类的public类型的构造函数。
Constructor<Child>[] childConstructors = (Constructor<Child>[]) Child.class.getConstructors();
/**
* 输出为:
com.rampage.jdk7.chapter2.Child
[Ljava.lang.reflect.Parameter;@15db9742
1
*/
for (Constructor<Child> constructor : childConstructors) {
System.out.println(constructor.getName());
System.out.println(constructor.getParameters());
System.out.println(constructor.getParameterCount());
} Constructor<Parent>[] parentConstructors = (Constructor<Parent>[]) Parent.class.getConstructors();
/**
* 输出为:
com.rampage.jdk7.chapter2.Parent
[Ljava.lang.Class;@6d06d69c
1
com.rampage.jdk7.chapter2.Parent
[Ljava.lang.Class;@7852e922
0
发现其实不管该构造函数是否有参数getParameterTypes或者getParameters都会返回值
*/
for (Constructor<Parent> constructor : parentConstructors) {
System.out.println(constructor.getName());
System.out.println(constructor.getParameterTypes());
System.out.println(constructor.getParameterCount());
}
Parent.class.getConstructor();
Parent.class.getConstructor(double.class);
// Parent.class.getConstructor(void.class); 会抛出异常,当构造函数没有参数的时候直接不传即可,而不能传void.class
// Parent.class.getConstructor(int.class); 会抛出异常,因为以int为参数的构造函数是不存在的 // Part2: 测试getDeclaredConstruct,该方法能够得到当前类的所有构造函数,不管是public/protected还是private。
childConstructors = (Constructor<Child>[]) Child.class.getDeclaredConstructors();
/**
* 输出为:
com.rampage.jdk7.chapter2.Child
[Ljava.lang.reflect.Parameter;@4e25154f
1
com.rampage.jdk7.chapter2.Child
[Ljava.lang.reflect.Parameter;@70dea4e
1
*/
for (Constructor<Child> constructor : childConstructors) {
System.out.println(constructor.getName());
System.out.println(constructor.getParameters());
System.out.println(constructor.getParameterCount());
// 私有的构造函数实例化对象的时候需要先调用 setAccessible(true),否则会报权限错误。
} // Part3: 参数长度可变的构造函数
// 获取构造函数的时候指定构造函数的参数应当当作数组来指定
Constructor<VaragsConstructor> constructor = VaragsConstructor.class.getDeclaredConstructor(int[].class);
System.out.println(constructor.getName()); // com.rampage.jdk7.chapter2.VaragsConstructor
// 利用得到的Constructor创建对象的实例时,可以把传入的参数转换成Object类型,也可以使用参数类型的数组
VaragsConstructor obj = constructor.newInstance((Object) (new int[] {1, 2, 3, 4}));
obj = constructor.newInstance(new int[] {1, 2, 3, 4}); // Part4: 嵌套类的构造方法
// 嵌套类需要区分静态嵌套类和非静态嵌套类,对于静态嵌套类,获得其构造函数的方法和其他的非嵌套类没有区别,对于非静态的嵌套类,
// 因为必须先初始化外部类才能使用非静态的嵌套类, 因此在获取构造函数以及使用得到的构造函数实例化对象的时候第一个参数必须是外部类class和外部类实例
Constructor<NestedClass> constructor2 = NestedClass.class.getDeclaredConstructor(NonStaticNestedClass.class, int.class);
NonStaticNestedClass object = new NonStaticNestedClass();
constructor2.newInstance(object, 12);
} catch (ReflectiveOperationException e) { // 在java6中各种反射的异常需要逐个捕获。而java7提供了一个新的异常类: ReflectiveOperationException,该类可以捕获所有反射操作的异常(因为他是所有反射操作异常的父类)
System.out.println(e.getCause()); // 得到异常的具体信息
} } /**
* 反射进行域处理的例子
*/
private void testFields() {
// 同样测试getField和getDeclareField的区别
Field[] fields = Child.class.getFields();
System.out.println();
/**
* 输出为:
field3
field3
可以看出这时候获得了父和子中所有的public的field
*/
for (Field field : fields) {
System.out.println(field.getName());
} fields = Child.class.getDeclaredFields();
System.out.println();
/**
* 输出为:
field0
field1
field2
field3
可以看出此时输出了自己本身这个类中的所有域而不仅仅是public的
*/
for (Field field : fields) {
System.out.println(field.getName());
// 给私有的域设置值需要先调用 setAccessible(true),否则会报权限错误。
}
} private void testMethods() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method[] methods = Child.class.getMethods();
System.out.println();
/**
* 输出为:
parentMethod
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
可以看出把所有继承层次中(包括Object)的public方法都或得到了
*/
for (Method method : methods) {
System.out.println(method.getName());
} methods = Child.class.getDeclaredMethods();
System.out.println();
/**
* 输出为:
ChildMethod
只是获得了当前类中的所有方法
*/
for (Method method : methods) {
System.out.println(method.getName());
// 对于私有的method如果直接调用会抛出异常但是通过 method.setAccessible(true)就可以解决这一问题。
}
} /**
* 用反射实现的设置某个属性值的方法
* 通过反射API,java也可以应用在灵活性很高的场景中,最长见的Servlet中http请求参数值的填充。
* 虽然随着java虚拟机性能的改进,反射API的性能有所提升。但是反射方法和非反射方法的性能差距还是客观存在的。
* 因此在一些性能要求很高的场景中要慎用反射API或者将常调用的反射获得的方法先缓存起来。
*/
void invokeSetter(Object obj, String field, Object value) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
String methodName = "set" + field.substring(0, 1).toUpperCase() + field.substring(1);
Class<?> clazz = obj.getClass();
Method setMethod = clazz.getMethod( methodName, value.getClass());
setMethod.invoke(obj, value);
}
} class Parent {
String field0;
private String field1;
protected String field2;
public String field3; public Parent(double a) {}
public Parent() {}
public void parentMethod() {}
} class Child extends Parent {
String field0;
private String field1;
protected String field2;
public String field3; // 如果父类没有同样的构造函数,则默认会调用父类的无参构造函数,如果父类没有无参构造函数,则编译会报错,会要求显示调用父类的某一个构造函数,以确保父类会在子类被实例化之前被实例化。
public Child(int i) {}
private Child(long l) {}
private void ChildMethod() {}
} class VaragsConstructor {
public VaragsConstructor(int... varags) {};
} class NonStaticNestedClass {
class NestedClass {
NestedClass(int i) {}
}
}

ReflectionAPI

JDK1.7新特性(4):java语言动态性之反射API的更多相关文章

  1. JDK1.7新特性(3):java语言动态性之脚本语言API

    简要描述:其实在jdk1.6中就引入了支持脚本语言的API.这使得java能够很轻松的调用其他脚本语言.具体API的使用参考下面的代码: package com.rampage.jdk7.chapte ...

  2. JDK1.7新特性

    jdk1.7新特性 1 对集合类的语言支持: 2 自动资源管理: 3 改进的通用实例创建类型推断: 4 数字字面量下划线支持: 5 switch中使用string: 6 二进制字面量: 7 简化可变参 ...

  3. jdk1.6新特性

    1.Web服务元数据 Java 里的Web服务元数据跟微软的方案基本没有语义上的区别,自从JDK5添加了元数据功能(Annotation)之后,SUN几乎重构了整个J2EE体 系, 由于变化很大,干脆 ...

  4. JDK1.6新特性,WebService强化

    Web service是一个平台独立的,松耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布式的互操作的应用程序. Web ...

  5. JDK1.5新特性,基础类库篇,集合框架(Collections)

    集合框架在JDK1.5中增强特性如下: 一. 新语言特性的增强 泛型(Generics)- 增加了集合框架在编译时段的元素类型检查,节省了遍历元素时类型转换代码量. For-Loop循环(Enhanc ...

  6. jdk1.5新特性之-----自动装箱与自动拆箱

    import java.util.ArrayList; /* jdk1.5新特性之-----自动装箱与自动拆箱. java是面向对象 的语言,任何事物都可以使用类进行描述,sun就使用了 一些类描述j ...

  7. JDK1.7新特性(2):异常和可变长参数处理

    异常 jdk1.7对try--catch--finally的异常处理模式进行了增强,下面我们依次来看增强的方面. 1. 为了防止异常覆盖,给Throwable类增加了addSuppressed方法,可 ...

  8. jdk1.8新特性应用之Iterable

    我们继续看lambda表达式的应用: public void urlExcuAspect(RpcController controller, Message request, RpcCallback ...

  9. jdk1.8新特性之lambda表达式

    lambda表达式其实就是指一个匿名函数,应用最广泛的就是匿名内部类的简化.在jdk1.8之前,我们定义一个匿名内部类可能需要写一大坨代码,现在有了lambda之后,可以写的很简洁了.但不是说lamb ...

随机推荐

  1. 【node错误】/usr/bin/env: node: No such file or directory

    背景 安装了node后,执行npm run xxx的命令的时候,报错,提示如下: /usr/bin/env: node: No such file or directory 步骤 1. 什么玩意,执行 ...

  2. 使用centos官方镜像制作jdk8环境镜像

    首先将jdk文件或者tar包放在/var/local路径下 然后Dockerfile中写 # 以 centos7 为基础镜像 FROM centos:latest MAINTAINER chen # ...

  3. 创建jdk8基础镜像

    https://blog.csdn.net/qq_35981283/article/details/80738451

  4. c# .NET RSA结合AES加密服务端和客户端请求数据

    这几天空闲时间就想研究一下加密,环境是web程序,通过js请求后台返回数据,我想做的事js在发送请求前将数据加密,服务端收到后解密,待服务端处理完请求后,将处理结果加密返回给客户端,客户端在解密,于是 ...

  5. 「NOI2014」魔法森林

    题目链接 戳我 \(Solution\) 两个变量,emm...不好搞啊. 于是我们可以按照\(A\)排序.然后动态加边,因为\(A\)是越来越大,所以不需要管他,只要使得\(1\)~\(n\)的路径 ...

  6. “全栈2019”Java第一百零九章:匿名内部类实现唯一抽象类或接口

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  7. mybatis常用默认配置

    设置参数 描述 有效值 默认值 cacheEnable 该配置影响所有映射器中配置的缓存全局开关 true.false true lazyLoadingEnable 延迟加载的全局开关.当它开启时,所 ...

  8. HTML基础总纲

    我看了很多博客感觉如果自己写的话还不一定有人家写的好,在介于我没有时间从这么细小的知识总结,那么人家总结好的我们为什么不用,完了之后在就自己的感受和不足之处在做补充. 我们一个的讲:主要参考: 一,H ...

  9. Dubbo自定义日志拦截器

    前言 上一篇文章 Spring aop+自定义注解统一记录用户行为日志 记录了 web层中通过自定义注解配合Spring aop自动记录用户行为日志的过程.那么按照分布式架构中Dubbo服务层的调用过 ...

  10. leetcode-888-公平的糖果交换

    题目描述: 爱丽丝和鲍勃有不同大小的糖果棒:A[i] 是爱丽丝拥有的第 i 块糖的大小,B[j] 是鲍勃拥有的第 j 块糖的大小. 因为他们是朋友,所以他们想交换一个糖果棒,这样交换后,他们都有相同的 ...