漫反射 高光反射_如何有效地使用反射

漫反射 高光反射

本文是我们名为“ 高级Java ”的学院课程的一部分。

本课程旨在帮助您最有效地使用Java。 它讨论了高级主题,包括对象创建,并发,序列化,反射等。 它将指导您完成Java掌握的旅程! 在这里查看 !

目录

1.简介 2.反射API 3.访问泛型类型参数 4.反射API和可见性 5.反射API陷阱 6.方法句柄 7.方法参数名称 8.接下来 9.下载源代码

1.简介

在本教程的这一部分中,我们将简要介绍一个非常有趣的主题,即反射反射是程序在运行时检查或自检的能力。 反射是一项非常有用且功能强大的功能,它可以极大地扩展程序的功能,以在执行过程中执行其自己的检查,修改或转换,而无需一行代码更改。 并非每种编程语言实现都支持此功能,但是幸运的是Java自一开始就采用了此功能。

2.反射API

反射API是Java标准库的一部分,它提供了一种在运行时探索内部类详细信息,动态创建新类实例(无需显式使用new运算符),动态调用方法,自省注释(已添加注释)的方法。在教程的第5部分“ 如何以及何时使用Enums和Annotations”中进行了介绍 ,以及更多其他内容。 它使Java开发人员可以自由编写代码,这些代码可以在运行时自行调整,验证,执行甚至修改自己。

Reflection API以非常直观的方式设计,并托管在java.lang.reflect包下。 它的结构严格遵循Java语言概念,并具有表示类(包括通用版本),方法,字段(成员),构造函数,接口,参数和注释的所有元素。 Reflection API的入口点是Class< ? > Class< ? >类。 例如,列出String类的所有公共方法的最简单方法是使用getMethods()方法调用:

final Method[] methods = String.class.getMethods();
for( final Method method: methods ) {System.out.println( method.getName() );
}

按照相同的原则,我们可以使用getFields()方法调用列出String类的所有公共字段,例如:

final Field[] fields = String.class.getFields();
for( final Field field: fields ) {System.out.println( field.getName() );
}

继续使用反射类对String类进行实验,让我们尝试创建一个新实例,并在其上调用length()方法,所有这些仅通过使用反射API即可

final Constructor< String > constructor = String.class.getConstructor( String.class );
final String str = constructor.newInstance( "sample string" );
final Method method = String.class.getMethod( "length" );
final int length = ( int )method.invoke( str );
// The length of the string is 13 characters

可能最需要反射的用例围绕注释处理。 注释本身(不包括Java标准库中的注释)对代码没有任何影响。 但是,Java应用程序可以使用反射在运行时检查它们感兴趣的不同Java元素上存在的注释,并根据注释及其属性应用某些逻辑。 例如,让我们看一下自省的方式是否存在于类定义中:

@Retention( RetentionPolicy.RUNTIME )
@Target( ElementType.TYPE )
public @interface ExampleAnnotation {// Some attributes here
}@ExampleAnnotation
public class ExampleClass {// Some getter and setters here
}

使用反射API ,可以使用getAnnotation()方法调用轻松完成。 返回的非null值表示存在注释,例如:

final ExampleAnnotation annotation =ExampleClass.class.getAnnotation( ExampleAnnotation.class );if( annotation != null ) {// Some implementation here
}

