java 反射api_Java学习笔记--反射API

反射API

1.反射API的介绍

通过反射API可以获取Java程序在运行时刻的内部结构。比如Java类中包含的构造方法、域和方法等元素,并可以与这些元素进行交换。

按照 一般地面向对象的设计思路,一个对象的内部状态都应该通过相应的方法来改变,而不是直接去修改属性的值。一般Java类中的属性设置获取方法的命名都遵循JavaBeans规范中的要求,即利用setXxx和getXxx这样的的方法声明,因此可以实现一个使用工具类来完成对任意对象的属性设置和获取的操作,只要设置和获取属性的方法满足JavaBeans规范。

使用反射API设置对象的属性值的示例

public class ReflectSetter{

public static void invokeSetter(Object obj,String field,Object value) throws NoSuchMethodException,InvocationTargetException,IllegalAccessException{

String methodName = "set" + field.substring(0,1).toUpperCase() + field.substring();

Class> clazz = obj.getClass();

Method method = clazz.getMethod(methodName,value.getClass());

method.invole(obj,value);

}

}

从根本上来说,反射API实际上定义了一种功能提供者和使用之间的松散契约。以方法调用为例,按照Java语言的一般用法,在调用方法的时候,在代码中首先需要一个对象的变量作为调用的接受者,再把方法的名称直接写在代码中。方法的名称不可能是变量。编译器会检查这个对象中是否确实有待调用的方法,如果没有就会出现编译错误。这种一般地做法,是提供者和使用者之间的一种紧密的契约,由编译器来保证其合法性。而是用反射API,两者的契约只需要建立在名称和参数类型这个层次上就足够了。方法名称可以是变量,参数值也可以动态生成。调用的合法性由开发人员自己保证。如果方法调用不是合法的,相关的异常会在运行时抛出。

反射API的一个重要的使用场合是要调用的方法或者要操作的域的名称按照某种规律变化的时候。一个典型的场景就是在Servlet中用HTTP请求值来填充领域对象。比如在用户注册的时候,包含在HTTP请求中的用户所填写的相关信息,需要被填充到程序中定义好的领域对象中。只需要利用Servlet提供的API遍历请求中的所有参数,然后用ReflectSetter类中invokeSetter方法设置领域对象中与参数名称相对应的属性的值即可。另外一个场景是在数据库操作中,从SQL查询结果集中创建并填充领域对象。数据库的别名和领域对象属性名称也存在着类似的对应关系。

反射API在为Java程序带来灵活性的同时,也产生了额外的性能代价。由于反射API的实现机制,对于相同的操作,比如调用同一个方法,用反射API来动态实现比直接在源代码中编写的方式大概慢到一到两个数量级。随之Java虚拟机实现的改进,反射API的性能已经有了非常大的提升。但是这种性能的差距是客观存在。因此,在某些对性能要求比较高的应用,要慎用反射API。

2.使用反射API获取构造方法

通过反射API可以获取到Java类中的构造方法。通过构造方法可以在运行动态地创建Java对象,而不只是通过new操作符来进行创建。在得到Class类的对象之后,可以通过其中的方法来获取构造方法。相关的方法有4个,其中getConstructors用来获取所有的public构造方法的列表,getConstructor则根据参数类型来获取public的构造方法。另外两个对应方法getDeclaredConstructors和getDeclaredConstructor的作用类似。只不过它们会获取类中真正声明的构造方法,而忽略从父类中继承下来的构造方法。得到了表示构造函数的java.lang.reflect.Constructor对象之后,就可以获取关于构造方法的更多信息,以及通过newInstance方法创建出的新的对象。

一般地构造方法的获取和使用没有什么特殊之处,需要特别说明的是对参数长度可变的构造方法和嵌套类(nested class)的构造方法的使用。

如果构造方法声明了长度可变的参数,在获取构造方法的时候,要使用对应的数组类型的Class对象。这是因为长度可变的参数实际上是通过数组来实现的。

使用反射API获取参数可变的构造方法

public class VarargsConstructor{

public VarargsConstructor(String... names) {}

}

