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 ...
随机推荐
- 随手记录: MVC自定义提交form
function mySubmit() { var frm = $('#frm'); var result = frm.valid(); if (ret) { frm.submit(); } else ...
- WinForm 窗体应用程序(初步)之三
进程: 进程,简单的说,就是让你的程序启动另一个程序. 1.Process.Start("calc");//启动计算器 弊端:只认识系统自带的程序,如果写错系统会崩溃. 2. // ...
- html中事件调用JavaScript函数时有return与没有return的区别
JAVASCRIPT在事件中调用函数时用return返回值实际上是对window.event.returnvalue进行设置. 而该值决定了当前操作是否继续.当返回的是true时,将继续操作.当返回是 ...
- 【cocos2d-x 手游研发小技巧(3)Android界面分辨率适配方案】
先感叹一下吧~~android的各种分辨率各种适配虐我千百遍,每次新项目我依旧待它如初恋···· 每家公司都有自己项目工程适配的方案,这种东西就是没有最好,只有最适合!!! 这次新项目专项针对andr ...
- django系列4.2--自定义标签, 自定义过滤器, inclusion_tag, 引入静态文件(css,js等)
项目的目录为 在app中创建templates时,最好要再创建一个app名相同的文件夹,因为项目找文件时从第一个app开始遍历,不同app内的同名文件会有冲突,所以这样处理 一.自定义标签和过滤器 1 ...
- Gogland配置- 去掉Go源代码中的参数提示
Gogland处于好意,在Go源代码中对每个参数提示类型,这或许方便大家处理源代码,但是我觉得对于正常阅读源代码反而造成一种负担,我决定去掉这个功能! Gogland默认配置状态,有参数提示: 下面是 ...
- python文件备份与简单操作
#!/usr/bin/python # -*- coding: utf-8 -*- # data:2018/8/30 # user:fei import sys import random num = ...
- 开源代码MyCommons
MyCommons是我在开发Android App中,经过多个项目的实践和应用,上十次修改的,总结起来的代码,目的是希望大家能够快速的完成项目的开发. 主要也是参考了afinal和xutils2个框架 ...
- docker 实例设置自动重启
yaml格式太严格了,每个冒号后面都必须带有空格在linux中./代表当前目录,属于相对路径../代表上一级目录,属于相对路径/代表根目录,/开头的文件都是绝对路径./configure的意思是执行当 ...
- 43.oracle同义词
不愿长大,好多人如此,其实这是一种逃避责任没有担当的表象. 同义词 从字面上理解就是别名的意思,和视图的功能类似,就是一张映射关系. 私有同义词:一般是普通用户自己建立的同义词,创建者需要create ...