Java反射示例教程
Java反射示例教程
Java Reflection提供检查和修改应用程序的运行时行为的能力。Java中的反射是核心java的一个先进主题。使用java反射我们可以检查一个类,在运行时接口,枚举,获取它们的结构,方法和字段信息,即使在编译时无法访问类。我们还可以使用反射来实例化对象,调用它的方法,更改字段值。
- Java中的反射
- 类的Java反射
- 获取类对象
- 获得超级课程
- 获取公共成员类
- 获取声明的类
- 获取声明类
- 获取包名称
- 获得类修饰符
- 获取类型参数
- 获得已实现的接口
- 获取所有公共方法
- 获取所有公共构造函数
- 获取所有公共领域
- 获取所有注释
- 字段的Java反射
- 获得公共领域
- 字段声明类
- 获取字段类型
- 获取/设置公共字段值
- 获取/设置私有字段值
- 方法的Java反射
- 获取公共方法
- 调用公共方法
- 调用私有方法
- 构造函数的Java反射
- 获取公共构造函数
- 使用Constructor实例化对象
- 注释的Java反射
Java中的反射
Java中的反射是一个非常强大的概念,它在普通编程中几乎没有用,但它是大多数Java,J2EE框架的支柱。一些使用java反射的框架是:
- JUnit - 使用反射来解析@Test注释以获取测试方法,然后调用它。
- Spring - 依赖注入,在Spring Dependency Injection中内容
- Tomcat Web容器通过解析其web.xml文件并请求URI来将请求转发到正确的模块。
- Eclipse自动完成方法名称
- 支柱
- 过冬
列表是无穷无尽的,它们都使用java反射,因为所有这些框架都不知道和访问用户定义的类,接口,它们的方法等。
我们不应该在正常编程中使用反射,因为以下缺点我们已经可以访问类和接口。
- 性能不佳 - 由于java反射动态解析类型,因此涉及扫描类路径以查找要加载的类的处理,从而导致性能降低。
- 安全限制 - Reflection需要运行时权限,这些权限可能不适用于在安全管理器下运行的系统。由于安全管理器,这可能导致应用程序在运行时失败。
- 安全问题 - 使用反射,我们可以访问我们不应该访问的部分代码,例如,我们可以访问类的私有字段并更改它的值。这可能是严重的安全威胁,并导致您的应用程序出现异常行为。
- 高维护 - 反射代码很难理解和调试,在编译时也无法找到代码的任何问题,因为这些类可能不可用,使其不太灵活且难以维护。
类的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));
字段的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"
方法的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"
构造函数的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);
注释的反射
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反射示例教程相关推荐
- java反射用法示例_Java反射示例教程
java反射用法示例 Java Reflection provides ability to inspect and modify the runtime behavior of applicatio ...
- Java Generics示例教程 - 通用方法,类,接口
Java Generics示例教程 - 通用方法,类,接口 Java Genrics是Java 5中引入的最重要的功能之一.如果您一直在使用Java Collections 对于版本5或更高版本,我确 ...
- Java设计模式 - 示例教程
Java设计模式 - 示例教程 设计模式在软件开发人员中非常流行.设计模式是针对常见软件问题的良好描述的解决方案.我已经写了很多关于java设计模式的文章.您可以订阅我们的时事通讯下载PDF电子书(1 ...
- java反射菜鸟教程_Java反射
JAVA反射机制 1定义: 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射是java中一种强大的工具,能够 ...
- java web3j示例教程
最近在用java开发区块链项目,妥妥的菜鸟选手一枚,碰到问题,翻牌各种资源查询,百度,谷歌,GitHub,脑细胞死了不知道多少了,今天,发现了一个非常棒的网站,特地向大家推荐,可以说涵盖了web3j在 ...
- Java反射课程教程
1为什么需要反射?(reflect) Person p = new Student(); p在编译时的类型是person,但是在运行时是student. 为了让程序在运行时发现对象和类的真实信息,有两 ...
- java 实例化xpath_Java XPath示例教程
java 实例化xpath Welcome to Java XPath Example Tutorial. XPath provides syntax to define part of an XML ...
- Java锁示例– ReentrantLock
Welcome to Java Lock example tutorial. Usually when working with multi-threaded environment, we use ...
- java反射教程_Java反射教程
java反射教程 在本教程中,我主要编写一些示例来介绍Java反射可以做什么. 希望它可以给您这个概念的概述. 请留下您的评论以寻求建议. 什么是反射? 简而言之,反射是程序在运行时检查和修改对象的结 ...
最新文章
- 添加引用方式抛出和捕获干净的WebService异常
- Objective-C 自动生成文档工具:appledoc
- linux下IPython的安装方法
- Java必会的面试题
- (笔记)Mysql命令select from:查询表中的数据(记录)
- C语言 某班级有30名学生,要求从键盘输入每个学生的数学课程成绩(百分制),并进行以下处理
- 深入浅出的webpack4构建工具--webpack4+react构建环境(二十)
- Android MediaPlayer使用方法简单介绍
- linux的定cron计划任务命令
- tcp并发服务器_在Go中构建并发TCP服务器
- python画散点图-从零开始学Python【15】--matplotlib(散点图)
- python 详解re模块
- 高赞 GitHub 项目盘点:给力的 Spring 教程
- 文档损坏了怎么修复?文档修复方法分享
- Sequelize多表联合查询案例
- 无盘服务器内存问题,无盘服务器内存占用过高
- 海外游戏广告投放渠道
- 如何保护您的数据免遭未经授权的访问
- 自考《管理经济学》之宏观理解
- 【统计学习方法】模型评估与模型选择
热门文章
- JavaScript 文件拖拽上传插件 dropzone.js 介绍
- PEAR简介:用PEAR来写你的下一个php程序
- UITableView 系列二 :资料的设定方式 (Navigation Controller切换视图) (实例)
- 时区日期处理及定时 (NSDate,NSCalendar,NSTimer,NSTimeZone) -- IOS(实例)
- 人工智障学习笔记——机器学习(16)降维小结
- 动态数组ArrayList c# 1613536290
- css 列表相关的属性 列表前的小点点 0302
- 前端开发 样式表的建立和优先级 0229
- 爬虫技术前置准备工作 http url 请求方法 状态码 等等
- django小结191107