Java反射学习
2009-04-05 00:18
330 查看
Reflection是Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性。例如,使用它能获得 Java 类中各成员的名称并显示出来。
Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。 JavaBean 是 reflection 的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过 reflection 动态的载入并取得 Java 组件(类) 的属性。
反射除了显示类的自身信息外,它还可以创建对象和执行方法等
(1)找出类的方法
找出一个类中定义了些什么方法,这是一个非常有价值也非常基础的 reflection 用法,示例代码如下:
Java代码
import java.lang.reflect.*;
/**
*获取指定类的方法相关信息
*/
class InformationTest
{
public static void main(String[] args) throws Exception
{
//得到String类对象
Class cls=Class.forName("java.lang.String");
//得到所有的方法,包括从父类继承过来的方法
Method []methList=cls.getMethods();
//下面是得到的是String类本身声明的方法
//Method []methList=cls.getDeclaredMethods();
//遍历所有的方法
for(Method m:methList){
//方法名
System.out.println("方法名="+m.getName());
//方法声明所在的类
System.out.println("声明的类="+m.getDeclaringClass());
//获取所有参数类型的集体
Class []paramTypes=m.getParameterTypes();
//遍历参数类型
for(int i=0;i<paramTypes.length;i++){
System.out.println("参数 "+i+" = "+paramTypes[i]);
}
//获取所有异常的类型
Class []excepTypes=m.getExceptionTypes();
//遍历异常类型
for(int j=0;j<excepTypes.length;j++){
System.out.println("异常 "+j+" = "+excepTypes[j]);
}
//方法的返回类型
System.out.println("返回类型 ="+m.getReturnType());
//结束一层循环标志
System.out.println("---------");
}
}
}
import java.lang.reflect.*; /** *获取指定类的方法相关信息 */ class InformationTest { public static void main(String[] args) throws Exception { //得到String类对象 Class cls=Class.forName("java.lang.String"); //得到所有的方法,包括从父类继承过来的方法 Method []methList=cls.getMethods(); //下面是得到的是String类本身声明的方法 //Method []methList=cls.getDeclaredMethods(); //遍历所有的方法 for(Method m:methList){ //方法名 System.out.println("方法名="+m.getName()); //方法声明所在的类 System.out.println("声明的类="+m.getDeclaringClass()); //获取所有参数类型的集体 Class []paramTypes=m.getParameterTypes(); //遍历参数类型 for(int i=0;i<paramTypes.length;i++){ System.out.println("参数 "+i+" = "+paramTypes[i]); } //获取所有异常的类型 Class []excepTypes=m.getExceptionTypes(); //遍历异常类型 for(int j=0;j<excepTypes.length;j++){ System.out.println("异常 "+j+" = "+excepTypes[j]); } //方法的返回类型 System.out.println("返回类型 ="+m.getReturnType()); //结束一层循环标志 System.out.println("---------"); } } }
(2) 获取构造器信息
获取类构造器的用法与上述获取方法的用法类似,示例代码如下:
Java代码
import java.lang.reflect.*;
import java.io.IOException;
/**
*获取指定类的构造器相关信息
*/
public class ConstructorTest
{
private int i;
private double j;
//默认的构造器
public ConstructorTest(){
}
//重载的构造器
public ConstructorTest(int i,double j)throws IOException{
this.i=i;
this.j=j;
}
public static void main(String[] args) throws Exception
{
//得到本类的类对象
Class cls=Class.forName("ConstructorTest");
//取得所有在本类声明的构造器
Constructor []cs=cls.getDeclaredConstructors();
//遍历
for(Constructor c:cs){
//构造器名称
System.out.println("构造器名="+c.getName());
//构造器声明所在的类
System.out.println("其声明的类="+c.getDeclaringClass());
//取得参数的类型集合
Class []ps=c.getParameterTypes();
//遍历参数类型
for(int i=0;i<ps.length;i++){
System.out.println("参数类型"+i+"="+ps[i]);
}
//取得异常的类型集合
Class []es=c.getExceptionTypes();
//遍历异常类型
for(int j=0;j<es.length;j++){
System.out.println("异常类型"+j+"="+es[j]);
}
//结束一层循环标志
System.out.println("-----------");
}
}
}
import java.lang.reflect.*; import java.io.IOException; /** *获取指定类的构造器相关信息 */ public class ConstructorTest { private int i; private double j; //默认的构造器 public ConstructorTest(){ } //重载的构造器 public ConstructorTest(int i,double j)throws IOException{ this.i=i; this.j=j; } public static void main(String[] args) throws Exception { //得到本类的类对象 Class cls=Class.forName("ConstructorTest"); //取得所有在本类声明的构造器 Constructor []cs=cls.getDeclaredConstructors(); //遍历 for(Constructor c:cs){ //构造器名称 System.out.println("构造器名="+c.getName()); //构造器声明所在的类 System.out.println("其声明的类="+c.getDeclaringClass()); //取得参数的类型集合 Class []ps=c.getParameterTypes(); //遍历参数类型 for(int i=0;i<ps.length;i++){ System.out.println("参数类型"+i+"="+ps[i]); } //取得异常的类型集合 Class []es=c.getExceptionTypes(); //遍历异常类型 for(int j=0;j<es.length;j++){ System.out.println("异常类型"+j+"="+es[j]); } //结束一层循环标志 System.out.println("-----------"); } } }
(3) 获取类的字段(域)
找出一个类中定义了哪些数据字段也是可能的,下面的代码就在干这个事情:
Java代码
import java.lang.reflect.*;
/**
*获取指定类的字段相关信息
*/
class FieldTest
{
//字段1
private double d;
//字段2
public static final int i=37;
//字段3
String str="fieldstest";
public static void main(String[] args) throws Exception
{
//获取本类的类对象
Class c=Class.forName("FieldTest");
//获取所有声明的的字段,getFields()包括继承来的字段
Field []fs=c.getDeclaredFields();
//遍历
for(int i=0;i<fs.length;i++){
Field f=fs[i];
//字段名
System.out.println("字段名"+(i+1)+"="+f.getName());
//字段声明所在的类
System.out.println("该字段所在的类为:"+f.getDeclaringClass());
//字段的类型
System.out.println("字段"+(i+1)+"的类型:"+f.getType());
//查看修饰符
int mod=f.getModifiers();
//为0就是默认的包类型
if(mod==0){
System.out.println("该字段的修饰符为:默认包修饰符");
}else{
//否则就是相应的类型
System.out.println("该字段的修饰符为:"+Modifier.toString(mod));
}
System.out.println("---结束第"+(i+1)+"循环---");
}
}
}
import java.lang.reflect.*; /** *获取指定类的字段相关信息 */ class FieldTest { //字段1 private double d; //字段2 public static final int i=37; //字段3 String str="fieldstest"; public static void main(String[] args) throws Exception { //获取本类的类对象 Class c=Class.forName("FieldTest"); //获取所有声明的的字段,getFields()包括继承来的字段 Field []fs=c.getDeclaredFields(); //遍历 for(int i=0;i<fs.length;i++){ Field f=fs[i]; //字段名 System.out.println("字段名"+(i+1)+"="+f.getName()); //字段声明所在的类 System.out.println("该字段所在的类为:"+f.getDeclaringClass()); //字段的类型 System.out.println("字段"+(i+1)+"的类型:"+f.getType()); //查看修饰符 int mod=f.getModifiers(); //为0就是默认的包类型 if(mod==0){ System.out.println("该字段的修饰符为:默认包修饰符"); }else{ //否则就是相应的类型 System.out.println("该字段的修饰符为:"+Modifier.toString(mod)); } System.out.println("---结束第"+(i+1)+"循环---"); } } }
(4) 根据方法的名称来执行方法
我们也可以用 reflection 来做一些其它的事情,比如执行一个指定了名称的方法。下面的示例演示了这一操作:
Java代码
import java.lang.reflect.*;
/**
*通过反射执行类的方法
*/
class PerformMethod
{
//声明一个简单的方法,用于测试
public int add(int a,int b){
return a+b;
}
public static void main(String[] args)throws Exception
{
//获取本类的类对象
Class c=Class.forName("PerformMethod");
/**
*声明add方法参数类型的集合
*共有两个参数,都为Integer.TYPE
*/
Class []paramTypes=new Class[2];
paramTypes[0]=Integer.TYPE;
paramTypes[1]=Integer.TYPE;
//根据方法名和参数类型集合得到方法
Method method=c.getMethod("add",paramTypes);
//声明类的实例
PerformMethod pm=new PerformMethod();
//传入参数的集合
Object []argList=new Object[2];
//传入37和43
argList[0]=new Integer(37);
argList[1]=new Integer(43);
//执行后的返回值
Object returnObj=method.invoke(pm,argList);
//类型转换下
Integer returnVal=(Integer)returnObj;
//打印结果
System.out.println("方法执行结果为:"+returnVal.intValue());
}
}
import java.lang.reflect.*; /** *通过反射执行类的方法 */ class PerformMethod { //声明一个简单的方法,用于测试 public int add(int a,int b){ return a+b; } public static void main(String[] args)throws Exception { //获取本类的类对象 Class c=Class.forName("PerformMethod"); /** *声明add方法参数类型的集合 *共有两个参数,都为Integer.TYPE */ Class []paramTypes=new Class[2]; paramTypes[0]=Integer.TYPE; paramTypes[1]=Integer.TYPE; //根据方法名和参数类型集合得到方法 Method method=c.getMethod("add",paramTypes); //声明类的实例 PerformMethod pm=new PerformMethod(); //传入参数的集合 Object []argList=new Object[2]; //传入37和43 argList[0]=new Integer(37); argList[1]=new Integer(43); //执行后的返回值 Object returnObj=method.invoke(pm,argList); //类型转换下 Integer returnVal=(Integer)returnObj; //打印结果 System.out.println("方法执行结果为:"+returnVal.intValue()); } }
(5) 创建新的对象
对于构造器,则不能像执行方法那样进行,因为执行一个构造器就意味着创建了一个新的对象 (准确的说,创建一个对象的过程包括分配内存和构造对象)。所以,与上例最相似的例子如下:
Java代码
import java.lang.reflect.*;
/**
*通过反射创新类的新对象
*/
class CreateNewObj
{
//显式默认的构造器
public CreateNewObj(){
}
//重载构造器
public CreateNewObj(int a,int b){
System.out.println("a= "+a+" b="+b);
}
public static void main(String[] args) throws Exception
{
//得到本类的类对象
Class c=Class.forName("CreateNewObj");
//声明构造器的参数类型集合
Class []paramTypes=new Class[2];
//都为int型
paramTypes[0]=Integer.TYPE;
paramTypes[1]=Integer.TYPE;
//根据参数类型决定得到哪个构造器
Constructor cs=c.getConstructor(paramTypes);
//声明要传入的参数集合
Object []argList=new Object[2];
//传入37和43
argList[0]=new Integer(37);
argList[1]=new Integer(43);
//根据符合上述参数类型的构造器来创建新的对象
Object rtnObj=cs.newInstance(argList);
}
}
import java.lang.reflect.*; /** *通过反射创新类的新对象 */ class CreateNewObj { //显式默认的构造器 public CreateNewObj(){ } //重载构造器 public CreateNewObj(int a,int b){ System.out.println("a= "+a+" b="+b); } public static void main(String[] args) throws Exception { //得到本类的类对象 Class c=Class.forName("CreateNewObj"); //声明构造器的参数类型集合 Class []paramTypes=new Class[2]; //都为int型 paramTypes[0]=Integer.TYPE; paramTypes[1]=Integer.TYPE; //根据参数类型决定得到哪个构造器 Constructor cs=c.getConstructor(paramTypes); //声明要传入的参数集合 Object []argList=new Object[2]; //传入37和43 argList[0]=new Integer(37); argList[1]=new Integer(43); //根据符合上述参数类型的构造器来创建新的对象 Object rtnObj=cs.newInstance(argList); } }
(6) 改变字段(域)的值
reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点:
Java代码
reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点:
import java.lang.reflect.*;
/**
*通过反射改变字段的值
*/
class ModifyField
{
//声明一个字段
public double d;
public static void main(String[] args) throws Exception
{
//得到类的类对象
Class c=Class.forName("ModifyField");
//根据字段名得到字段对象
Field f=c.getField("d");
//创建类的实例
ModifyField mf=new ModifyField();
//打印修改前字段的值
System.out.println("修改 "+f.getName()+" 前的值为:"+mf.d);
//修改d的值为12.34
f.setDouble(mf,12.34);
//打印修改后的值
System.out.println("修改 "+f.getName()+" 后的值为:"+mf.d);
}
}
reflection 的还有一个用处就是改变对象数据字段的值。reflection 可以从正在运行的程序中根据名称找到对象的字段并改变它,下面的例子可以说明这一点: import java.lang.reflect.*; /** *通过反射改变字段的值 */ class ModifyField { //声明一个字段 public double d; public static void main(String[] args) throws Exception { //得到类的类对象 Class c=Class.forName("ModifyField"); //根据字段名得到字段对象 Field f=c.getField("d"); //创建类的实例 ModifyField mf=new ModifyField(); //打印修改前字段的值 System.out.println("修改 "+f.getName()+" 前的值为:"+mf.d); //修改d的值为12.34 f.setDouble(mf,12.34); //打印修改后的值 System.out.println("修改 "+f.getName()+" 后的值为:"+mf.d); } }
(7)使用数组
reflection 的最后一种用法是创建的操作数组。数组在 Java 语言中是一种特殊的类类型,一个数组的引用可以赋给 Object 引用。观察下面的例子看看数组是怎么工作的:
Java代码
import java.lang.reflect.*;
/**
*通过反射来操作数组
*/
class UserArray
{
public static void main(String[] args) throws Exception
{
//得到String类的类对象
Class c=Class.forName("java.lang.String");
//通过Array类的反射创建一个含有10个元素的String类型的数组
Object arr=Array.newInstance(c,10);
//为数组第5个位置元素赋一个值
Array.set(arr,5,"第5个位置元素");
//取得第5个位置元素的值
String s=(String)Array.get(arr,5);
//打印这个元素的值
System.out.println("值为:"+s);
}
}
import java.lang.reflect.*; /** *通过反射来操作数组 */ class UserArray { public static void main(String[] args) throws Exception { //得到String类的类对象 Class c=Class.forName("java.lang.String"); //通过Array类的反射创建一个含有10个元素的String类型的数组 Object arr=Array.newInstance(c,10); //为数组第5个位置元素赋一个值 Array.set(arr,5,"第5个位置元素"); //取得第5个位置元素的值 String s=(String)Array.get(arr,5); //打印这个元素的值 System.out.println("值为:"+s); } }
看下更复杂的情况:
Java代码
import java.lang.reflect.*;
/**
*通过反射创建和使用更复杂的数组
*/
class UserArrayComplex
{
public static void main(String[] args) throws Exception
{
//声明数组的维数为5X10X15
int dims[]=new int []{5,10,15};
//创建该类型的数组,元素的类型为Integer
Object arr=Array.newInstance(Integer.TYPE,dims);
//得到第3个10X15的二维数组
Object arrObj=Array.get(arr,3);
//Class c=arrObj.getClass().getComponentType();
//System.out.println(c);
//得到第2维中的第2个15位长度的数组
arrObj=Array.get(arrObj,5);
//然后设置该数组里第10个元素的值为37
Array.set(arrObj,10,37);
//再将数组还原
int [][][]arrCast=(int [][][])arr;
//打印刚刚那个值
System.out.println(arrCast[3][5][10]);
}
}
import java.lang.reflect.*; /** *通过反射创建和使用更复杂的数组 */ class UserArrayComplex { public static void main(String[] args) throws Exception { //声明数组的维数为5X10X15 int dims[]=new int []{5,10,15}; //创建该类型的数组,元素的类型为Integer Object arr=Array.newInstance(Integer.TYPE,dims); //得到第3个10X15的二维数组 Object arrObj=Array.get(arr,3); //Class c=arrObj.getClass().getComponentType(); //System.out.println(c); //得到第2维中的第2个15位长度的数组 arrObj=Array.get(arrObj,5); //然后设置该数组里第10个元素的值为37 Array.set(arrObj,10,37); //再将数组还原 int [][][]arrCast=(int [][][])arr; //打印刚刚那个值 System.out.println(arrCast[3][5][10]); } }
OK,掌握以上几点Java的反射差不多就会使用了!
相关文章推荐
- java学习之反射
- java中的反射学习笔记(一)
- 黑马程序员-Java学习(高新)16-枚举,反射
- Java 反射学习(二)成员变量的反射
- 我的java学习笔记(13)关于反射(part 2)
- java 反射的学习。
- Java反射学习总结五(Annotation(注解)-基础篇)
- 【Java基础学习】 详解Java的反射机制
- Java反射学习
- Java反射学习总结
- Java基础班学习笔记(17)反射
- 【Java学习】使用泛型和反射 创建通用的数据库查询方法
- Java学习笔记——网络编程、反射
- Java基础学习(1)——反射
- Java学习笔记之反射(Reflection)
- Java反射之获取类的相关信息学习笔记(一)
- Java学习之反射机制
- 黑马程序员—JAVA基础学习日记十——反射学习总结
- Java中的反射学习及反射解耦应用
- 黑马程序员—Java学习笔记之必须掌握的反射技术