JDK1.7新特性(4):java语言动态性之反射API
直接通过一个代码示例来熟悉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的更多相关文章
- JDK1.7新特性(3):java语言动态性之脚本语言API
简要描述:其实在jdk1.6中就引入了支持脚本语言的API.这使得java能够很轻松的调用其他脚本语言.具体API的使用参考下面的代码: package com.rampage.jdk7.chapte ...
- JDK1.7新特性
jdk1.7新特性 1 对集合类的语言支持: 2 自动资源管理: 3 改进的通用实例创建类型推断: 4 数字字面量下划线支持: 5 switch中使用string: 6 二进制字面量: 7 简化可变参 ...
- jdk1.6新特性
1.Web服务元数据 Java 里的Web服务元数据跟微软的方案基本没有语义上的区别,自从JDK5添加了元数据功能(Annotation)之后,SUN几乎重构了整个J2EE体 系, 由于变化很大,干脆 ...
- JDK1.6新特性,WebService强化
Web service是一个平台独立的,松耦合的,自包含的.基于可编程的web的应用程序,可使用开放的XML标准来描述.发布.发现.协调和配置这些应用程序,用于开发分布式的互操作的应用程序. Web ...
- JDK1.5新特性,基础类库篇,集合框架(Collections)
集合框架在JDK1.5中增强特性如下: 一. 新语言特性的增强 泛型(Generics)- 增加了集合框架在编译时段的元素类型检查,节省了遍历元素时类型转换代码量. For-Loop循环(Enhanc ...
- jdk1.5新特性之-----自动装箱与自动拆箱
import java.util.ArrayList; /* jdk1.5新特性之-----自动装箱与自动拆箱. java是面向对象 的语言,任何事物都可以使用类进行描述,sun就使用了 一些类描述j ...
- JDK1.7新特性(2):异常和可变长参数处理
异常 jdk1.7对try--catch--finally的异常处理模式进行了增强,下面我们依次来看增强的方面. 1. 为了防止异常覆盖,给Throwable类增加了addSuppressed方法,可 ...
- jdk1.8新特性应用之Iterable
我们继续看lambda表达式的应用: public void urlExcuAspect(RpcController controller, Message request, RpcCallback ...
- jdk1.8新特性之lambda表达式
lambda表达式其实就是指一个匿名函数,应用最广泛的就是匿名内部类的简化.在jdk1.8之前,我们定义一个匿名内部类可能需要写一大坨代码,现在有了lambda之后,可以写的很简洁了.但不是说lamb ...
随机推荐
- expect+scp传输文件发现文件丢失
背景 使用expect+scp去跨机器传输文件,(别问我为什么,因为公司的测试机器都是通过堡垒机的,无法绕开堡垒机,只能暂时使用这个方法了),结果发现从A传递到B的tar.gz文件大小不一致了的,当时 ...
- osgi.net框架
osgi.net是一个动态的模块化框架.它向用户提供了模块化与插件化.面向服务构架和模块扩展支持等功能.该平台是OSGi联盟定义的服务平台规范移植到.NET的实现. 简介 尤埃开放服务平台是一个基于. ...
- sharepoint 2007 log track
1. 以管理员权限运行CMD 2. 运行命令: NOTEPAD c:\windows\system32\drivers\etc\hosts 3. 在打开的记事本中最后一行添加一条记录后保存. ...
- iOS Facebook SDK
iOS 使用 Facebook SDK 可以登录,分享,发布通知(Notifications)等. 首先下载 Facebook SDK.然后在 Facebook Developer 上注册自己的 ap ...
- c语言第六次作业---结构体&文件
1.本章学习总结 1.1思维导图 1.2学习体会 这次应该是本学期最后一次博客了,总结一下这个学期的学习,一开始就基础薄弱还一直畏难一直懒惰,不想去解决问题导致后面问题越来越多就觉得学习越来越难,后面 ...
- python3+requests:post请求四种传送正文方式(详解)
前言:post请求我在python接口自动化2-发送post请求详解(二)已经讲过一部分了,主要是发送一些较长的数据,还有就是数据比较安全等,可以参考Get,Post请求方式经典详解进行学习一下. 我 ...
- SQL查询表结构的语句
SELECT tableName=CASE WHEN a.colorder=1 THEN d.name ELSE '' END ,表说明 =CASE WHEN a.colorder=1 THEN IS ...
- Python元类编程
来源:http://python.jobbole.com/88582/ @property装饰器,是将类中的函数当做属性调用 Python类中定义的属性,如果属性名前面只有一个下划线,那么就是一种规范 ...
- 在 Go 语言中使用 Log 包--转自GCTT
Linux 在许多方面相对于 Windows 来说都是独特的,在 Linux 中编写程序也不例外.标准输出,标准 err 和 null devices 的使用不仅是一个好主意,也是一个原则.如果您的程 ...
- [Alpha]Scrum Meeting#7
github 本次会议项目由PM召开,时间为4月9日晚上10点30分 时长15分钟 任务表格 人员 昨日工作 下一步工作 木鬼 整理并发布之前因为清明耽误的博客 撰写每日例会报告 SiMrua 添加暂 ...