Java反射示例教程

Java Reflection提供检查和修改应用程序的运行时行为的能力。Java中的反射是核心java的一个先进主题。使用java反射我们可以检查一个类,在运行时接口,枚举,获取它们的结构,方法和字段信息,即使在编译时无法访问类。我们还可以使用反射来实例化对象,调用它的方法,更改字段值。

  1. Java中的反射
  2. 类的Java反射
    • 获取类对象
    • 获得超级课程
    • 获取公共成员类
    • 获取声明的类
    • 获取声明类
    • 获取包名称
    • 获得类修饰符
    • 获取类型参数
    • 获得已实现的接口
    • 获取所有公共方法
    • 获取所有公共构造函数
    • 获取所有公共领域
    • 获取所有注释
  3. 字段的Java反射
    • 获得公共领域
    • 字段声明类
    • 获取字段类型
    • 获取/设置公共字段值
    • 获取/设置私有字段值
  4. 方法的Java反射
    • 获取公共方法
    • 调用公共方法
    • 调用私有方法
  5. 构造函数的Java反射
    • 获取公共构造函数
    • 使用Constructor实例化对象
  6. 注释的Java反射
  1. Java中的反射

Java中的反射是一个非常强大的概念,它在普通编程中几乎没有用,但它是大多数Java,J2EE框架的支柱。一些使用java反射的框架是:

  1. JUnit - 使用反射来解析@Test注释以获取测试方法,然后调用它。
  2. Spring - 依赖注入,在Spring Dependency Injection中内容
  3. Tomcat Web容器通过解析其web.xml文件并请求URI来将请求转发到正确的模块。
  4. Eclipse自动完成方法名称
  5. 支柱
  6. 过冬

列表是无穷无尽的,它们都使用java反射,因为所有这些框架都不知道和访问用户定义的类,接口,它们的方法等。

我们不应该在正常编程中使用反射,因为以下缺点我们已经可以访问类和接口。

  • 性能不佳 - 由于java反射动态解析类型,因此涉及扫描类路径以查找要加载的类的处理,从而导致性能降低。
  • 安全限制 - Reflection需要运行时权限,这些权限可能不适用于在安全管理器下运行的系统。由于安全管理器,这可能导致应用程序在运行时失败。
  • 安全问题 - 使用反射,我们可以访问我们不应该访问的部分代码,例如,我们可以访问类的私有字段并更改它的值。这可能是严重的安全威胁,并导致您的应用程序出现异常行为。
  • 高维护 - 反射代码很难理解和调试,在编译时也无法找到代码的任何问题,因为这些类可能不可用,使其不太灵活且难以维护。
  1. 类的Java反射

在java中,每个对象都是基本类型或引用。所有类,枚举,数组都是引用类型并继承自java.lang.Object。原始类型是 - 布尔值,字节,短,int,long,char,float和double。

java.lang.Class是所有反射操作的入口点。对于每种类型的对象,JVM都实例化一个不可变实例,java.lang.Class该实例提供了检查对象的运行时属性并创建新对象,调用其方法以及获取/设置对象字段的方法。

在本节中,我们将研究Class的重要方法,为方便起见,我正在创建一些具有继承层次结构的类和接口。


package com.journaldev.reflection;public interface BaseInterface {public int interfaceInt=0;void method1();int method2(String str);
}

package com.journaldev.reflection;public class BaseClass {public int baseInt;private static void method3(){System.out.println("Method3");}public int method4(){System.out.println("Method4");return 0;}public static int method5(){System.out.println("Method5");return 0;}void method6(){System.out.println("Method6");}// inner public classpublic class BaseClassInnerClass{}//member public enumpublic enum BaseClassMemberEnum{}
}

