前言

在上一篇文章中介绍了Java反射的基本概念以及基本应用,不熟悉的朋友可以点这里
本篇文章将重点介绍反射机制的深入应用

反射除了可以取得一个类的完整结构外,还可以调用类中的指定方法或指定属性,并且可以通过反射完成对数组的操作。

通过反射调用类中的方法

如果要使用反射调用类中的方法可以通过Method类完成,操作步骤如下:
(1) 通过Class类的getMethod(String name,Class….parameterTypes)方法取得一个Method的对象,并设置此方法操作时所需要的参数类型。
(2)之后可以使用invoke()进行调用,并向方法中传递要设置的参数。

下面通过一个具体的例子来为读者演示操作,此操作主要完成调用Person类中sayChina()方法的功能。(person类的定义在上一篇文章)

import java.lang.reflect.Method;
public class invokeSayChinaDemo{
public static void main(String[] args){
Class<?> c1=null;  //声明Class对象
try{c1=Class.forName("org.ljz.demo.Person"); //实例化Class对象
}catch(ClassNotFoundException e){
e.printStackTrace();
}
try{
Method met=c1.getMethod("sayChina");  //此方法没有参数
met.invoke(c1.newInstance());  //调用方法,必须传递对象实例
}catch(Exception e){
e.printStackTtace();}}
}      

程序运行结果:

作者: ljz, 国籍: China

以上程序通过Class类的getMethod()方法根据一个类中的方法名称取得Method对象,并通过invoke()调用指定的方法。在使用invoke()方法时必须传入一个类的实例化对象,因为在sayChina()方法上没有任何的参数,所以此处没有设置参数类型和参数内容,本程序的操作如图所示

下面再为读者演示一个向方法中传递参数的实例,以调用Person类中的sayHello(String name;int age)方法为例,此方法需要传递两个参数。

package org.ljz.demo.invokedemo;
import java.lang.reflect.Method;
public class invokeSayHelloDemo{
public static void main(String[] args){
class<?> c1=null;      //声明Class对象
try{
c1=Class.forName("org.ljz.demo.Person"); //实例化Class对象
}catch(ClassNotFoundException e){
e.printStackTrace();
}
try{
Method met=c1.getMethod("sayHello", String.class,int.class);  //此方法需要两个参数
String rv=null;    //接收方法的返回值
//调用方法,必须传递对象实例,同时传递两个参数值
rv=(String)met.invoke(c1.newInstance(),"ljz",23);
System.out.println(rv);
}catch(Exception e){
e.printStackTrace();}}
}     

程序运行结果:

ljz,你好!我今年23岁了!

以上程序中,因为sayHello()方法本身要接收两个参数,所以在使用getMethod()方法调用时除了要指定调用的方法名称外,也需要接收参数的类型,由于sayHello()方法调用完之后存在返回值,而且返回值的类型是String,所以使用了一个字符串接收方法返回的内容。

调用setter及getter方法

熟悉面向对象的读者就知道”类中的属性必须封装,封装之后的属性要通过setter及getter”方法设置和取得,那么在使用反射进行调用方法操作中,最重要的是调用类中的setter及getter方法,这一点在Java的开发中随处可见,下面为读者演示如何完成这样的功能。直接调用Person类中的setter及getter方法

代码如下:

package org.ljz.demo.invokedemo;
import java.lang.reflect.Method;
public class InvokeSetGetDemo{public static void main(String[] args){
Class<?> c1=null;   //声明Class对象
Object obj=null;   //声明一个对象
try{
c1=Class.forName("org.ljz.demo.Person");//实例化对象
}catch(ClassNotFountException e){
e.printStackTrace();
}
try{
obj=c1.newInstance();  //实例化操作对象
}catch(InstantiationException e){
e.printStackTrace();
}catch(IllegalAccessException e){
e.printStackTrace();
}
setter(obj,"name","ljz",String.class);   //调用setter方法
setter(obj,"age",23,int.class);  //调用setter方法
System.out.print("姓名:");
getter(obj,"name");    //调用getter方法
System.out.print("年龄:");
getter(obj,"age");   //调用getter方法
}
/***@param obj 操作的对象*@param att 操作的属性 *@param value 设置的值 *@param type 参数的类型*/ public static void setter(Object obj,String att,Object value, Class<?> type){  //调用setter方法
try{Method met=obj.getClass().getMethod("set"+initStr(att),type);//设置方法参数类型
met.invoke(obj,value);  //调用方法
}catch(Exception e){
e.printStackTrace();}
}public static void getter(Object obj,String att){ //调用getter方法
try{Method met=obj.getClass().getMethod("get" + initStr(att));  //此方法不需要参数
System.out.println(met.invoke(obj));  //接收方法的返回值
}catch(Exception e){
e.printStackTrace();}
}
public static String initStr(String old){  //单词首字母大写
String str=old.substring(0,1).toUpperCase()+old.substring(1);
return str;}
}