public void useVarargsConstructor() throws Exception{

Constructor constructor = VarargsConstructo.class.getDeclaredConstructor(String[].class);

//为了避免方法调用时的歧义,这样编译器就知道把这个字符串数组作为一个可变长度的参数来传递

//在调用newInstance的时候,要把作为实际参数的字符串数组先转换成Object类型,

constructor.newInstance((Object) new String[] {"A","B","C"});

}

对嵌套类的构造方法的获取,需要区分静态和非静态两种情况,即是否在声明嵌套类的时候使用static关键词。静态的嵌套类并没有特别之处,按照一般的方式来使用即可。而对非静态类嵌套类来说,其特殊之处在于它的对象实例中都有一个隐含的对象引用,指向包含它的外部类对象,也正是这个隐含的对象引用的存在,使得非静态类嵌套类中的代码可以直接引用外部类中的包含的私有域和方法。因此,在获取非静态类的构造方式时候,类型参数列表的第一个值必须是外部类的Class对象。

使用反射API获取嵌套类的构造方法

public class ConstNestedClass{

static class StaticNestedClass{

public StaticNestedClass(String name){}

}

class NestedClass{

public NestedClass(int count){}

}

public void useNestedClassConstrcutor() throws Exception{

Constructor sncc = StaticNestedClass.class.getDeclaredConstructor(String.class);

sncc.newInstance("Alex");

Constructor ncc = NestedClass.class.getDeclaredConstructor(ConstructorUsage.class,int.class);

NestedClass nc = ncc.newInstance(this,3);

}

}

3.使用反射API获取域

通过反射API可以获取到类中公开的静态域和对象中的实例域。得到表示域的java.lang.reflect.Field类的对象之后,就可以获取和设置域的值。Class类中有4个方法用来获取域,分别是getFields、getField、getDeclaredFields和getDeclaredField,其含义与获取构造方法的4个方法类似。

使用反射API获取和使用静态域和实例域

public void useField() throws Exception{

Field fieldCount = FieldContainer.class.getDeclaredField("count");

fieldCount.set(null,3);

Field fieldName = FieldContainer.class.getDeclaredField("name");

fieldContainer fieldContainer = new FieldContainer();

fieldName.set(fieldContainer,"Arthur");

}

总的来说,对域的获取和设置都比较简单,但是只能对类中的公开域进行操作。私有域可以通过反射API的进行获取、操作(必须知晓字段名,且必须事先取消Java语言访问检查)。

4.使用反射API获取方法

最后一个可以通过反射API获取的元素是方法,这也是最常使用反射API的场景,即获取一个对象中的方法,并在运行时调用该方法。与之前提到的构造方法和域类似,Class类也有4个方法用来获取方法,分别是getMethods、getMethod、getDeclaredMethods和getDeclaredMethod。这4个方法的含义类似于获取构造方法和域的对应方法。在得到了表示方法的java.lang.reflect.Method类的对象之后,就可以查询该方法的详细信息,比如方法的参数和返回值的类型等。最重要的是可以通过invoke方法来传入实际参数并调用该方法。

使用反射API获取和使用公开和私有方法

public void useMethod() throws Exception{

MethodContainer mc = new MethodContainer();

Method publicMethod = MethodContainer.class.getDeclaredMethod("publicMethod");

publicMethod.invoke(mc);

Method privateMethod = MethodComtainer.class.getDeclareMethod("privateMethod");

privateMethod.setAccessible(true);

privateMethod.invoke(mc);

}

5.使用反射API操作数组

使用反射API对数组进行操作的方式不同于一般的Java对象,是通过专门的java.lang.reflect.Array这个实用工具类来实现的。Array类提供的方法包括创建数组和操作数组中的元素。

使用反射API操作数组

public void useArray(){

String name = (String[])Array.mewInstance(String.class,10);

names[0] = "Hello";

Array.set(names,1,"World");

String str = (String)Array.get(names,0);

int[][][] matrix1 = (int[][][])Array.newInstance(int.class,3,3,3);

martix1[0][0][0] = 1;

int[][][] martix2 = (int[][][])Array.newInstance(int[].class,3,4);

martix2[0][0] = new int[10];

martix2[0][1] = new int[3];

martix2[0][0][1] = 1;

}