package com.journaldev.reflection;@Deprecated
public class ConcreteClass extends BaseClass implements BaseInterface {public int publicInt;private String privateString="private string";protected boolean protectedBoolean;Object defaultObject;public ConcreteClass(int i){this.publicInt=i;}@Overridepublic void method1() {System.out.println("Method1 impl.");}@Overridepublic int method2(String str) {System.out.println("Method2 impl.");return 0;}@Overridepublic int method4(){System.out.println("Method4 overriden.");return 0;}public int method5(int i){System.out.println("Method4 overriden.");return 0;}// inner classespublic class ConcreteClassPublicClass{}private class ConcreteClassPrivateClass{}protected class ConcreteClassProtectedClass{}class ConcreteClassDefaultClass{}//member enumenum ConcreteClassDefaultEnum{}public enum ConcreteClassPublicEnum{}//member interfacepublic interface ConcreteClassPublicInterface{}}

让我们看一下类的一些重要的反射方法。

获取类对象

我们可以使用三种方法获取对象的类 - 通过静态变量class,使用getClass()对象和方法java.lang.Class.forName(String fullyClassifiedClassName)。对于原始类型和数组,我们可以使用静态变量class。包装类提供另一个静态变量TYPE来获取类。


// Get Class using reflection
Class<?> concreteClass = ConcreteClass.class;
concreteClass = new ConcreteClass(5).getClass();
try {// below method is used most of the times in frameworks like JUnit//Spring dependency injection, Tomcat web container//Eclipse auto completion of method names, hibernate, Struts2 etc.//because ConcreteClass is not available at compile timeconcreteClass = Class.forName("com.journaldev.reflection.ConcreteClass");
} catch (ClassNotFoundException e) {e.printStackTrace();
}
System.out.println(concreteClass.getCanonicalName()); // prints com.journaldev.reflection.ConcreteClass//for primitive types, wrapper classes and arrays
Class<?> booleanClass = boolean.class;
System.out.println(booleanClass.getCanonicalName()); // prints booleanClass<?> cDouble = Double.TYPE;
System.out.println(cDouble.getCanonicalName()); // prints doubleClass<?> cDoubleArray = Class.forName("[D");
System.out.println(cDoubleArray.getCanonicalName()); //prints double[]Class<?> twoDStringArray = String[][].class;
System.out.println(twoDStringArray.getCanonicalName()); // prints java.lang.String[][]

getCanonicalName()返回基础类的规范名称。请注意,java.lang.Class使用Generics,它帮助框架确保检索的Class是框架Base Class的子类。查看Java Generics Tutorial以了解泛型及其通配符。

获得超级课程

Class对象上的getSuperclass()方法返回类的超类。如果此Class表示Object类,接口,基本类型或void,则返回null。如果此对象表示数组类,则返回表示Object类的Class对象。


Class<?> superClass = Class.forName("com.journaldev.reflection.ConcreteClass").getSuperclass();
System.out.println(superClass); // prints "class com.journaldev.reflection.BaseClass"
System.out.println(Object.class.getSuperclass()); // prints "null"
System.out.println(String[][].class.getSuperclass());// prints "class java.lang.Object"

获取公共成员类

getClasses()object的类表示形式的方法返回一个数组,该数组包含Class对象,这些对象表示作为此Class对象所表示的类的成员的所有公共类,接口和枚举。这包括从超类继承的公共类和接口成员,以及由类声明的公共类和接口成员。如果此Class对象没有公共成员类或接口,或者此Class对象表示基本类型,数组类或void,则此方法返回长度为0的数组。


Class<?>[] classes = concreteClass.getClasses();
//[class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass,
//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum,
//interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface,
//class com.journaldev.reflection.BaseClass$BaseClassInnerClass,
//class com.journaldev.reflection.BaseClass$BaseClassMemberEnum]
System.out.println(Arrays.toString(classes));

获取声明的类

getDeclaredClasses()method返回Class对象的数组,这些对象反映声明为此Class对象所表示的类的成员的所有类和接口。返回的数组不包括在继承的类和接口中声明的类。


//getting all of the classes, interfaces, and enums that are explicitly declared in ConcreteClass
Class<?>[] explicitClasses = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredClasses();
//prints [class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass,
//class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultEnum,
//class com.journaldev.reflection.ConcreteClass$ConcreteClassPrivateClass,
//class com.journaldev.reflection.ConcreteClass$ConcreteClassProtectedClass,
//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass,
//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum,
//interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface]
System.out.println(Arrays.toString(explicitClasses));

获取声明类

getDeclaringClass() method返回表示声明它的类的Class对象。


Class<?> innerClass = Class.forName("com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass");
//prints com.journaldev.reflection.ConcreteClass
System.out.println(innerClass.getDeclaringClass().getCanonicalName());
System.out.println(innerClass.getEnclosingClass().getCanonicalName());

获取包名称

getPackage()method返回此类的包。此类的类加载器用于查找包。我们可以调用getName()Package的方法来获取包的名称。


//prints "com.journaldev.reflection"
System.out.println(Class.forName("com.journaldev.reflection.BaseInterface").getPackage().getName());

获得类修饰符

getModifiers()方法返回类修饰符的int表示,我们可以使用java.lang.reflect.Modifier.toString()方法以源代码中使用的字符串格式获取它。


System.out.println(Modifier.toString(concreteClass.getModifiers())); //prints "public"
//prints "public abstract interface"
System.out.println(Modifier.toString(Class.forName("com.journaldev.reflection.BaseInterface").getModifiers()));

获取类型参数

getTypeParameters()如果存在与该类关联的任何Type参数,则返回TypeVariable数组。类型参数的返回顺序与声明的顺序相同。


//Get Type parameters (generics)
TypeVariable<?>[] typeParameters = Class.forName("java.util.HashMap").getTypeParameters();
for(TypeVariable<?> t : typeParameters)
System.out.print(t.getName()+",");

获得已实现的接口

getGenericInterfaces()method返回由类实现的接口数组和泛型类型信息。我们还可以使用getInterfaces()获取所有已实现接口的类表示。


Type[] interfaces = Class.forName("java.util.HashMap").getGenericInterfaces();
//prints "[java.util.Map<K, V>, interface java.lang.Cloneable, interface java.io.Serializable]"
System.out.println(Arrays.toString(interfaces));
//prints "[interface java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]"
System.out.println(Arrays.toString(Class.forName("java.util.HashMap").getInterfaces()));

获取所有公共方法

getMethods() method返回Class的公共方法数组,包括它的超类和超级接口的公共方法。


Method[] publicMethods = Class.forName("com.journaldev.reflection.ConcreteClass").getMethods();
//prints public methods of ConcreteClass, BaseClass, Object
System.out.println(Arrays.toString(publicMethods));

获取所有公共构造函数

getConstructors() 方法返回对象的类引用的公共构造函数列表。


//Get All public constructors
Constructor<?>[] publicConstructors = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructors();
//prints public constructors of ConcreteClass
System.out.println(Arrays.toString(publicConstructors));

获取所有公共领域

getFields() method返回类的公共字段数组,包括它的超类和超级接口的公共字段。


//Get All public fields
Field[] publicFields = Class.forName("com.journaldev.reflection.ConcreteClass").getFields();
//prints public fields of ConcreteClass, it's superclass and super interfaces
System.out.println(Arrays.toString(publicFields));

获取所有注释

getAnnotations()方法返回元素的所有注释,我们也可以将它与类,字段和方法一起使用。请注意,只有带反射的注释可以使用RUNTIME的保留策略,请查看Java Annotations Tutorial
我们将在后面的章节中详细介绍这一点。


java.lang.annotation.Annotation[] annotations = Class.forName("com.journaldev.reflection.ConcreteClass").getAnnotations();
//prints [@java.lang.Deprecated()]
System.out.println(Arrays.toString(annotations));
  1. 字段的Java反射

Reflection API提供了几种方法来分析类字段并在运行时修改它们的值,在本节中我们将研究一些常用的方法反射函数。

获得公共领域

在上一节中,我们了解了如何获取类的所有公共字段的列表。Reflection API还提供了通过getField()方法获取类的特定公共字段的方法。此方法在指定的类引用中查找字段,然后在超级接口中查找,然后在超类中查找。


Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");

上面的调用将返回由ConcreteClass实现的BaseInterface字段。如果没有找到任何字段,则抛出NoSuchFieldException。

字段声明类

我们可以使用getDeclaringClass()field对象来获取声明该字段的类。


try {Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");Class<?> fieldClass = field.getDeclaringClass();System.out.println(fieldClass.getCanonicalName()); //prints com.journaldev.reflection.BaseInterface
} catch (NoSuchFieldException | SecurityException e) {e.printStackTrace();
}

获取字段类型

getType()方法返回声明的字段类型的Class对象,如果field是基本类型,则返回包装类对象。


Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");
Class<?> fieldType = field.getType();
System.out.println(fieldType.getCanonicalName()); //prints int

获取/设置公共字段值

我们可以使用反射来获取和设置对象中字段的值。


Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");
ConcreteClass obj = new ConcreteClass(5);
System.out.println(field.get(obj)); //prints 5
field.setInt(obj, 10); //setting field value to 10 in object
System.out.println(field.get(obj)); //prints 10

get()方法返回Object,因此如果field是基本类型,则返回相应的Wrapper类。如果该字段是静态的,我们可以在get()方法中将Object作为null传递。

有几个set *()方法可以将Object设置为字段,或者为字段设置不同类型的基元类型。我们可以获取字段类型,然后调用正确的函数来正确设置字段值。如果该字段是final,则set()方法抛出java.lang.IllegalAccessException。

获取/设置私有字段值

我们知道私有字段和方法不能在类外部访问,但是使用反射我们可以通过关闭字段修饰符的java访问检查来获取/设置私有字段值。


Field privateField = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredField("privateString");
//turning off access check with below method call
privateField.setAccessible(true);
ConcreteClass objTest = new ConcreteClass(1);
System.out.println(privateField.get(objTest)); // prints "private string"
privateField.set(objTest, "private string updated");
System.out.println(privateField.get(objTest)); //prints "private string updated"
  1. 方法的Java反射

使用反射我们可以获得有关方法的信息,我们也可以调用它。在本节中,我们将学习获取方法,调用方法和访问私有方法的不同方法。

获取公共方法

我们可以使用getMethod()来获取类的公共方法,我们需要传递方法的方法名和参数类型。如果在类中找不到该方法,则反射API将在超类中查找该方法。

在下面的例子中,我使用反射获取HashMap的put()方法。该示例还显示了如何获取方法的参数类型,方法修饰符和返回类型。


Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
//get method parameter types, prints "[class java.lang.Object, class java.lang.Object]"
System.out.println(Arrays.toString(method.getParameterTypes()));
//get method return type, return "class java.lang.Object", class reference for void
System.out.println(method.getReturnType());
//get method modifiers
System.out.println(Modifier.toString(method.getModifiers())); //prints "public"

调用公共方法

我们可以使用Method对象的invoke()方法来调用方法,在下面的示例代码中我使用反射调用HashMap上的put方法。


Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
Map<String, String> hm = new HashMap<>();
method.invoke(hm, "key", "value");
System.out.println(hm); // prints {key=value}

如果方法是静态的,我们可以传递NULL作为对象参数。

调用私有方法

我们可以使用getDeclaredMethod()来获取私有方法,然后关闭访问检查以调用它,下面的示例显示了我们如何调用BaseClass的method3()是静态的并且没有参数。


//invoking private method
Method method = Class.forName("com.journaldev.reflection.BaseClass").getDeclaredMethod("method3", null);
method.setAccessible(true);
method.invoke(null, null); //prints "Method3"
  1. 构造函数的Java反射

Reflection API提供了获取类的构造函数进行分析的方法,我们可以通过调用构造函数来创建类的新实例。我们已经学会了如何获得所有公共构造函数。

获取公共构造函数

我们可以在对象的类表示上使用getConstructor()方法来获取特定的公共构造函数。下面的示例演示如何获取上面定义的ConcreteClass的构造函数和HashMap的无参数构造函数。它还显示了如何获取构造函数的参数类型数组。


Constructor<?> constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);
//getting constructor parameters
System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"

