使用Java反射,我们可以检查一个类(社区/教程/界面-in-java What is Interface in Java – Example Tutorial
),(enum)(/community/tutorials/java-enum Java Enum
),在运行时获取其结构、方法和领域信息,即使类在编译时无法访问。
java 反思
- [在爪哇语中引用] (#回放-in-java)
- [Java反射类] (# reflection-class)
- [获得类对象] (#得到-class-object)
- [Get Super-class] (#Get-Super-class)
- [Get public-member-class (#public-member-class)
- [Get sclass (#Get-classlating-class)(#Get-classlating-class (#Get-classlating-class)(#Get-classlating-class)( ) - [Get Class-classmodifers] (#Class-class-classlating-moders)(#Get-classlating-celling-class)(# ) - [Get-package-name (#MKBRBR1_]]] -[Get-ging Classclassmoders] [MKBR ) - [获得类型参数] (#类型参数)
- [获得已执行接口] (#已执行接口)
- [获得所有公用方法] (#所有公用方法)
- [Get all Public Constructioners] (#All-public-Constructors
- [Get all Public-Public-Constructions (#All-public-Constructors (#All-Public-Public-CBR1_)] (#All-Public-Public-Public-Public-Public-Public-Public-Public-Public-F) (# ) - [Get All-Anotations (# ) 3. [Java反射场 (#反射-场
- [Get Public Field] (#Get-public-field-field)
- [Get-public-field-field-field-field-type] (#Get-field-field-type) (#Get-field-field-typed-type) (_) - ) - [Get/Set Public Field value] (#Get-set-public-field-field-)
- [Get/Set Privatal Field value] (#Get-set-private-field-field-)
- [Java对方法的反思] (#反省-方法) (-). ) - [获得公用方法] (#方法-公用
- [引用公用方法] (#invoke-public-method)(_). )- [引用私人方法] (#invoke-private-method)
- [Get Public Constructor] (#public-Constructor)
- [使用建构器的参数化对象] (#新建构器)
- 说明的贾瓦反射( (英语)
1、###在Java中的反射
Java中的反射是一个非常强大的概念,在正常编程中很少使用,但它是大多数Java、J2EE框架的支柱。
- JUnit - 使用反思来解析 @Test 注释以获取测试方法,然后调用它
- Spring - 依赖注射,阅读更多在 Spring Dependency Injection
- Tomcat 网络容器通过解析他们的 web.xml 文件并请求 URI 4.Eclipse 自动完成方法名称
- Struts( _) **6.H
列表是无限的,他们都使用Java反射,因为所有这些框架都没有对用户定义的类、界面、方法等的知识和访问,我们不应该在正常编程中使用反射,因为我们已经可以访问类和界面。
由于 Java 反射可以动态地解决类型,它涉及处理,如扫描类路径以找到要加载的类,导致性能慢
- 安全限制 - 反射需要运行时许可,可能无法在安全管理器下运行系统。这可能会导致应用程序在运行时因安全管理器而失败
- 安全问题 - 使用反射我们可以访问我们不应该访问的代码部分,例如我们可以访问类别的私有领域并改变其值。
Java 对类的反思
在 Java 中,每个对象都是原始类型或参考类型,所有类型, enums, array 都是参考类型,并从java.lang.Object 继承。原始类型是 - boolean, byte, short, int, long, char, float, and double. java.lang.Class是所有反射操作的入口点。对于每个对象类型,JVM(/community/tutorials/difference-jdk-vs-jre-vs-jvm "JDK, JRE 和 JVM 在 Java 中之间的差异")实例一个 [immutable](/community/tutorials/how-to-create-immutable-classin-java- "How to write an immutable?" class)的java.lang.Class实例,它提供了
1package com.journaldev.reflection;
2
3public interface BaseInterface {
4
5 public int interfaceInt=0;
6
7 void method1();
8
9 int method2(String str);
10}
1package com.journaldev.reflection;
2
3public class BaseClass {
4
5 public int baseInt;
6
7 private static void method3(){
8 System.out.println("Method3");
9 }
10
11 public int method4(){
12 System.out.println("Method4");
13 return 0;
14 }
15
16 public static int method5(){
17 System.out.println("Method5");
18 return 0;
19 }
20
21 void method6(){
22 System.out.println("Method6");
23 }
24
25 // inner public class
26 public class BaseClassInnerClass{}
27
28 //member public enum
29 public enum BaseClassMemberEnum{}
30}
1package com.journaldev.reflection;
2
3@Deprecated
4public class ConcreteClass extends BaseClass implements BaseInterface {
5
6 public int publicInt;
7 private String privateString="private string";
8 protected boolean protectedBoolean;
9 Object defaultObject;
10
11 public ConcreteClass(int i){
12 this.publicInt=i;
13 }
14
15 @Override
16 public void method1() {
17 System.out.println("Method1 impl.");
18 }
19
20 @Override
21 public int method2(String str) {
22 System.out.println("Method2 impl.");
23 return 0;
24 }
25
26 @Override
27 public int method4(){
28 System.out.println("Method4 overriden.");
29 return 0;
30 }
31
32 public int method5(int i){
33 System.out.println("Method4 overriden.");
34 return 0;
35 }
36
37 // inner classes
38 public class ConcreteClassPublicClass{}
39 private class ConcreteClassPrivateClass{}
40 protected class ConcreteClassProtectedClass{}
41 class ConcreteClassDefaultClass{}
42
43 //member enum
44 enum ConcreteClassDefaultEnum{}
45 public enum ConcreteClassPublicEnum{}
46
47 //member interface
48 public interface ConcreteClassPublicInterface{}
49
50}
让我们来看看课堂上一些重要的修复方法。
获取类对象
我们可以使用三种方法获得对象的类 - 通过静态变量类
,使用对象的方法getClass()
和java.lang.Class.forName(String fullyClassifiedClassName)
。
1// Get Class using reflection
2Class<?> concreteClass = ConcreteClass.class;
3concreteClass = new ConcreteClass(5).getClass();
4try {
5 // below method is used most of the times in frameworks like JUnit
6 //Spring dependency injection, Tomcat web container
7 //Eclipse auto completion of method names, hibernate, Struts2 etc.
8 //because ConcreteClass is not available at compile time
9 concreteClass = Class.forName("com.journaldev.reflection.ConcreteClass");
10} catch (ClassNotFoundException e) {
11 e.printStackTrace();
12}
13System.out.println(concreteClass.getCanonicalName()); // prints com.journaldev.reflection.ConcreteClass
14
15//for primitive types, wrapper classes and arrays
16Class<?> booleanClass = boolean.class;
17System.out.println(booleanClass.getCanonicalName()); // prints boolean
18
19Class<?> cDouble = Double.TYPE;
20System.out.println(cDouble.getCanonicalName()); // prints double
21
22Class<?> cDoubleArray = Class.forName("[D");
23System.out.println(cDoubleArray.getCanonicalName()); //prints double[]
24
25Class<?> twoDStringArray = String[][].class;
26System.out.println(twoDStringArray.getCanonicalName()); // prints java.lang.String[][]
请注意,java.lang.Class 使用 Generics,它有助于框架程序确保所获取的 Class 是框架基础类的子类。 查看 [Java Generics Tutorial](/community/tutorials/java-generics-example-method-class-interface Java Generics Tutorial – Example Class, Interface, Methods, Wildcards 和更多
)来了解通用和其野生卡。
获得超级班级
getSuperclass() 方法在一个类对象上返回类的超级类. 如果这个类代表对象类、接口、原始类型或无,则返回 null。
1Class<?> superClass = Class.forName("com.journaldev.reflection.ConcreteClass").getSuperclass();
2System.out.println(superClass); // prints "class com.journaldev.reflection.BaseClass"
3System.out.println(Object.class.getSuperclass()); // prints "null"
4System.out.println(String[][].class.getSuperclass());// prints "class java.lang.Object"
获取公共会员类
getClasses()
对象表示类的方法返回一个包含 Class 对象的数组,代表了该类对象所代表的类的所有公共类、接口和单元,包括从超级类和由该类声明的公共类和接口成员继承的公共类和接口成员。
1Class<?>[] classes = concreteClass.getClasses();
2//[class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass,
3//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum,
4//interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface,
5//class com.journaldev.reflection.BaseClass$BaseClassInnerClass,
6//class com.journaldev.reflection.BaseClass$BaseClassMemberEnum]
7System.out.println(Arrays.toString(classes));
取得宣布的班级
getDeclaredClasses()
方法返回一组 Class 对象,这些对象反映了被这个 Class 对象表示为类的所有类和界面,返回的数组不包括在继承类和界面中宣布的类。
1//getting all of the classes, interfaces, and enums that are explicitly declared in ConcreteClass
2Class<?>[] explicitClasses = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredClasses();
3//prints [class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass,
4//class com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultEnum,
5//class com.journaldev.reflection.ConcreteClass$ConcreteClassPrivateClass,
6//class com.journaldev.reflection.ConcreteClass$ConcreteClassProtectedClass,
7//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicClass,
8//class com.journaldev.reflection.ConcreteClass$ConcreteClassPublicEnum,
9//interface com.journaldev.reflection.ConcreteClass$ConcreteClassPublicInterface]
10System.out.println(Arrays.toString(explicitClasses));
宣布班级
getDeclaringClass()
方法返回代表它被声明的类的类对象。
1Class<?> innerClass = Class.forName("com.journaldev.reflection.ConcreteClass$ConcreteClassDefaultClass");
2//prints com.journaldev.reflection.ConcreteClass
3System.out.println(innerClass.getDeclaringClass().getCanonicalName());
4System.out.println(innerClass.getEnclosingClass().getCanonicalName());
包装名称
getPackage()
方法返回该类的包. 该类的类加载器用于查找包. 我们可以使用 Package 的 getName()
方法获取包的名称。
1//prints "com.journaldev.reflection"
2System.out.println(Class.forName("com.journaldev.reflection.BaseInterface").getPackage().getName());
变更班级
getModifiers()
方法返回类型修改器的 int 表示,我们可以使用 java.lang.reflect.Modifier.toString()
方法以源代码中使用的字符串格式获取它。
1System.out.println(Modifier.toString(concreteClass.getModifiers())); //prints "public"
2//prints "public abstract interface"
3System.out.println(Modifier.toString(Class.forName("com.journaldev.reflection.BaseInterface").getModifiers()));
查找参数类型
getTypeParameters()
返回 TypeVariable 的数组,如果有与类别相关的任何类型参数. 类型参数以声明的相同顺序返回。
1//Get Type parameters (generics)
2TypeVariable<?>[] typeParameters = Class.forName("java.util.HashMap").getTypeParameters();
3for(TypeVariable<?> t : typeParameters)
4System.out.print(t.getName()+",");
实现了接口
getGenericInterfaces()
方法返回由类实施的界面数组与通用类型信息. 我们还可以使用 getInterfaces()
来获得所有实现的界面的类代表性。
1Type[] interfaces = Class.forName("java.util.HashMap").getGenericInterfaces();
2//prints "[java.util.Map<K, V>, interface java.lang.Cloneable, interface java.io.Serializable]"
3System.out.println(Arrays.toString(interfaces));
4//prints "[interface java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]"
5System.out.println(Arrays.toString(Class.forName("java.util.HashMap").getInterfaces()));
使用所有公共方法
getMethods()
方法返回该类的公共方法,包括其超级类和超级接口的公共方法。
1Method[] publicMethods = Class.forName("com.journaldev.reflection.ConcreteClass").getMethods();
2//prints public methods of ConcreteClass, BaseClass, Object
3System.out.println(Arrays.toString(publicMethods));
获取所有公共建设者
getConstructors()
方法返回对象类引用的公共构建者列表。
1//Get All public constructors
2Constructor<?>[] publicConstructors = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructors();
3//prints public constructors of ConcreteClass
4System.out.println(Arrays.toString(publicConstructors));
获取所有公共场所
'getFields()' 方法返回类的公共字段,包括其超级类和超级接口的公共字段。
1//Get All public fields
2Field[] publicFields = Class.forName("com.journaldev.reflection.ConcreteClass").getFields();
3//prints public fields of ConcreteClass, it's superclass and super interfaces
4System.out.println(Arrays.toString(publicFields));
获取所有注释
getAnnotations()
方法返回元素的所有注释,我们也可以使用它与类、字段和方法一起使用。 请注意,只有与反射可用的注释具有 RUNTIME 保留策略,请参阅 Java Annotations Tutorial. 我们将在以后的部分详细研究这一点。
1java.lang.annotation.Annotation[] annotations = Class.forName("com.journaldev.reflection.ConcreteClass").getAnnotations();
2//prints [@java.lang.Deprecated()]
3System.out.println(Arrays.toString(annotations));
Java 对字段的反思
Reflection API 提供了几个方法来分析 Class 字段并在运行时修改它们的值,在本节中,我们将探讨一些常用的方法的反射函数。
获得公共场所
在最后一节中,我们看到了如何获取一个类的所有公共字段的列表. 反射API还提供了通过getField()
方法获取一个类的特定公共字段的方法. 此方法在指定类引用中搜索该字段,然后在超级接口中,然后在超级类中搜索。
1Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");
上面的调用将返回由 ConcreteClass 实现的 BaseInterface 中的字段,如果没有找到的字段,则会丢弃 NoSuchFieldException。
场地声明班级
我们可以使用字段对象的 getDeclaringClass()
来获得该字段的类声明。
1try {
2 Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("interfaceInt");
3 Class<?> fieldClass = field.getDeclaringClass();
4 System.out.println(fieldClass.getCanonicalName()); //prints com.journaldev.reflection.BaseInterface
5} catch (NoSuchFieldException | SecurityException e) {
6 e.printStackTrace();
7}
获取田野类型
getType() 方法返回声明字段类型的 Class 对象,如果字段是原始类型,则返回 wrapper 类对象。
1Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");
2Class<?> fieldType = field.getType();
3System.out.println(fieldType.getCanonicalName()); //prints int
获取/设置公共字段值
我们可以使用反射获取并设置对象中的字段的值。
1Field field = Class.forName("com.journaldev.reflection.ConcreteClass").getField("publicInt");
2ConcreteClass obj = new ConcreteClass(5);
3System.out.println(field.get(obj)); //prints 5
4field.setInt(obj, 10); //setting field value to 10 in object
5System.out.println(field.get(obj)); //prints 10
get() 方法返回 Object,所以如果字段是原始类型,它返回相应的 ** Wrapper Class**. 如果字段是静态的,我们可以将 Object 传递为 null in get() 方法. 有几个 set*() 方法将 Object 设置为字段或将不同类型的原始类型设置为字段. 我们可以获得字段的类型,然后召唤正确的函数以正确设置字段值。如果字段是最终的,则 set() 方法将 java.lang.IllegalAccessException 投放。
获取/设置私人字段值
我们知道私有字段和方法不能在类之外访问,但使用反射我们可以通过关闭Java访问检查来获取/设置私有字段值。
1Field privateField = Class.forName("com.journaldev.reflection.ConcreteClass").getDeclaredField("privateString");
2//turning off access check with below method call
3privateField.setAccessible(true);
4ConcreteClass objTest = new ConcreteClass(1);
5System.out.println(privateField.get(objTest)); // prints "private string"
6privateField.set(objTest, "private string updated");
7System.out.println(privateField.get(objTest)); //prints "private string updated"
Java 方法反思
使用反思,我们可以获取有关方法的信息,我们也可以召唤它. 在本节中,我们将学习不同的方法来获取方法,召唤方法和访问私人方法。
使用公共方法
我们可以使用 getMethod() 来获取类的公用方法,我们需要通过该方法的方法名称和参数类型。如果该方法在类中没有找到,反射 API 就会在超级类中寻找该方法。
1Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
2//get method parameter types, prints "[class java.lang.Object, class java.lang.Object]"
3System.out.println(Arrays.toString(method.getParameterTypes()));
4//get method return type, return "class java.lang.Object", class reference for void
5System.out.println(method.getReturnType());
6//get method modifiers
7System.out.println(Modifier.toString(method.getModifiers())); //prints "public"
使用公共方法
我们可以使用 Method 对象的 invoke() 方法召唤方法,在下面的示例代码中,我正在使用反射在 HashMap 上召唤 put 方法。
1Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);
2Map<String, String> hm = new HashMap<>();
3method.invoke(hm, "key", "value");
4System.out.println(hm); // prints {key=value}
如果方法是静态的,我们可以通过 NULL 作为对象参数。
使用私人方法
我们可以使用 getDeclaredMethod() 来获取私人方法,然后关闭访问检查来调用它,下面的示例显示了我们如何调用 BaseClass 静态且没有参数的 method3()。
1//invoking private method
2Method method = Class.forName("com.journaldev.reflection.BaseClass").getDeclaredMethod("method3", null);
3method.setAccessible(true);
4method.invoke(null, null); //prints "Method3"
Java 设计师的反思
反射 API 提供了方法来让类的构造者进行分析,我们可以通过召唤构造者来创建新的类实例。
成为公共建设者
我们可以在对象的类表示上使用 getConstructor() 方法来获取特定公共构建器. 下面的示例显示如何获取上面定义的 ConcreteClass 构建器和 HashMap 无参数构建器。
1Constructor<?> constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);
2//getting constructor parameters
3System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"
4
5Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
6System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"
使用 Constructor 即时对象
由于我们在编译时没有类信息时使用反射,我们可以将其分配给 Object,然后进一步使用反射来访问其字段并召唤其方法。
1Constructor<?> constructor = Class.forName("com.journaldev.reflection.ConcreteClass").getConstructor(int.class);
2//getting constructor parameters
3System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"
4
5Object myObj = constructor.newInstance(10);
6Method myObjMethod = myObj.getClass().getMethod("method1", null);
7myObjMethod.invoke(myObj, null); //prints "Method1 impl."
8
9Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);
10System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes())); // prints "[]"
11HashMap<String,String> myMap = (HashMap<String,String>) hashMapConstructor.newInstance(null);
反思的注释
Annotations 被引入 Java 1.5 以提供类、方法或领域的元数据信息,现在它被广泛应用于诸如 Spring 和 Hibernate 等框架中。 Reflection API 也被扩展到提供在运行时分析注释的支持。 使用反射 API,我们可以分析注释,其保留策略是 Runtime。 我已经写了一篇关于注释的详细教程,以及我们如何使用反射 API 来分析注释,所以我建议您检查 (Java Annotations Tutorial)(/community/tutorials/java-annotations)。