程序运行结果:

姓名: ljz
年龄:23

以上程序完成了调用类中setter及getter方法的功能,下面我们分步介绍本程序的思路

(1) 在设置方法名称时,本程序直接传入的是类中的属性名称,例如name或age。但是实际上方法名称是setName(0,getName(),setAge(),getAge(),这样,所有属性名称的首字母需要大写,所以为了解决这样的问题,单独设置了一个方法initStr(),通过此方法将字符串中的首字母大写。首字母大写之后在增加set及get字符串以找到相应的方法。

(2)调用setter()方法时,传入了实例化对象,要操作的属性名称(在方法中会将其首字母大写),要设置的参数内容以及具体的参数类型,这样做是为了满足getMethod() 和invoke()方法的使用要求。

(3)在调用getter()方法时,也同样传入同一个实例化对象,因为其本身不需要任何的接收参数,所以只传入属性名称(在方法中会将其首字母大写), 并在此方法中将内容打印输出。

以上程序是在反射调用方法时的重要应用,读者一定掌握其原理。因为在以后的开发中,许多系统会为开发者实现好以上的功能。

通过反射操作属性

在反射操作中虽然可以使用Method调用类中的setter及getter方法设置和取得属性,但是这样操作毕竟很麻烦,所以在反射机制中也可以直接通过Field类操作类中的属性,通过Field类提供的set()和get()方法就可以完成设置和取得属性内容的操作。但是在操作前首先需要注意的是,在类中的所有属性已经都设置成私有的访问权限,所以在使用set()或get()方法时首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置成可以被外部访问。

代码如下:

package org.ljz.demo.invokedemo;
import java.lang.reflect.Field;
public class invokeFieldDemo{
public static void main(String[] args) throws Exception{
Class<?> c1=null;    //声明Class对象
Object obj=bull;     //声明一个对象
c1=Class.forName("org.ljz.demo.Person");//实例化Class对象
obj=c1.newInstance();  //实例化对象
Field nameField=null;  //表示name属性
Field ageField=null;  //表示age属性
naneField=c1.getDeclaredField("name");//取得name属性
ageField=c1.getDeclaredField("age");// 取得age属性
nameField.set(obj,"ljz");   //设置name属性内容
ageField.setAccessible(true); //将age属性设置成可以被外部访问
ageField.set(obj,23); //设置age属性内容
System.out.println("姓名:"+nameField.get(obj));
System.out.println("年龄:"+ageField.get(obj));}
}

程序运行结果:

姓名:ljz
年龄:23

从以上代码不难看出,明显比之前使用setter或getter方法操作属性的代码更加简单,方便。

通过反射操作数组

反射机制不仅只能用在类上,还可以应用在任意的引用数据类型的数据上,当然,这也就包含了数组,即可以使用反射操作数组。可以通过Class类的以下方法取得一个数组的Class对象。

public Class<?> getComponentType()

在反射操作包java.lang.reflect中使用Array类表示一个数组,可以通过此类取得数组长度,取得数组内容的操作。Array类的常用方法如下所示:

下面通过两个范例让读者了解以上方法的使用

1. 取得数组信息并修改数组内容

package org.ljz.arraydemo;
import java.lang.reflect.Array;
public class ClassArrayDemo{
public static void main(String[] args)throws Exception{
int temp[]={1,2,3}; //声明一个整形数组
Class<?> c=temp.getClass().getComponentType();//取得数组的Class对象
System.out.println("类型" +c.getNmae()); //取得数组类型的名称
System.out.println("长度"+Array.getLength(temp));//得到数组的长度
System.out.println("第一个内容:"+Array.get(temp,0));//得到第一个内容
Array.set(temp,0,6);   //修改第一个内容
System.out.println("第一个内容"+Array.get(temp,0));//得到第一个内容}} 

程序运行结果:

类型: int
长度:3
第一个内容:1
第一个内容: 6

以上程序中通过Array类取得了数组的相关信息,并通过Array类中的set()方法修改了数组中的元素内容。

在应用中还可以通过Array类根据自己已有的数组类型来开辟新的数组对象,下面我们就来使用Array完成一个可以修改已有数组大小的功能。

2.修改数组的大小

package org.ljz.arraydemo
import java.lang.reflect.Array;public class ChangeArrayDemo{
public static void main(String[] args)throws Exception{
int temp[]={1,2,3};
int newTemp[]=(int[])arrayInc(temp,5);//扩大数组的长度
String t[]={"zhangsan","lisi","wangwu"};//声明一个字符串数组
String nt[]=(String[])arrayInc(t,6);//扩大数组长度
print(nt);//打印数组信息
}public static Object arrayinc(Object obj,int len){ //修改数组长度
Class<?> c=obj.getClass(); //通过数组得到Class对象
Class<?> arr=c.getComponentType();//得到数组的Class对象
Object newO=Array.newInstance(arr,len);//重新开辟新的数组空间
int co=Array.getLength(obj);//取得数组长度
System.arraycopy(obj,0,newO,0,co)//复制数组内容
return newO;
}public static void print(Object obj){ //输出数组
Class<?> c=obj.getClass();  //通过数组得到Class对象
if(!c.isArray()){//判断是否是数组
return;
}
Class<?> arr=c.getComponentType();//取得数组的Class
System.out.println(arr.getName()+"数组的长度:"+Array.getLength(obj));//输出数组的信息
for(int i=0;i<Array.getLength(obj);i++){  //循环输出
System.out.print(Array.get(obj,i)+",");//通过Array输出}}}  

程序运行结果:

int数组的长度是:5
1,2,3,4,5
java.lang.String数组的长度是6
zhangsan ,lisi, wangwu, null, null, null

后续

下一篇我将介绍动态代理以及反射应用到工厂设计模式的相关应用,感兴趣的朋友可以关注一下!

Java反射机制的深入应用相关推荐

  1. 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换

    作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...

  2. Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法...

    Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法 www.MyException.Cn   发布于:2012-09-15 ...

  3. Java反射机制分析指南

    一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反 ...

  4. 反射 字段_详解面试中常考的 Java 反射机制

    反射(Reflection) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性和方法. 反射是一项高级 ...

  5. 【java】java反射机制,动态获取对象的属性和对应的参数值,并属性按照字典序排序,Field.setAccessible()方法的说明【可用于微信支付 签名生成】...

    方法1:通过get()方法获取属性值 package com.sxd.test.controller;public class FirstCa{private Integer num;private ...

  6. java基础-java反射机制

    2019独角兽企业重金招聘Python工程师标准>>> 引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓"登高必自卑,涉远必自迩" ...

  7. 利用java反射机制进行对象操作

    我们经常使用COMMONS-BEANUTILS包来进行bean的操作,例如从map到bean获从bean到map的映射,那么实现的原理是什么呢,下面举个简单的操作的例子:首先,我建立一个bean pu ...

  8. java反射机制知识_Java反射机制讲解,程序员必须掌握的知识点

    关注程序员7歌,一起用技术改变世界 大家好,我是程序员7歌,今天我为大家讲解Java的反射机制. 首先我们来看看反射的概念: Java反射说的就是在程序运行中,任何一个类,我们都可以知道这个类的方法和 ...

  9. java继承 映射_hibernate继承关系映射和java反射机制的运用

    转:http://blog.csdn.net/derpvailzhangfan/article/details/1957946 ,感谢博主分享 Notes:hibernate元数据的运用:uuid的概 ...

  10. java初反射_初始 java 反射机制 (一)

    反射机制详解 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为j ...

最新文章

  1. mac微软雅黑字体_【字体字重】常见设计稿字体对应字重
  2. linux目录结构   各个目录文件作用
  3. Android 中shape的使用(圆角矩形)
  4. java string replace 重载_关于Java:如何使用replace(char,char)替换字符b的所有实例为空...
  5. python列表生成时 if_Python列表生成式
  6. OpenCV 发起 Spatial AI挑战赛
  7. Bookmarklet
  8. 解决pip无法安装bayes-opt报错:ERROR: Could not find a version that satisfies the requirement bayes-opt
  9. 从门户网站看内容传播的开放式革命
  10. [18/11/22] 将点分十进制的IP地址化成二进制输出
  11. 假如有一门叫做 Ctrump 的编程语言...
  12. OpenGL和OpenCV的区别
  13. iOS UI-团购案例(通过xib文件自定义UITableViewCell)
  14. 程序转换实验程序流程图_智能化实验室 | # 自动智能化实验室的5大系统 #
  15. 菜鸟的IT道路ing (六)
  16. 扫描仪怎样装无线网络服务器,怎么设置打印机IP地址和安装扫描仪。
  17. r语言和python爬虫谁厉害_r语言和python有必要都学吗
  18. html5制作新年祝福,新年祝福视频制作教程
  19. 关于电子发票打印报销最优美的姿势——发票大师网页版
  20. 长江大学计算机科学学院德贵奖学金,关于做好2019年各类奖学金评选的通知

热门文章

  1. C# 之 GUID格式化
  2. VS发生生成错误,但错误列表无错误提示。
  3. python爬取qq电话_用Python爬取整个学院MM的电话和QQ,爬虫这也太牛了!
  4. 虹科前沿丨AR在医疗领域的应用如何?权威科学家告诉你!
  5. spring的依赖注入方式
  6. 使用SAX解析XML文件出现中文乱码问题(dom4j)
  7. python爬取链家房价消息_Python的scrapy之爬取链家网房价信息并保存到本地
  8. 快鹿集团被罚15亿 黄家骝及韦炎平以集资诈骗罪被判无期
  9. promql中使用rate/irate等函数__name__丢失处理
  10. javaEE Design Patter(1)初步了解23种常用设计模式