本文共 24637 字,大约阅读时间需要 82 分钟。
java反射用法示例
Java Reflection provides ability to inspect and modify the runtime behavior of application. Reflection in Java is one of the advance topic of core java. Using java reflection we can inspect a class, , , get their structure, methods and fields information at runtime even though class is not accessible at compile time. We can also use reflection to instantiate an object, invoke it’s methods, change field values.
Java Reflection提供了检查和修改应用程序运行时行为的功能。 Java中的反射是核心Java的高级主题之一。 使用java反射,即使在编译时无法访问类,我们也可以在运行时检查类, , ,获取其结构,方法和字段信息。 我们还可以使用反射来实例化对象,调用其方法,更改字段值。
Reflection in Java is a very powerful concept and it’s of little use in normal programming but it’s the backbone for most of the Java, J2EE frameworks. Some of the frameworks that use java reflection are:
Java中的反射是一个非常强大的概念,在常规编程中很少使用,但它是大多数Java,J2EE框架的基础。 使用Java反射的一些框架是:
The list is endless and they all use java reflection because all these frameworks have no knowledge and access of user defined classes, interfaces, their methods etc.
列表是无止境的,它们都使用Java反射,因为所有这些框架都不了解并且不能访问用户定义的类,接口,其方法等。
We should not use reflection in normal programming where we already have access to the classes and interfaces because of following drawbacks.
由于以下缺点,我们不应该在已经可以访问类和接口的常规编程中使用反射。
In java, every object is either a primitive type or reference. All the classes, enums, arrays are reference types and inherit from java.lang.Object
. Primitive types are – boolean, byte, short, int, long, char, float, and double.
在Java中,每个对象都是原始类型或引用。 所有的类,枚举,数组都是引用类型,并且继承自java.lang.Object
。 基本类型为-布尔值,字节,短型,整数,长型,字符,浮点型和双精度型。
java.lang.Class is the entry point for all the reflection operations. For every type of object, instantiates an instance of java.lang.Class
that provides methods to examine the runtime properties of the object and create new objects, invoke its method and get/set object fields.
java.lang.Class是所有反射操作的入口点。 对于每种类型的对象, 实例化一个java.lang.Class
的实例,该实例提供方法来检查对象的运行时属性并创建新对象,调用其方法并获取/设置对象字段。
In this section, we will look into important methods of Class, for convenience, I am creating some classes and interfaces with hierarchy.
在本节中,我们将研究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 class public class BaseClassInnerClass{} //member public enum public enum BaseClassMemberEnum{}}
package com.journaldev.reflection;@Deprecatedpublic 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; } @Override public void method1() { System.out.println("Method1 impl."); } @Override public int method2(String str) { System.out.println("Method2 impl."); return 0; } @Override public int method4(){ System.out.println("Method4 overriden."); return 0; } public int method5(int i){ System.out.println("Method4 overriden."); return 0; } // inner classes public class ConcreteClassPublicClass{} private class ConcreteClassPrivateClass{} protected class ConcreteClassProtectedClass{} class ConcreteClassDefaultClass{} //member enum enum ConcreteClassDefaultEnum{} public enum ConcreteClassPublicEnum{} //member interface public interface ConcreteClassPublicInterface{}}
Let’s look at some of the important refection methods for classes.
让我们看一下类的一些重要的refection方法。
We can get Class of an object using three methods – through static variable class
, using getClass()
method of object and java.lang.Class.forName(String fullyClassifiedClassName)
. For primitive types and arrays, we can use static variable class
. Wrapper classes provide another static variable TYPE
to get the class.
我们可以使用三种方法获取对象的Class:通过静态变量class
,使用object的getClass()
方法和java.lang.Class.forName(String fullyClassifiedClassName)
。 对于基本类型和数组,我们可以使用静态变量class
。 包装器类提供了另一个静态变量TYPE
来获取该类。
// Get Class using reflectionClass 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 time concreteClass = 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 arraysClass 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()
returns the canonical name of the underlying class. Notice that java.lang.Class uses Generics, it helps frameworks in making sure that the Class retrieved is subclass of framework Base Class. Check out to learn about generics and its wildcards.
getCanonicalName()
返回基础类的规范名称。 请注意,java.lang.Class使用泛型,它有助于框架确保所检索的Class是框架Base Class的子类。 查看以了解泛型及其通配符。
getSuperclass() method on a Class object returns the super class of the class. If this Class represents either the Object class, an interface, a primitive type, or void, then null is returned. If this object represents an array class then the Class object representing the Object class is returned.
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()
method of a Class representation of object returns an array containing Class objects representing all the public classes, interfaces and enums that are members of the class represented by this Class object. This includes public class and interface members inherited from superclasses and public class and interface members declared by the class. This method returns an array of length 0 if this Class object has no public member classes or interfaces or if this Class object represents a primitive type, an array class, or void.
对象的Class表示形式的getClasses()
方法返回一个数组,该数组包含Class对象,这些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 returns an array of Class objects reflecting all the classes and interfaces declared as members of the class represented by this Class object. The returned array doesn’t include classes declared in inherited classes and interfaces.
getDeclaredClasses()
方法返回一个Class对象数组,该数组反映了所有声明为该Class对象表示的类成员的所有类和接口。 返回的数组不包括在继承的类和接口中声明的类。
//getting all of the classes, interfaces, and enums that are explicitly declared in ConcreteClassClass [] 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 returns the Class object representing the class in which it was declared.
getDeclaringClass()
方法返回表示声明它的类的Class对象。
Class innerClass = Class.forName("com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass");//prints com.journaldev.reflection.ConcreteClassSystem.out.println(innerClass.getDeclaringClass().getCanonicalName());System.out.println(innerClass.getEnclosingClass().getCanonicalName());
getPackage()
method returns the package for this class. The class loader of this class is used to find the package. We can invoke getName()
method of Package to get the name of the package.
getPackage()
方法返回此类的包。 此类的类加载器用于查找包。 我们可以调用Package的getName()
方法来获取包的名称。
//prints "com.journaldev.reflection"System.out.println(Class.forName("com.journaldev.reflection.BaseInterface").getPackage().getName());
getModifiers()
method returns the int representation of the class modifiers, we can use java.lang.reflect.Modifier.toString()
method to get it in the string format as used in source code.
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()
returns the array of TypeVariable if there are any Type parameters associated with the class. The type parameters are returned in the same order as declared.
如果有任何与该类关联的Type参数,则getTypeParameters()
返回TypeVariable数组。 类型参数的返回顺序与声明的顺序相同。
//Get Type parameters (generics)TypeVariable [] typeParameters = Class.forName("java.util.HashMap").getTypeParameters();for(TypeVariable t : typeParameters)System.out.print(t.getName()+",");
getGenericInterfaces()
method returns the array of interfaces implemented by the class with generic type information. We can also use getInterfaces()
to get the class representation of all the implemented interfaces.
getGenericInterfaces()
方法返回具有通用类型信息的类实现的接口数组。 我们还可以使用getInterfaces()
获取所有已实现接口的类表示。
Type[] interfaces = Class.forName("java.util.HashMap").getGenericInterfaces();//prints "[java.util.Map, 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 returns the array of public methods of the Class including public methods of it’s superclasses and super interfaces.
getMethods()
方法返回Class的公共方法的数组,包括其超类和超级接口的公共方法。
Method[] publicMethods = Class.forName("com.journaldev.reflection.ConcreteClass").getMethods();//prints public methods of ConcreteClass, BaseClass, ObjectSystem.out.println(Arrays.toString(publicMethods));
getConstructors()
method returns the list of public constructors of the class reference of object.
getConstructors()
方法返回对象的类引用的公共构造函数的列表。
//Get All public constructorsConstructor [] publicConstructors = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructors();//prints public constructors of ConcreteClassSystem.out.println(Arrays.toString(publicConstructors));
getFields()
method returns the array of public fields of the class including public fields of it’s super classes and super interfaces.
getFields()
方法返回该类的公共字段数组,包括其超类和超级接口的公共字段。
//Get All public fieldsField[] publicFields = Class.forName("com.journaldev.reflection.ConcreteClass").getFields();//prints public fields of ConcreteClass, it's superclass and super interfacesSystem.out.println(Arrays.toString(publicFields));
getAnnotations()
method returns all the annotations for the element, we can use it with class, fields and methods also. Note that only annotations available with reflection are with retention policy of RUNTIME, check out .
getAnnotations()
方法返回元素的所有注释,我们也可以将其与类,字段和方法一起使用。 请注意,只有反射可用的注释才具有RUNTIME的保留策略,请查看 。
java.lang.annotation.Annotation[] annotations = Class.forName("com.journaldev.reflection.ConcreteClass").getAnnotations();//prints [@java.lang.Deprecated()]System.out.println(Arrays.toString(annotations));
Reflection API provides several methods to analyze Class fields and modify their values at runtime, in this section we will look into some of the commonly used reflection functions for methods.
Reflection API提供了几种方法来分析Class字段并在运行时修改它们的值,在本节中,我们将研究一些方法的常用反射函数。
In last section, we saw how to get the list of all the public fields of a class. Reflection API also provides method to get specific public field of a class through getField()
method. This method look for the field in the specified class reference and then in the super interfaces and then in the super classes.
在上一节中,我们看到了如何获取类的所有公共字段的列表。 Reflection API还提供了通过getField()
方法获取类的特定公共字段的方法。 此方法在指定的类引用中查找字段,然后在超级接口中查找字段,然后在超级类中查找。
Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");
Above call will return the field from BaseInterface that is implemented by ConcreteClass. If there is no field found then it throws NoSuchFieldException.
上面的调用将从BaseInterface返回由ConcreteClass实现的字段。 如果没有找到任何字段,则抛出NoSuchFieldException。
We can use getDeclaringClass()
of field object to get the class declaring the field.
我们可以使用字段对象的getDeclaringClass()
获取声明字段的类。
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() method returns the Class object for the declared field type, if field is primitive type, it returns the wrapper class object.
getType()方法返回声明的字段类型的Class对象,如果field是原始类型,则返回包装类对象。
Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");Class fieldType = field.getType();System.out.println(fieldType.getCanonicalName()); //prints int
We can get and set the value of a field in an Object using reflection.
我们可以使用反射获取并设置对象中字段的值。
Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");ConcreteClass obj = new ConcreteClass(5);System.out.println(field.get(obj)); //prints 5field.setInt(obj, 10); //setting field value to 10 in objectSystem.out.println(field.get(obj)); //prints 10
get() method return Object, so if field is primitive type, it returns the corresponsing . If the field is static, we can pass Object as null in get() method.
get()方法返回Object,因此,如果field是原始类型,则它将返回对应的 。 如果该字段是静态的,则可以在get()方法中将Object作为null传递。
There are several set*() methods to set Object to the field or set different types of primitive types to the field. We can get the type of field and then invoke correct function to set the field value correctly. If the field is final, the set() methods throw java.lang.IllegalAccessException.
有几种set *()方法可将Object设置为该字段或将不同类型的基本类型设置为该字段。 我们可以获取字段的类型,然后调用正确的函数来正确设置字段值。 如果该字段为final,则set()方法将引发java.lang.IllegalAccessException。
We know that private fields and methods can’t be accessible outside of the class but using reflection we can get/set the private field value by turning off the java access check for field modifiers.
我们知道私有字段和方法无法在类外部访问,但是使用反射,我们可以通过关闭字段修饰符的Java访问检查来获取/设置私有字段值。
Field privateField = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredField("privateString");//turning off access check with below method callprivateField.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"
Using reflection we can get information about a method and we can invoke it also. In this section, we will learn different ways to get a method, invoke a method and accessing private methods.
使用反射,我们可以获得有关方法的信息,我们也可以调用它。 在本节中,我们将学习获取方法,调用方法和访问私有方法的不同方法。
We can use getMethod() to get a public method of class, we need to pass the method name and parameter types of the method. If the method is not found in the class, reflection API looks for the method in superclass.
我们可以使用getMethod()获取类的公共方法,我们需要传递方法名称和方法的参数类型。 如果在类中未找到该方法,则反射API在超类中查找该方法。
In below example, I am getting put() method of HashMap using reflection. The example also shows how to get the parameter types, method modifiers and return type of a method.
在下面的示例中,我使用反射获取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 voidSystem.out.println(method.getReturnType());//get method modifiersSystem.out.println(Modifier.toString(method.getModifiers())); //prints "public"
We can use invoke() method of Method object to invoke a method, in below example code I am invoking put method on HashMap using reflection.
我们可以使用Method对象的invoke()方法来调用方法,在下面的示例代码中,我使用反射在HashMap上调用put方法。
Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);Maphm = new HashMap<>();method.invoke(hm, "key", "value");System.out.println(hm); // prints {key=value}
If the method is static, we can pass NULL as object argument.
如果该方法是静态的,则可以将NULL作为对象参数传递。
We can use getDeclaredMethod() to get the private method and then turn off the access check to invoke it, below example shows how we can invoke method3() of BaseClass that is static and have no parameters.
我们可以使用getDeclaredMethod()获取私有方法,然后关闭访问检查以调用它,下面的示例显示了如何调用静态且没有参数的BaseClass的method3()。
//invoking private methodMethod method = Class.forName("com.journaldev.reflection.BaseClass").getDeclaredMethod("method3", null);method.setAccessible(true);method.invoke(null, null); //prints "Method3"
Reflection API provides methods to get the constructors of a class to analyze and we can create new instances of class by invoking the constructor. We have already learned how to get all the public constructors.
Reflection API提供了获取类的构造函数进行分析的方法,我们可以通过调用构造函数来创建类的新实例。 我们已经学习了如何获取所有公共构造函数。
We can use getConstructor() method on the class representation of object to get specific public constructor. Below example shows how to get the constructor of ConcreteClass defined above and the no-argument constructor of HashMap. It also shows how to get the array of parameter types for the constructor.
我们可以在对象的类表示形式上使用getConstructor()方法来获取特定的公共构造函数。 下面的示例演示如何获取上面定义的ConcreteClass的构造函数和HashMap的无参数构造函数。 它还显示了如何获取构造函数的参数类型数组。
Constructor constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);//getting constructor parametersSystem.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 "[]"
We can use newInstance() method on the constructor object to instantiate a new instance of the class. Since we use reflection when we don’t have the classes information at compile time, we can assign it to Object and then further use reflection to access it’s fields and invoke it’s methods.
我们可以在构造函数对象上使用newInstance()方法来实例化该类的新实例。 由于我们在编译时没有类信息时使用反射,因此可以将其分配给Object,然后进一步使用反射来访问其字段并调用其方法。
Constructor constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);//getting constructor parametersSystem.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 "[]"HashMapmyMap = (HashMap ) hashMapConstructor.newInstance(null);
Annotations was introduced in Java 1.5 to provide metadata information of the class, methods or fields and now it’s heavily used in frameworks like Spring and Hibernate. Reflection API was also extended to provide support to analyze the annotations at runtime.
Java 1.5中引入了注释,以提供有关类,方法或字段的元数据信息,现在它在诸如Spring和Hibernate之类的框架中大量使用。 反射API也进行了扩展,以提供在运行时分析注释的支持。
Using reflection API we can analyze annotations whose retention policy is Runtime. I have already written a detailed tutorial on annotations and how we can use reflection API to parse annotations, so I would suggest you to check out .
使用反射API,我们可以分析其保留策略为Runtime的注释。 我已经写了一个详细的注释教程,以及如何使用反射API解析注释,因此建议您阅读 。
Thats all for java reflection example tutorial, I hope you liked the tutorial and understood the importance of Java Reflection API.
多数民众赞成在Java反射示例教程中,希望您喜欢该教程并理解Java Reflection API的重要性。
翻译自:
java反射用法示例
转载地址:http://eqlzd.baihongyu.com/