反射是一种内置机制,用于在执行时对Java程序进行内省。它可以用来检查、修改和转换Java程序,而不会影响现有代码。这个强大的特性可以用来扩展程序的功能,在运行时检查类或对象的内部结构。本文试图探究其中的一些错综复杂之处,并对其有效使用略作一瞥。

反射API

反射API是标准java api库的一部分。它使我们不仅可以探索类的内在本质,而且可以在运行时不使用显式的new运算符来实例化一个类。使用这个API,执行代码可以向对象请求它的类,研究它的方法、它所接受的参数、返回类型和构造函数。这是动态完成的;编译器不知道运行时加载的类。

API托管在java.lang.reflect.package。从结构上讲,api与Java语言没有区别,它包含所有的语言元素,如类、方法、字段、构造函数、接口、注释等等。

名为Class>是反射API中最重要的类,是内省和反射机制的基础。它是一个final类;因此,它不能被扩展。

public final class Class extends Object implements

Serializable, GenericDeclaration, Type, AnnotatedElement

加载到Java运行时的任何类都会创建一个类的实例,该实例表示加载的类或接口。众所周知,Object类是Java中所有类的父类;它提供了一个名为getClass()的方法。我们可以使用此方法获得实例化类对象的引用。或者,类中定义的静态forName()方法也可用于加载未知类并获取其类对象的引用。类类提供一组方法来获取类名、它的方法、修饰符、构造函数等等。例如:

类的getName()方法可用于获取它所表示的类的完全限定名。

getModifiers()方法返回Java语言修饰符;

getConstructors()方法返回一个数组,其中包含反映该类对象所表示类的所有公共构造函数的构造函数对象。

方法的作用是:返回一个Field对象数组,该数组反映由该类对象表示的类或接口声明的所有字段,依此类推。

例如,我们可以很容易地列出Object类的所有public方法,如下所示:

Method[] methods = Object.class.getMethods();

for(Method method:methods){

System.out.println(method.toString());

}

类似地,我们可以检索Integer类的字段信息。

Field[] fields = Integer.class.getFields();

for(Field field:fields){

System.out.println(field.toString());

}

newInstance()方法用于实例化当前类所表示的对象。如果类或无参数构造函数不可访问,则抛出IllegalAccessException。通常,如果类表示抽象类、接口、数组类、基元类型、Void,或者它没有默认的或由程序员提供的无参数构造函数,它会抛出另一个异常,称为InstantiationException。

try {

Constructor constructor =

String.class.getConstructor(String.class);

String strObj = constructor.newInstance("Hello");

Method method = String.class.getMethod("length");

int len = (int)method.invoke(strObj);

System.out.println(len);

}catch (NoSuchMethodException | IllegalAccessException

| InvocationTargetException | InstantiationException ex){

ex.printStackTrace();

}

注解反射

Java应用程序可以使用反射API对注解进行反射。这些api有助于在运行时检查代码中存在的注释元素,并根据需要修改它们。例如,我们可以使用API来发现和反思类定义中声明的特定注释,如下所示:

package com.mano.examples;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

public@interface DemoAnnotation {

// ...

}

package com.mano.examples;

@DemoAnnotation

public class DemoClass {

// ...

}

我们可以通过下面的方法来确定注释@DemoAnnotation是否应用于DemoClass。

DemoAnnotation annotation = DemoClass.class

.getAnnotation(DemoAnnotation.class);

if(annotation==null){

System.out.println("DemoAnnotation is not applied");

} else {

System.out.println("DemoAnnotation is applied");

}

因为Java中注释的使用非常丰富,比如用于restfulweb服务的java api、Java持久化、JMS、Bean验证等等。我们可以有效地使用反射API来获取有关运行应用程序中使用的注释的信息。

泛型反射

反射API还支持泛型类型的内省。通过使用这些api,我们可以发现类或任何其他元素使用的泛型参数的类型。假设有一个类,如下所示:

package com.mano.examples;

public class Invoice implements Payable {

private String itemNumber;

private String itemName;

private int quantity;

private double unitPrice;

public Invoice(String itemName, int quantity,

double unitPrice) {

// ...

}

public int getQuantity() {

// ...

return quantity;

}

public double getUntPrice() {

// ...

return unitPrice;

}

@Override

public double calcAmount() {

return getQuantity()*getUntPrice();

}

}

package com.mano.examples;

import java.util.List;

public class DemoClass {

private List invoices;

public List getInvoices(){

return invoices;

}

}

我们可以考虑使用Invoice type参数声明为泛型类型List的Invoice类的属性。

try {

Type type = DemoClass.class

.getDeclaredField("invoices").getGenericType();

if(type instanceof ParameterizedType){

ParameterizedType parameterizedType =

(ParameterizedType) type;

for(Type t:parameterizedType.getActualTypeArguments()){

System.out.println(t);

}

}

}catch (NoSuchFieldException ex){

ex.printStackTrace();

}

使用反射修改应用程序代码

有了反射API,我们可以以某种方式修改代码。例如,让我们声明一个带有私有字段和一个公共getter类的类,如下所示:

package com.mano.examples;

public class SampleClass {

private String greetings;

public String getGreetings(){

return greetings;

}

}

请注意,该类只有getter方法,而没有setter方法来设置字符串字段问候语。这意味着我们无法在运行时设置任何问候语的值。但是,有趣的是,我们可以使用反射API,更改字段的可见性和可访问性范围,并将字段设置为所需的值,如下所示。

Try {

SampleClass sampleClass = new SampleClass();

Field field = SampleClass.class

.getDeclaredField("greetings");

field.setAccessible(true);

field.set(sampleClass,"Hello, everybody. I am all set.");

System.out.println(sampleClass.getGreetings());

}catch(NoSuchFieldException | IllegalAccessException ex){

ex.printStackTrace();

}

注意字段集可访问field.setAccessible(true)必须设置;否则,我们无法访问声明为私有成员的任何类成员。这个特性对于实现依赖注入框架特别有用。

了解getMethods()和getConstructors()方法都会抛出SecurityException。这意味着SecurityManager在幕后使用安全策略来确定不安全或敏感的操作。例如,当调用checkMemberAccess(this, Member.PUBLIC)方法时,它拒绝访问类中的方法和构造函数,这表明具有公共访问权限的方法或构造函数不能通过动态发现调用。当在当前类的类装入器的类层次结构中找不到调用方的类装入器时,也会引发SecurityException。这实际上意味着加载的类不是它所属包的一部分。这会引发安全漏洞,并拒绝对已加载类的包权限。

反射API的缺陷

不管怎样,反射api都有安全问题,并且可能不适用于应用程序运行的每个编程环境。它还可能对应用程序的性能产生负面影响。从这个意义上说,API是重而昂贵的。不能保证型号安全。程序员在大多数情况下被迫使用对象实例。此外,它在转换方法或构造函数参数和方法返回值方面也非常有限。

结论

本文只是简单介绍了反射在Java应用程序中的适用性。反射并不是每种编程语言中都存在的常见现象。Java支持这个特性,并且从版本1开始就是它的一部分。除了许多框架之外,还有许多库广泛使用反射api。可能是我们在任何现代java IDE中最常见的应用程序,它在输入Java代码时主动提供类成员的详细信息。它功能强大,是Java最重要的特性之一。