使用Constructor实例化对象

我们可以在构造函数对象上使用newInstance()方法来实例化该类的新实例。由于我们在编译时没有类信息时使用反射,我们可以将它分配给Object,然后进一步使用反射来访问它的字段并调用它的方法。


Constructor<?> constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);
//getting constructor parameters
System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"Object myObj = constructor.newInstance(10);
Method myObjMethod = myObj.getClass().getMethod("method1", null);
myObjMethod.invoke(myObj, null); //prints "Method1 impl."Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"
HashMap<String,String> myMap = (HashMap<String,String>) hashMapConstructor.newInstance(null);
  1. 注释的反射

Java 1.5中引入了注释来提供类,方法或字段的元数据信息,现在它在Spring和Hibernate等框架中被大量使用。Reflection API也得到了扩展,以提供在运行时分析注释的支持。

使用反射API,我们可以分析其保留策略为运行时的注释。我已经编写了一个关于注释的详细教程以及我们如何使用反射API来解析注释,因此我建议您查看Java Annotations Tutorial

这就是所有的java反射示例教程,我希望你喜欢这个教程并理解Java Reflection API的重要性。

PS: 本文中部分反思 ,指Java中的术语:反射

转载来源:https://www.journaldev.com/1789/java-reflection-example-tutorial

Java反射示例教程相关推荐

  1. java反射用法示例_Java反射示例教程

    java反射用法示例 Java Reflection provides ability to inspect and modify the runtime behavior of applicatio ...

  2. Java Generics示例教程 - 通用方法,类,接口

    Java Generics示例教程 - 通用方法,类,接口 Java Genrics是Java 5中引入的最重要的功能之一.如果您一直在使用Java Collections 对于版本5或更高版本,我确 ...

  3. Java设计模式 - 示例教程

    Java设计模式 - 示例教程 设计模式在软件开发人员中非常流行.设计模式是针对常见软件问题的良好描述的解决方案.我已经写了很多关于java设计模式的文章.您可以订阅我们的时事通讯下载PDF电子书(1 ...

  4. java反射菜鸟教程_Java反射

    JAVA反射机制 1定义: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是java中一种强大的工具,能够 ...

  5. java web3j示例教程

    最近在用java开发区块链项目,妥妥的菜鸟选手一枚,碰到问题,翻牌各种资源查询,百度,谷歌,GitHub,脑细胞死了不知道多少了,今天,发现了一个非常棒的网站,特地向大家推荐,可以说涵盖了web3j在 ...

  6. Java反射课程教程

    1为什么需要反射?(reflect) Person p = new Student(); p在编译时的类型是person,但是在运行时是student. 为了让程序在运行时发现对象和类的真实信息,有两 ...

  7. java 实例化xpath_Java XPath示例教程

    java 实例化xpath Welcome to Java XPath Example Tutorial. XPath provides syntax to define part of an XML ...

  8. Java锁示例– ReentrantLock

    Welcome to Java Lock example tutorial. Usually when working with multi-threaded environment, we use ...

  9. java反射教程_Java反射教程

    java反射教程 在本教程中,我主要编写一些示例来介绍Java反射可以做什么. 希望它可以给您这个概念的概述. 请留下您的评论以寻求建议. 什么是反射? 简而言之,反射是程序在运行时检查和修改对象的结 ...

最新文章

  1. 添加引用方式抛出和捕获干净的WebService异常
  2. Objective-C 自动生成文档工具:appledoc
  3. linux下IPython的安装方法
  4. Java必会的面试题
  5. (笔记)Mysql命令select from:查询表中的数据(记录)
  6. C语言 某班级有30名学生,要求从键盘输入每个学生的数学课程成绩(百分制),并进行以下处理
  7. 深入浅出的webpack4构建工具--webpack4+react构建环境(二十)
  8. Android MediaPlayer使用方法简单介绍
  9. linux的定cron计划任务命令
  10. tcp并发服务器_在Go中构建并发TCP服务器
  11. python画散点图-从零开始学Python【15】--matplotlib(散点图)
  12. python 详解re模块
  13. 高赞 GitHub 项目盘点:给力的 Spring 教程
  14. 文档损坏了怎么修复?文档修复方法分享
  15. Sequelize多表联合查询案例
  16. 无盘服务器内存问题,无盘服务器内存占用过高
  17. 海外游戏广告投放渠道
  18. 如何保护您的数据免遭未经授权的访问
  19. 自考《管理经济学》之宏观理解
  20. 【统计学习方法】模型评估与模型选择

热门文章

  1. JavaScript 文件拖拽上传插件 dropzone.js 介绍
  2. PEAR简介:用PEAR来写你的下一个php程序
  3. UITableView 系列二 :资料的设定方式 (Navigation Controller切换视图) (实例)
  4. 时区日期处理及定时 (NSDate,NSCalendar,NSTimer,NSTimeZone) -- IOS(实例)
  5. 人工智障学习笔记——机器学习(16)降维小结
  6. 动态数组ArrayList c# 1613536290
  7. css 列表相关的属性 列表前的小点点 0302
  8. 前端开发 样式表的建立和优先级 0229
  9. 爬虫技术前置准备工作 http url 请求方法 状态码 等等
  10. django小结191107