如今,大多数Java API都包含注释,以方便开发人员使用和集成它们。 非常流行的Java规范的最新版本,例如RESTful Web服务的Java API ( https://jcp.org/en/jsr/detail?id=339 ), Bean验证 ( https://jcp.org/en/jsr / detail?id = 349 ), Java临时缓存API ( https://jcp.org/en/jsr/detail?id=107 ), Java消息服务 ( https://jcp.org/en/jsr/detail? id = 343 ), Java Persistence ( https://jcp.org/en/jsr/detail?id=338 )以及许多其他构建在注释之上,它们的实现通常大量使用Reflection API来收集有关正在运行的应用程序。

3.访问泛型类型参数

自从引入泛型(本教程的第4部分“ 如何和何时使用泛型”介绍了泛型 )以来, Reflection API已得到扩展,以支持对泛型类型的自省。 在许多不同的应用程序中经常弹出的用例是弄清楚用其声明了特定类,方法或其他元素的通用参数的类型。 让我们看一下示例类声明:

public class ParameterizedTypeExample {private List< String > strings;public List< String > getStrings() {return strings;}
}

现在,在使用Reflection检查类时,很容易知道将strings属性声明为具有String类型参数的泛型类型List 。 下面的代码段说明了如何实现:

final Type type = ParameterizedTypeExample.class.getDeclaredField( "strings" ).getGenericType();if( type instanceof ParameterizedType ) {final ParameterizedType parameterizedType = ( ParameterizedType )type;for( final Type typeArgument: parameterizedType.getActualTypeArguments() ) {System.out.println( typeArgument );}
}

以下通用类型参数将被打印在控制台上:

class java.lang.String

4.反射API和可见性

在本教程的第1部分“ 如何创建和销毁对象”中 ,我们第一次遇到了Java语言支持的可访问性和可见性规则。 可能令人惊讶,但是反射API能够以某种方式修改给定类成员的可见性规则。

让我们看一下带有单个私有字段名称的类的以下示例。 提供了此字段的getter,但没有提供setter,这是有意为之。

public static class PrivateFields {private String name;public String getName() {return name;}
}

显然,对于任何Java开发人员而言,显然都无法使用Java语言语法构造来设置name字段,因为该类无法提供实现此目的的方法。 关于救援的反射API ,让我们看看如何通过更改字段的可见性和可访问范围来完成。

final PrivateFields instance = new PrivateFields();
final Field field = PrivateFields.class.getDeclaredField( "name" );
field.setAccessible( true );
field.set( instance, "sample name" );
System.out.println( instance.getName() );

以下输出将打印在控制台上:

sample name

请注意,如果没有field.setAccessible( true )调用,则会在运行时引发异常,表明无法访问带有修饰符private的类的成员。

反射API的此功能经常由测试支架或依赖项注入框架使用,以便访问内部(或不可暴露)的实现细节。 除非您别无选择,否则请尝试避免在应用程序中使用它。

5.反射API陷阱

另外,请注意,即使反射API非常强大,也有一些陷阱。 首先,它是安全权限的主题,可能并非在您的代码正在其上运行的所有环境中都可用。 其次,它可能会对您的应用程序性能产生影响。 从执行前景来看,对反射API的调用非常昂贵。

最后, 反射API不能提供足够的类型安全保证,迫使开发人员在大多数地方使用Object实例,并且在转换构造函数/方法参数或方法返回值方面受到很大限制。

自Java 7发行以来,有一些有用的功能可以提供更快,另一种方法来访问某些功能,这些功能以前只能通过反射调用来使用。 下一节将向您介绍它们。

6.方法句柄

Java 7版本向JVM和Java标准库(方法句柄)引入了一个非常重要的新功能。 方法句柄是对基础方法,构造函数或字段(或类似的低级操作)的类型化,直接可执行的引用,具有自变量或返回值的可选转换。 在许多方面,它们是使用Reflection API执行的方法调用的更好替代方法。 让我们看一下使用方法句柄动态调用String类上的方法length()的代码片段。

final MethodHandles.Lookup lookup = MethodHandles.lookup();
final MethodType methodType = MethodType.methodType( int.class );
final MethodHandle methodHandle =lookup.findVirtual( String.class, "length", methodType );
final int length = ( int )methodHandle.invokeExact( "sample string" );
// The length of the string is 13 characters

上面的示例不是很复杂,只是概述了方法处理能力的基本概念。 请将其与使用“ 反射API ”部分中的“ 反射API”的相同实现进行比较。 但是,它看起来确实有些冗长,但是从性能和类型安全性角度来看,预期的方法句柄是更好的选择。

方法句柄是非常强​​大的工具,它们为在JVM平台上有效实现动态(和脚本)语言奠定了必要的基础。 在本教程的第12部分动态语言支持中 ,我们将介绍其中的几种语言。

7.方法参数名称

Java开发人员多年来面临的一个众所周知的问题是,方法参数名称没有在运行时保留,而是被彻底清除。 几个社区项目,例如Paranamer ( https://github.com/paul-hammant/paranamer ),试图通过向生成的字节码中注入一些其他元数据来解决此问题。 幸运的是,Java 8通过引入新的编译器参数–parameters改变了这一点,该–parameters将确切的方法参数名称注入字节码中。 让我们看一下以下方法:

public static void performAction( final String action, final Runnable callback ) {// Some implementation here
}

在下一步中,让我们使用Reflection API检查该方法的方法参数名称,并确保保留它们:

final Method method = MethodParameterNamesExample.class.getDeclaredMethod( "performAction", String.class, Runnable.class );
Arrays.stream( method.getParameters() ).forEach( p -> System.out.println( p.getName() ) );

指定了-parameters编译器选项后,以下参数名称将打印在控制台上:

action
callback

对于许多Java库和框架的开发人员来说,这一期待已久的功能确实使他们大为欣慰。 从现在开始,仅使用纯Java Reflection API即可提取更多有用的元数据,而无需引入任何其他变通方法(或黑客手段)。

8.接下来

在本教程的这一部分中,我们介绍了反射API ,它是检查代码,从代码中提取有用的元数据甚至进行修改的方法。 尽管存在所有缺点,但反射API如今已在大多数(如果不是全部)Java应用程序中得到了广泛使用。 在本教程的下一部分中,我们将讨论Java中的脚本和动态语言支持。

9.下载源代码

这是高级Java课程的第11部分“ 反射” 课程 。 您可以在此处下载源代码: advanced-java-part-11

翻译自: https://www.javacodegeeks.com/2015/09/how-to-use-reflection-effectively.html

漫反射 高光反射

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

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

相关文章

python编译helloworld_python3学习笔记--001--python HelloWorld

python默认使用UTF-8编码 一个python3版本的HelloWorld代码如下&#xff1a; #!/usr/bin/env python print (Hello World!) 如果此python脚本文件名为&#xff1a;hello.py&#xff0c;则运行此脚本文件的方法有两种&#xff1a; 1、python hello.py [laolanglocalhost python]…

漫谈 C++:良好的编程习惯与编程要点

点击蓝字关注我们以良好的方式编写C class假设现在我们要实现一个复数类complex&#xff0c;在类的实现过程中探索良好的编程习惯。① Header(头文件)中的防卫式声明complex.h: # ifndef __COMPLEX__ # define __COMPLEX__ class complex {} # endif防止头文件的内容被多次包含…

Python3只出现一次数字

Python3只出现一次数字原题 https://leetcode-cn.com/problems/single-number/ 题目&#xff1a; 给定一个非空整数数组&#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 说明&#xff1a; 你的算法应该具有线性时…

junit测试找不到数据库_将数据库日志添加到JUnit3

junit测试找不到数据库在过去的十年中&#xff0c;我们已经编写了成千上万的JUnit3测试&#xff0c;现在正尝试将结果合并到数据库中&#xff0c;而不是分散的日志文件中。 事实证明&#xff0c;扩展TestCase类非常容易做到这一点。 注意&#xff1a;这种方法并不直接适用于JUn…

python float 精度_浅谈Python里面小数点精度的控制

要求较小的精度 round()内置方法 这个是使用最多的&#xff0c;刚看了round()的使用解释&#xff0c;也不是很容易懂。round()不是简单的四舍五入的处理方式。 For the built-in types supporting round(), values are rounded to the closest multiple of 10 to the power min…

【C语言】指针进阶第二站:指针数组!

点击蓝字关注我们指针数组数组是一种类型的数的集合整型数组的元素都是int类型指针数组的元素都是指针变量int* arr1[10];//整型指针的数组char*arr2[10];//一级字符指针的数组char** arr3[5];//二级字符指针的数组参考这一份示意图示例1:定义多个字符指针在上一站的字符指针里…

Python3不用str自带lower转换位小写字母

Python3不用str自带lower转换位小写字母原题 https://leetcode-cn.com/problems/to-lower-case/ 题目&#xff1a; 不准用字符串自带的lower() API&#xff01; 实现函数 ToLowerCase()&#xff0c;该函数接收一个字符串参数 str&#xff0c;并将该字符串中的大写字母转换成小…

php 命令执行crud_使用活动记录执行CRUD

php 命令执行crud本文是我们学院课程“ jOOQ –类型安全数据库查询”的一部分 。 在SQL和特定关系数据库很重要的Java应用程序中&#xff0c;jOOQ是一个不错的选择。 当JPA / Hibernate抽象过多而JDBC过于抽象时&#xff0c;这是一种替代方法。 它显示了一种现代的领域特定语言…

python所有的父类_object代表所有类的父类吗??

作者&#xff1a;邹冲 链接&#xff1a;https://www.zhihu.com/question/19754936/answer/202650790 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 写东西的时候刚好遇到这个问题&#xff0c;回答一波…… 继承 obje…

C语言初学者常见错误 | 总结22点

点击蓝字关注我们正文一.语言使用错误在打代码的过程中&#xff0c;经常需要在中文与英文中进行转换&#xff0c;因此常出现一些符号一不小心就用错&#xff0c;用成中文。例如&#xff1a;“&#xff1b;”中文中的分号占用了两个字节&#xff0c;而英文中“;”分号只占用一个…

Python3实现队列

Python3实现队列class MyQueue:def __init__(self):self.__arr []def push(self, x: int) -> None:self.__arr.append(x)def pop(self) -> int:return self.__arr.pop(0)def peek(self) -> int:return self.__arr[0]def empty(self) -> bool:return len(self.__ar…

nginx配置vue项目500_一个Nginx部署多个vue前端项目总结

摘要&#xff1a;近来接手了一个二次开发的前后端分离模式的项目&#xff0c;其中在前端项目的部署上需要让2个前端项目都部署到一个IP地址和端口下&#xff0c;那么我们这里就要用到Nginx了&#xff0c;接下来我们看看如何在一个Nginx下部署2个前端项目的编译打包2个前端项目执…

vaadin_Vaadin和DukeScript中的Hello World

vaadin从表面上看 &#xff0c; Vaadin和GWT通常与DukeScript有很多共同点。 两者都致力于为Java开发人员提供面向浏览器的解决方案&#xff0c;并且由于其对Maven的原生支持&#xff0c;因此与IDE集成良好。 但是&#xff0c;这些方面实际上是它们共有的全部。 从编程模型到框…

【C语言】指针进阶第三站,数组指针!

点击蓝字关注我们数组指针整型指针&#xff1a;指向整型的指针字符指针&#xff1a;指向字符的指针数组指针&#xff1a;指向数组的指针基本概念下面哪个是数组指针呢&#xff1f;指针数组和数组指针的概念很容易混淆&#xff0c;一定要分清楚哦&#xff01;int *p1[10]; int (…

Python3判断是否为回文数

Python3判断是否为回文数原题 https://leetcode-cn.com/problems/palindrome-number/ 题目&#xff1a; 不允许用str的方法&#xff01; 判断一个整数是否是回文数。回文数是指正序&#xff08;从左向右&#xff09;和倒序&#xff08;从右向左&#xff09;读都是一样的整数。…

lambda 序列化_如何以及为什么要序列化Lambda

lambda 序列化总览 lambda序列化在许多用例中很有用&#xff0c;例如持久配置或作为远程资源的访客模式 。 远程访客 例如&#xff0c;因此我想访问远程Map上的资源&#xff0c;可以使用get / put&#xff0c;但是说我只想从Map的值中返回一个字段&#xff0c;我可以将lambda作…

python进行数据查询_如何进行python数据库查询?(实例解析)

在这篇文章之中我们来了解一下关于python数据库的相关知识&#xff0c;有些朋友可能是刚刚接触到python这一编程语言&#xff0c;对这一方面不是特别的了解&#xff0c;在接下来这篇文章将会来带大家来了解关于python查询数据库中数据的相关知识。 数据库的查询操作 Python查询…

【C语言】指针进阶第四站:数组/指针的传参问题!

点击蓝字关注我们朋友们&#xff0c;到站啦&#xff01;指针进阶第四站&#xff1a;传参问题0.引例自定义函数里形参的类型&#xff0c;要和函数调用中传过去的实参类型相对应test函数里的是int类型&#xff0c;我们传过去的参数a也是int类型void test(int n) {} int main() {i…

python做自动化控制postman_python自动化测试入门篇-postman

接口测试基础-postman 常用的接口有两种&#xff1a;webservice接口和http api接口。 Webservice接口是走soap协议通过http传输&#xff0c;请求报文和返回报文都是xml格式。 http api接口是走http协议&#xff0c;通过路径来区分调用的方法&#xff0c;请求报文都是key-value形…

Python3实现红黑树[上篇]

Python3实现红黑树[上篇]由于时间有限&#xff0c;这次只写了红黑树添加节点&#xff0c;关于节点的删除放在下一讲 https://blog.csdn.net/qq_18138105/article/details/105324025。 关于红黑树的介绍&#xff0c;来由&#xff0c;性质和定义&#xff0c;可以看这篇文章&…