如何优化java反射,如何有效地使用Java反射相关推荐

  1. java反射设置属性值_Java反射如何有效的修改final属性值详解

    前言 以前写过一篇 Java 反射修改 final 属性值,本文将在这里重新温习一下Java反射如何有效的修改final属性值,下面话不多说了,来一起看看详细的介绍: 假设有个类 class Pers ...

  2. 深入理解Java类型信息(Class对象)与反射机制

    关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java并发之synchronize ...

  3. java反射的编译过程_Java反射机制小结和实际操作

    一.什么是反射 1.编译和运行 在了解什么是Java反射机制前,先聊聊Java的编译和运行. 还记得第一次使用记事本编写第一个Java程序的场景吗?通过命令窗口,使用javac命令编译一个.java文 ...

  4. 鲸鱼优化算法_盘点 35 个 Java 代码优化细节

    代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是, ...

  5. 【JAVA SE】第十七章 反射、注解与Spring事务底层原理

    第十七章 反射.注解与Spring事务底层原理 文章目录 第十七章 反射.注解与Spring事务底层原理 一.反射 1.简介 2.意义 3.缺点 4.应用场景 5.反射技术的使用 二.注解 1.概念 ...

  6. java 反射为何耗性能_Java反射的性能成本

    在Java中,普遍认为java.reflect API的性能代价很高.旧的Java版本有巨大的性能开销,而新版本似乎使其处于可接受的范围内.但"可接受"到底是什么意思呢? 这是我在 ...

  7. 【译】Java编程动态性,第 2部分: 反射简介

    概要: 反射使您的程序代码在运行时能够访问加载到JVM中类的内部信息并和加载的特定类协作,而不是在源代码中.这使反射成为构建灵活性应用的强大工具.但需注意的是 --如果使用不当,反射的代价很高.在Ja ...

  8. java 防止反射_如何防止JAVA反射对单例类的攻击?

    在我的上篇随笔中,我们知道了创建单例类有以下几种方式: (1).饿汉式; (2).懒汉式(.加同步锁的懒汉式.加双重校验锁的懒汉式.防止指令重排优化的懒汉式); (3).登记式单例模式; (4).静态 ...

  9. java 反射机制详解_java反射机制原理详解

    反射机制:所谓的反射机制就是java语言在运行时拥有一项自观的能力.通过这种能力可以彻底的了解自身的情况为下一步的动作做准备.下面具体介绍一下java的反射机制.这里你将颠覆原来对java的理解. J ...

最新文章

  1. TokuDB · 引擎特性 · HybridDB for MySQL高压缩引擎TokuDB 揭秘
  2. python反转单链表
  3. 将两个有序链表合并,合并后仍然有序
  4. ASP.NET MVC 实现与SQLSERVER的依赖缓存
  5. MySQL高级配置(二)详细介绍
  6. ie11上vue中使用elementui的input框无法输入中文
  7. .Net Core In Docker 在容器内编译并发布
  8. 后端码农谈前端(HTML篇)第三课:常见属性
  9. 关于未能启用约束。一行或多行中包含违反非空、唯一或外键约束的值的解决方法...
  10. Exposure Mask of Digital Cameras
  11. 对抗弱网下的音视频难题,声网正式开源抗丢包音频编解码器 Agora SOLO!
  12. java BigDecimal equals和compareTo区别
  13. java集合框架源代码_面试必备——Java集合框架
  14. Vs自带的freetextbox无法在远端使用
  15. vmplayer7安装OSX10.10
  16. firefox 3.0 beta 1 试用与下载
  17. appfuse mysql_Appfuse学习笔记(1)
  18. 【Java8】Function 讲解
  19. Pandas数据分析与处理补充习题
  20. 制作系统光盘Server 2003 总结

热门文章

  1. HTML基础:用表单写一个简易登录页面
  2. [CodeForces332E]Binary Key
  3. (转)Clang 比 GCC 编译器好在哪里?
  4. Entity Framework 6新特性:全局性地自定义Code First约定
  5. Git服务器Gitosis安装设置
  6. 修改Extmail和Extman的源代码增加公司部门和中文名字段
  7. JN_0005:PS改变图片指定内容颜色
  8. Python 打包工具cx_freeze 问题记录及解决办法
  9. 九度笔记之 1209最小邮票数
  10. Maven配置之pom.xml(一)