Abstract: Java reflection is a very powerful mechanism, which can detect the fields, methods and constructors of internal classes in the same system. Many of its Java frameworks have applied reflection technology, such as Hibernate and Spring. It can be said that the characteristics of the reflection mechanism allow Java to build an extremely powerful and flexible system.
This article is shared from the HUAWEI CLOUD community " JAVA programming must know reflection usage summary丨 [Run! JAVA] ", original author: jackwangcumt.
Java reflection is a very powerful mechanism that can detect the fields, methods and constructors of the internal classes in the same system. Many of its Java frameworks, such as Hibernate and Spring, have applied a large number of reflection technologies. It can be said that the characteristics of the reflection mechanism allow Java to build an extremely powerful and flexible system.
Although the Java reflection mechanism has disadvantages such as low efficiency, slow speed, and low security, in many scenarios, these features are not the main factors, or the execution efficiency can be gradually improved through caching or JVM optimization.
According to online statements, reflection technology can check or modify the behavior of applications in the JVM at runtime. This is a relatively high-level language feature and a powerful technology. Reflection can enable applications to implement operations that are otherwise impossible.
The following describes and summarizes the basic knowledge of Java reflection:
First define a MyBase class, which has private fields and public fields. There are also public methods and private methods. An example of the MyBase class is as follows:
package com.hwdev.demo;
/**
* 基类示例
* @author wangming
*/
public class MyBase {
//公有字段
public int version = 1;
//私有字段
private String date = "2021-05-18" ;
//公有方法
public void say2(String msg){
System.out.println("Hello " + msg);
}
//私有方法
private String getData(){
return this.date;
}
}
Here is another definition of Hello class, which inherits from the MyBase class. Through inheritance, it is mainly used to verify the reflection usage of reflection for parent classes and subclasses.
package com.hwdev.demo;
/**
*
* @author wangming
*/
public class Hello extends MyBase {
public String author = "JackWang" ;
public int version = 1;
private String company = "kzcloud" ;
public void say(String msg){
System.out.println("Hello " + msg);
}
public void setAuthor(String author){
this.author = author;
}
public String getAuthor(){
return this.author;
}
private int getVersion(){
return this.version;
}
}
Regarding Java reflection, the powerful thing is that you can dynamically call a method from the system or modify the field value of one of the objects through the string configuration, and the Class.forName method can obtain the corresponding by passing in the full path string name of the class The Class object is very convenient. In addition, the specified fields and methods can be obtained through the getField method and the GetMethod method, and they can be called dynamically.
package com.hwdev.demo;
import java.lang.reflect.*;
import java.util.Arrays;
/**
* 反射第一种用法 Class.forName
* @author wangming
*/
public class ReflectDemo01 {
public static void Test() {
try
{
//通过字符串全路径类名查找Class
Class helloC = Class.forName("com.hwdev.demo.Hello");
//获取所有公有的字段数组,私有的无法获取
Field [] fields = helloC.getFields();
//打印字段数组内容
System.out.println(Arrays.toString(fields));
//[public java.lang.String com.hwdev.demo.Hello.author, public int com.hwdev.demo.Hello.version]
//实例化
Object obj = helloC.newInstance();
//获取特定字段,比遍历Field[]效率更高
Field f = helloC.getField("author");
if (f != null){
//关闭安全检查,提高效率
f.setAccessible(true);
//获取字段author内容
String author = (String)f.get(obj);
System.out.println("author=" + author);
//author=JackWang
}
//获取所有公有的方法数组,私有的无法获取
Method [] methods = helloC.getMethods();
//打印方法数组内容,子类等方法也可以获取到
System.out.println(Arrays.toString(methods));
//本类所有方法
Method [] methods2 = helloC.getDeclaredMethods();
//打印方法数组内容
System.out.println(Arrays.toString(methods2));
//获取特定方法,第二个参数String.class为say方法的参数类型
//say(java.lang.String)
Method m = helloC.getDeclaredMethod("say",String.class);
if (m != null){
//关闭安全检查,提高效率
m.setAccessible(true);
//获取字段author内容
Object returnValue = m.invoke(obj, new Object[]{"Java"});
//Hello Java
if (returnValue!=null){
System.out.println("returnValue =" + returnValue);
}
}
}catch(ClassNotFoundException | SecurityException ex){
ex.printStackTrace();
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
Note here: By default, the xxx.getMethods() method returns the public methods of this class, parent class, and parent interface, while xxx.getDeclaredMethods() returns all methods of this class, including private methods. In the same way, the usage of other getXXX and getDeclaredXXX in the reflection API is similar.
package com.hwdev;
import com.hwdev.demo.ReflectDemo01;
/**
*
* @author wangming
*/
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
//反射第一种用法 Class.forName
ReflectDemo01.Test();
}
}
Executing the program, the output results are as follows:
[public java.lang.String com.hwdev.demo.Hello.author, public int com.hwdev.demo.Hello.version, public int com.hwdev.demo.MyBase.version]
author=JackWang
[public void com.hwdev.demo.Hello.say(java.lang.String), public void com.hwdev.demo.Hello.setAuthor(java.lang.String), public java.lang.String com.hwdev.demo.Hello.getAuthor(), public void com.hwdev.demo.MyBase.say2(java.lang.String), public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]
[public void com.hwdev.demo.Hello.say(java.lang.String), public void com.hwdev.demo.Hello.setAuthor(java.lang.String), public java.lang.String com.hwdev.demo.Hello.getAuthor(), private int com.hwdev.demo.Hello.getVersion()]
Hello Java
From the output result, Field [] fields = helloC.getFields(); can not only get the public fields of the Hello class, but also the public fields of the parent class MyBase: com.hwdev.demo.MyBase.version
And Method [] methods2 = helloC.getDeclaredMethods(); You can get all the methods of this class, that is, the Hello class, including public methods and private methods. Therefore, Java reflection can access the private fields and methods of the class, thereby exposing internal information. This is also the reason why Java reflection has security problems.
Because Java methods support overloading, there can be multiple methods with the same name, that is, with different parameters. Therefore, when calling a method by reflection, you need to specify the parameter type of the method, so that you can clearly call the specific method signature, such as Method m = helloC.getDeclaredMethod("say",String.class); The call is public void com.hwdev.demo.Hello.say(java.lang.String).
In addition to using Class.forName for reflection, you can also obtain reflection objects in the following ways:
Hello hello = new Hello();
Class helloC = hello.getClass();
Field [] fields = helloC.getFields();
//////////////////////////////////////////
Class helloC = Hello.class;
Field [] fields = helloC.getFields();
Here is an example of how to use Java reflection to modify private fields and call private methods:
package com.hwdev.demo;
import java.lang.reflect.*;
/**
* 反射访问私有字段和方法
* @author wangming
*/
public class ReflectDemo02 {
public static void Test() {
try
{
//通过已有类查找Class
Class helloC = Hello.class;
//实例化
Object obj = helloC.newInstance();
//获取特定私有字段
Field f = helloC.getDeclaredField("company");
if (f != null){
//私有必须开启
f.setAccessible(true);
//设置私有字段值
f.set(obj, "newKZ");
//获取字段author内容
String fv = (String)f.get(obj);
System.out.println("company=" + fv);
//company=newKZ
}
//获取私有方法
Method m = helloC.getDeclaredMethod("getVersion", null);
if (m != null){
//私有必须开启
m.setAccessible(true);
Object returnValue = m.invoke(obj, null);
if (returnValue!=null){
//returnValue =1
System.out.println("returnValue =" + returnValue);
}
}
}catch(SecurityException ex){
ex.printStackTrace();
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
In addition, Java reflection can obtain annotation information, which is very much used for ORM frameworks.
package com.hwdev.demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 注解示例
* @author wangming
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ORMAnnotation {
public String FieldName();
public String FieldType();
}
Among them, @Retention(RetentionPolicy.RUNTIME) indicates that the annotation can be accessed through reflection at runtime. @Target(ElementType.FIELD) means that this annotation can only be used on the field. In the same way, you can change FIELD to Type or Method, etc.
package com.hwdev.demo;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
/**
* 反射或者字段注解
* @author wangming
*/
public class ReflectDemo03 {
public static void Test() {
try
{
Class helloC = Class.forName("com.hwdev.demo.HelloAnnotation");
Field[] fields = helloC.getDeclaredFields();
for(Field f : fields){
//关闭安全检查,提高效率
f.setAccessible(true);
Annotation ann = f.getAnnotation(ORMAnnotation.class);
if(ann instanceof ORMAnnotation){
ORMAnnotation ormAnn = (ORMAnnotation) ann;
System.out.println("FieldName=" + ormAnn.FieldName());
System.out.println("FieldType=" + ormAnn.FieldType());
}
}
}catch(ClassNotFoundException | SecurityException ex){
ex.printStackTrace();
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
Executing this example, the output is as follows:
FieldName=f_author
FieldType=varchar(50)
FieldName=f_ver
FieldType=int
Once again, introduce how to use reflection to obtain the number and types of method parameters, including generic information acquisition:
package com.hwdev.demo;
import java.util.ArrayList;
import java.util.List;
/**
* 泛型示例
* @author wangming
*/
public class GenericCls {
protected List<String> myList = new ArrayList();
public GenericCls(int size){
for(int i = 0;i<size;i++){
myList.add("item"+i);
}
}
public List<String> getList(){
return this.myList;
}
public String getList(int idx){
return this.myList.get(idx);
}
}
package com.hwdev.demo;
import java.lang.reflect.*;
/**
* 反射获取方法参数
* @author wangming
*/
public class ReflectDemo05 {
public static void Test() {
try
{
Class helloC = Class.forName("com.hwdev.demo.GenericCls");
//构造函数调用
Object obj = helloC.getConstructor(int.class).newInstance(3);
Method method = helloC.getMethod("getList", int.class);
Class<?> returnType = method.getReturnType();
System.out.println("ReturnType = " + returnType.getName());
Parameter[] params = method.getParameters();
for(Parameter p : params){
System.out.println("ParameterizedType = " + p.getParameterizedType());
System.out.println("getModifiers = " + p.getModifiers());
System.out.println("getName = " + p.getName());
System.out.println("getType = " + p.getType());
}
//调用方法
Object ret = method.invoke(obj, new Object[]{2});
System.out.println("ret = " + ret.toString());
Method method2 = helloC.getMethod("getList", null);
Type greturnType = method2.getGenericReturnType();
System.out.println("getGenericReturnType = " + returnType.getName());
if(greturnType instanceof ParameterizedType){
ParameterizedType type = (ParameterizedType) greturnType;
System.out.println("type = " + type.getTypeName());
Type[] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments){
Class typeArgClass = (Class) typeArgument;
System.out.println("typeArgClass = " + typeArgClass);
}
}
}catch(ClassNotFoundException | SecurityException ex){
ex.printStackTrace();
}
catch(Exception ex){
ex.printStackTrace();
}
}
}
Executing the above example, the output is as follows.
ReturnType = java.lang.String
ParameterizedType = int
getModifiers = 0
getName = arg0
getType = int
ret = item2
getGenericReturnType = java.lang.String
type = java.util.List<java.lang.String>
typeArgClass = class java.lang.String
There are a lot of knowledge points about reflection that can be explained, such as the use of reflection technology to implement dynamic loading of plug-ins. The efficiency of reflection can be solved by using an efficient third-party reflection library or adding a buffer mechanism, so I won't repeat it here.
Click to follow to get to know the fresh technology of Huawei Cloud for the first time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。