直接通过一个代码示例来熟悉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. PostgreSQL 区域设置

    安装PostgreSQL 10.3 windows版本时区域请选择"default locale",安装成功后输入命令: show lc_ctype; show lc_collat ...

  2. WPF解决方案------调用线程无法访问此对象,因为另一个线程拥有该对象

    WPF [调用线程无法访问此对象,因为另一个线程拥有该对象.] 解决方案 在这里以播放图片为例进行说明,代码如下: void _Timer_Elapsed(object sender, Elapsed ...

  3. Java50道经典习题-程序12 计算奖金

    题目:企业发放的奖金根据利润提成.利润(I)低于或等于10万元时,奖金可提10%:    利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%:     ...

  4. java学习笔记—国际化(41)

    国际化:internationalization即I18N. 举例: 本科高校的网站,一般的都有中文和英文两种页面风格.因此将这种根据不同用户群体显示不同的页面风格的方式称之为页面的国际化. 翻译 V ...

  5. “全栈2019”Java异常第九章:throws关键字详解

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

  6. Wannafly挑战赛29题解

    这套题目非常有意思啊23333--话说为啥没有上条先生的呢-- 传送门 \(A\) 御坂美琴 蠢了--首先先判总共加起来等不等于\(n\),不是的话就不行 然后dfs记录\(n\)不断分下去能分成哪些 ...

  7. Wireshark系列(从入门到精通的10个干货)

    Wireshark(前称Ethereal)是一个网络封包分析软件.网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料.Wireshark使用WinPCAP作为接口,直接与网卡进 ...

  8. lamp-linux-1

    LAMP编程之Linux(1) LAMP:Linux Apache MySQL PHP LNMP:Linux Nginx MySQL PHP WAMP:Windows Apache MySQL PHP ...

  9. input disabled的情况下在IOS设备中怎么修改颜色

    -webkit-text-fill-color:black; -webkit-opacity:1; opacity: 1; 一句代码就欧了

  10. html中文字溢出处理(text-overflow)

    文字溢出处理有两种方式: 一.css overflow:hidden;            white-space: nowrap;            text-overflow: ellips ...