6.访问权限与异常处理

使用反射API的一个重要好处是可以绕过Java语言中默认的访问控制权限。比如正正常的代码中,一个类的对象是不能访问在另外一个类中声明的私有方法的,但是通过反射API是可以做到这一点。Constructor、Field和Method都继承自java.lang.reflect.AccessibleObject,其中的方法setAccessible可以用来设置是否绕开默认的权限。

在利用invoke方法来调用方法时,如果方法本身抛了异常,invoke方法会抛出InvocationTargetException异常来表示这种情况。在捕获到InvocationTargetException异常的时候,通过InvocationTargetExeption异常的getCause方法可以获取到真正的异常信息,帮助进行调试。

在处理与反射相关的异常的时候,可以直接捕获java.lang.ReflectiveOperationException,这是所有与反射操作相关的异常类的父类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/336517.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++各类型有效范围

int -2147483648 ~ 2147483647 float 有6-7位有效数字 double 有15-16位有效数字

couchbase_具有Couchbase,Java EE和WildFly的CRUD Java应用程序

couchbaseCouchbase是一个开源的NoSQL文档数据库。 它允许访问,索引和查询JSON文档,同时利用集成的分布式缓存来实现高性能数据访问。 开发人员可以使用不同的语言(Java,Go,.NET,Node,PHP&…

java 对象的态_Java面向对象-------多态总结

1.多态:是同一个行为具有多个不同表现形式或形态的能力。多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:多态性是对象多种表现形式的体现。2.多态作用:1. 消除类型之间的耦合关系2. 可替换性3. 可扩充性4…

C++ 【随想录】(六)C++后端向JS前端转换

需要包含的头文件 #include"comutil.h" #include"<string> BSTR转string BSTR bstrText ::SysAllocString(L"Test"); string str _com_util::ConvertBSTRToString(bstrText); SysFreeString(bstrText); string转BSTR…

netbeans连接数据库_NetBeans Java EE技巧#1 –数据库中的实体类

netbeans连接数据库NetBeans IDE是开发各种应用程序的绝佳选择。 具体来说&#xff0c;我每天都使用它来开发和维护Java EE应用程序。 在过去的几个发行版中&#xff0c;不仅Java EE的生产力提高了&#xff0c;而且NetBeans IDE还减少了开发应用程序的时间……使Java EE和NetBe…

java spring eventbus_spring集成guava的event bus

Guava的event busguava&#xff0c; https://github.com/google/guava 是一个非常有名的Java类库&#xff0c;提供了很多在日常开发中常用的集合、函数接口等。此外&#xff0c;guava还提供了一个模块叫做event bus&#xff0c;生产者往event bus上投递消息&#xff0c;event b…

LeetCode 66 加一

原题链接 关键词 &#xff1a;数组 模拟法 解题思路: 此题为处理数组&#xff0c;数组特点 --数组下标 可以前后覆盖 数组元素可交换等。 此题分为三种情况 1.传入数为234形式 &#xff0c;加一后无进位。直接在最后一个数组1即可 2.传入数为239形式&#xff0c;即…

jboss fuse 教程_使用JBoss Fuse和OpenShift进行Cloud Native Camel骑行

jboss fuse 教程红帽公司最近发布了一个微服务集成工具包&#xff0c;用于在OpenShift v3的Docker和Kubernetes环境中运行我们的微服务。 为了帮助人们更好地理解这一点&#xff0c;我将Rider Auto应用程序迁移到一组微服务中&#xff0c;该应用程序已经存在了一段时间&#xf…

java streamhandler_java中的Lamdba表达式和Stream

基于JDK 1.81、循环&#xff1a;// 以前的循环方式for (String player : players) {System.out.print(player "; ");}// 使用 lambda 表达式以及函数操作(functional operation)players.forEach((player) -> System.out.print(player "; "));// 在 Ja…

LeetCode 217 存在重复元素

原题链接 关键词 数组 排序 重复 解题思路 1.先把数组进行排序&#xff0c;然后比较是否有相邻的两个数字相等 ,有返回TRUE 无则返回FALSE 2.需要注意的是nums.size()-1 因为是从下标0开始&#xff0c;所以要-1&#xff0c;否则会造成数组越界 class Solution { pu…

java 代码运行速度慢_C代码的运行速度总是比Java快,对吧? 错误!

java 代码运行速度慢因此&#xff0c;我们都知道&#xff0c;Java解释缓慢且C的编译和优化运行速度非常快。 您可能知道&#xff0c;情况截然不同。 TL; DR Java适用于星座图&#xff0c;它的速度更快&#xff0c;在JIT上可以执行内联&#xff0c;因为所有方法/功能都是可见的…

LeetCode 26.删除排序数组中的重复项

原题 标签 &#xff1a; 数组 重复元素 有序 双指针 快慢指针 解题思路: 1.判断数组是否为空&#xff0c;为空返回0 2.我们可以放置两个指针 &#xff0c;其中 k 是慢指针&#xff0c;用来存下所有不同的数&#xff0c;而 j 是快指针用来扫描整个数组。只要 nums[i] n…

javaone_JavaOne 2015 –又一年,又向前迈进了一步

javaoneJavaOne 2015 San Francisco于10月25日至29日举行。 我很自豪地说这是我第九个人参加JavaOne&#xff0c;第七个人是演讲者&#xff0c;第四个人是Oracle员工&#xff0c;第三个人是内容委员会成员&#xff0c;第二个人是项目负责人。 我认为对于JavaOne来说&#xff0c…

lnp和mysql分开安装_毕业设计之LNP+DISCUZ +分离的数据库操作

环境介绍&#xff1a;CentOS6.9最小化安装https://nginx.org/download/nginx-1.16.1.tar.gzhttps://www.php.net/distributions/php-7.3.14.tar.gzhttps://cdn.mysql.com//Downloads/MySQL-5.7/mysql-boost-5.7.29.tar.gznginxphp主机&#xff1a;192.168.111.141mysql主机&…

LeetCode 268 缺失数字

原题链接 标签&#xff1a; 数组 排序 解题思路: 1. 先进行排序 2. 0--N之间只有一个数没有出现&#xff0c;并且这是数组缺失的数字等于所在数组下标 3. 利用双指针&#xff0c;找到相差1的两个数组返回慢指针所指向值1&#xff0c;既可找到缺失的数字 …

java ee jms_在Java EE 7中自动配置JMS资源

java ee jmsJMS 2.0&#xff08;Java EE 7平台的一部分&#xff09;引入了许多不错的功能 。 其中之一是能够声明JMS资源以进行自动部署。 Java EE 7之前的版本 使用Resource注入连接工厂 使用Resource查找目标位置&#xff08;队列/主题&#xff09; 拉出Session对象&#…

python窗口居中_Python: tkinter窗口屏幕居中,设置窗口最大,最小尺寸实例

我就废话不多说了。大家直接看代码吧&#xff01;#!/usr/bin/env python#codingutf-8窗口屏幕居中,设置窗口最大,最小尺寸...版权所有 2014 yao_yu (http://blog.csdn.net/yao_yu_126)本代码以MIT许可协议发布2014-04-15 创建import tkinter as tkfrom tkinter import ttkdef g…

取得二进制最右面为1的数

取得二进制最右面为1的数 int rightOne eO & (~eO 1);

java中hotspot_Java 8中HotSpot选项的改进文档

java中hotspotOracle的HotSpot Java 8实现中引入的一些小但受欢迎的功能之一是在启动器的文档中添加了许多常见的HotSpot Java启动器 &#xff08; java &#xff09;选项/标志。 过去&#xff0c;甚至对某些相当常见的HotSpot JVM选项都感兴趣的开发人员不得不潜在地寻找多个不…

qchart折现图_Qt开发技术:QCharts(二)QCharts折线图介绍、Demo以及代码详解

若该文为原创文章&#xff0c;未经允许不得转载各位读者&#xff0c;知识无穷而人力有穷&#xff0c;要么改需求&#xff0c;要么找专业人士&#xff0c;要么自己研究敬请期待…红胖子&#xff0c;来也&#xff01;介绍了整体框架&#xff0c;开始动手码代码&#xff0c;按照顺…