博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
重识java反射
阅读量:2441 次
发布时间:2019-05-10

本文共 7220 字,大约阅读时间需要 24 分钟。

说到java反射,不得不说说它的功能

通过java反射机制,可以在程序中访问已经装载到JVM中的java对象的描述,实现访问、检测和修改描述java对象本身的信息的功能。java反射机制的功能十分强大,在java.lang.reflect对该功能的支持。

注意:在Object类中定义了一个getClass()方法,该方法会返回了一个类型为Class的对象。

例如: Class  NameA  =  a.getClass();     // a为A类的一个对象  

以下表格描述的是通过反射可以访问的主要描述信息:

通过反射能够访问以下类的信息:

 1.访问构造方法:

Constructor类的常用方法:

 实例1:首先创建一个Demo1类,在该类中声明一个String类型的成员变量和3个int型的成员变量,并提供一个构造方法。代码如下:

package com.study.reflect;public class Demo1 {String s;int i,i1,i2;private Demo1() {	}protected Demo1(String s,int i) {	this.s=s;	this.i=i;}public Demo1(String...strings) throws NumberFormatException{	if(strings.length>0) {		i=Integer.valueOf(strings[0]);	}	if(strings.length>1) {		i1=Integer.valueOf(strings[1]);	}	if(strings.length>2) {		i2=Integer.valueOf(strings[2]);	}}public void print() {	System.out.println("s="+s);	System.out.println("i="+i);	System.out.println("i1="+i1);	System.out.println("i2="+i2);}}

下面再编写测试类Main1,在类中通过反射访Demo1类中的所有构造方法,并将该构造方法是否允许带有可变数量的参数、入口参数类型和可能抛出的异常类型输出到控制台。代码如下:

package com.study.reflect;import java.lang.reflect.Constructor;public class Main1 {public static void main(String []args) {	//创建一个Demo1类的对象	Demo1 demo1 = new Demo1("11","22","33");	//获取demo1对象的Class类的对象	Class
demoA = demo1.getClass(); //获取所有的构造方法即构造方法的数组,一个Constructor代表一个构造方法 Constructor
[] declaredConstructors = demoA.getDeclaredConstructors(); //遍历构造方法 for(int i=0;i
constructor = declaredConstructors[i]; System.out.println("查看是否允许带有可以变数量的参数:"+constructor.isVarArgs()); System.out.println("该构造方法的入口参数类型依次为:"); //以Class数组的形式获得该构造方法的各个参数的类型 Class
[] parameterTypes = constructor.getParameterTypes(); for(int j=0;j
[] exceptionTypes = constructor.getExceptionTypes(); for (int j = 0; j < exceptionTypes.length; j++) { //以字符串的形式输出可能抛出异常的class类型 System.out.println(" "+exceptionTypes[j]); } Demo1 demo2 = null; while(demo2==null) { try {//如果该成员变量的访问权限为private,则抛出异常,即不允许访问 if(i==2) {//通过执行默认没有参数的创建对象 demo2 = (Demo1) constructor.newInstance(); } else if(i==1) { //通过执行两个参数的构造方法创建对象 demo2 = (Demo1) constructor.newInstance("7",5); }else { //通过执行具有可变数量参数的构造方法创建对象 Object [] parameters = new Object [] {new String [] {"100","200","300"}}; //Object [] strings = new String[] {"100","200","300"}; demo2 = (Demo1) constructor.newInstance(parameters); } } catch (Exception e) { // TODO: handle exception System.out.println("在创建对象时抛出异常,下面执行setAccessible()方法"); /** * 如果当前构造方法的权限为private,默认不允许创建通过反射利用newInstance(Object... initargs)方法创建对象。 * 如果先执行该方法,并将入口参数设为true,则允许创建 */ constructor.setAccessible(true);//设置为允许访问 } if(demo2!=null) { demo2.print(); System.out.println(); } } }}}

运行这个实例,当通过反射Demo1()构造方法时,输出结果如下:

 当通过反射Demo1(String s,int i)构造方法时,输出结果如下:

当通过反射构造方法Demo1(String...strings) 时,输出结果如下:

2.访问成员变量 :

Field类的常用方法:

实例2:创建一个Demo2类,在该类中一次声明一个int、float、boolean、String型的成员变量,并将他们设置为不同的权限。代码如下:

package com.study.reflect;public class Demo2 {int i;public float fl;protected boolean bl;private String s;}

通过反射Demo2类中的所有成员变量,将成员变量的名称和类型信息输出到控制台,并分别设置为不同的访问权限;代码如下:

package com.study.reflect;import java.lang.reflect.Field;public class Main2 {public static void main(String []args) {	Demo2 demo = new Demo2();	Class
demo2 = demo.getClass(); //获取所有成员变量 Field[] declaredFields = demo2.getDeclaredFields(); for(int i=0;i
fieldType = f.getType(); System.out.println("类型为"+fieldType); boolean start = true; while(start) { //如果该成员变量的访问权限为private,则抛出异常,即不允许访问 try { start=false; //获取成员变量的值 System.out.println("修改前的值为"+f.get(demo)); //判断成员变量的类型是否为int型 System.out.println("ni"+fieldType); if(fieldType.equals(int.class)) { System.out.println("利用方法setInt()方法修改成员变量的值"); f.setInt(demo, 123); System.out.println("------"); }else if(fieldType.equals(float.class)) {//判断成员变量的类型是否为float型 System.out.println("利用方法setFloat()方法修改成员变量的值"); System.out.println("wwwwwww"); f.setFloat(demo, 111.1f); }else if(fieldType.equals(boolean.class)) {//判断成员变量的类型是否为boolean型 System.out.println("利用方法setBoolean()方法修改成员变量的值"); f.setBoolean(demo, true); }else { System.out.println("利用方法set()修改车成员变量的值"); //可以为各种类型的成员变量赋值 f.set(demo, "Success"); } //获取成员变量值 System.out.println("修改后的值为"+f.get(demo)); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); System.out.println("在设置成员变量值时抛出异常,"+"下面执行setAccessible()方法"); f.setAccessible(true);//设置为允许访问 start= true; } } } }}

运行实例2,输出结果如下所示:

 3.访问方法:

Method类的常用方法:

 实例3:创建一个Demo3类,并编写4个典型的方法。具体代码如下:

package com.study.reflect;public class Demo3 {static void staticMethod() {	System.out.println("执行staticMethod()方法");}public int publicMethod(int i) {	System.out.println("执行publicMethod()方法");	return i*10;}protected int protectedMethod(String s,int i) throws NumberFormatException{	System.out.println("执行protectedMethod()方法");	return Integer.valueOf(s)+i;}private String privateMethod(String...strings) {//里面参数是一个可变长度的数组,名为strings	System.out.println("执行privateMethod()方法");	StringBuffer stringBuffer = new StringBuffer();	for(int i=0;i

通过反射访问Demo3类中的所有方法,将各个方法的名称、入口参数类型、返回值类型等信息输出到控制台,并执行方法。代码如下:

package com.study.reflect;import java.lang.reflect.Method;public class Main3 {public static void main(String []args) {	Demo3 demo = new Demo3();	Class
demo3 = demo.getClass(); //获取所有方法 Method[] declaredMethods = demo3.getDeclaredMethods(); for(int i=0;i
[] parameterTypes =method.getParameterTypes(); for(int j=0;j
[] exceptionTypes = method.getExceptionTypes(); for (int j = 0; j < exceptionTypes.length; j++) { System.out.println(" "+exceptionTypes[j]); } boolean start = true; while(start) { //如果该方法的权限为private则不允许访问 try { start = false; if("staticMethod".equals(method.getName())) {//执行没有入口参数的方法 method.invoke(demo); } else if("publicMethod".equals(method.getName())) { method.invoke(demo, 12); //执行方法 } else if("protectedMethod".equals(method.getName())) { method.invoke(demo, "34",6); //执行方法 } else if("privateMethod".equals(method.getName())) { Object [] parameters = new Object[] {new String[] {"HELLO","WORLD!"}}; //定义二维数组 System.out.println("返回值为:"+method.invoke(demo,parameters )); } } catch (Exception e) { // TODO: handle exception e.printStackTrace(); System.out.println("在执行方法时抛出异常"+"下面执行setAccessible()方法:"); method.setAccessible(true); //设置为允许 start=true; } } System.out.println(); }}}

运行实例,输出结果:

 4.得到Class对象的3种方式

首先编写一个普通类Test类,代码如下:

package com.study.reflect;/** *一个普通类 * @author 哎呦不错呦 * */public class Test {public Test() {	//构造方法}void work() {	System.out.println("调用了work()方法");}void like() {	System.out.println("调用了like()方法");}}

然后在编写一个测试类ReflectTest,代码如下:

package com.study.reflect;/** * 测试类,得到Class对象的3种方式 * @author 哎呦不错呦 * */public class ReflectTest {public static void main(String []args) throws ClassNotFoundException {	//1.通过对象调用getClass()方法获取Class对象	Test test  =  new Test();	Class
A = test.getClass(); //2.通过直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高 // 因为任何一个类都有一个隐含的静态成员变量 class Class B = Test.class; //3.通过 Class 对象的 forName() 静态方法来获取,用的最多, // 但可能抛出 ClassNotFoundException 异常 Class C = Class.forName("com.study.reflect");}}

参考:java从入门到精通(第4版) 

转载地址:http://jzdqb.baihongyu.com/

你可能感兴趣的文章
debian下编译2.6.13.2内核的步骤及感受(转)
查看>>
预装正版的市场意义(转)
查看>>
创建小于16M XFree86迷你Linux系统(转)
查看>>
shell中常用的工具(转)
查看>>
使用MySQL内建复制功能来最佳化可用性(转)
查看>>
一个比较vista的vista主题for rf5.0fb(转)
查看>>
推荐一款 Linux 上比较漂亮的字体(转)
查看>>
在Linux中添加新的系统调用(转)
查看>>
Fedora Core 5.0 安装教程{下载}(转)
查看>>
把ACCESS的数据导入到Mysql中(转)
查看>>
shell里边子函数与主函数的实例(转)
查看>>
Linux中MAXIMA符号运算软件的简介(转)
查看>>
银行选择Linux 则无法回避高成本(转)
查看>>
上网聊天需要防范的几大威胁(转)
查看>>
[分享]后门清除完全篇(转)
查看>>
用php在linux下连接mssql2000(转)
查看>>
让你的Linux支持WEB修改密码(转)
查看>>
MYSQL的master/slave数据同步配置(转)
查看>>
一个完整的ftp远程批量shell(转)
查看>>
Vsftpd匿名无法上传,配置如下,帮忙找下原因,谢谢~!(转)
查看>>