Java反射提供了检查和修改应用程序运行时行为的能力。Java中的反射是核心Java的前沿课题之一。使用java反射,我们可以在运行时检查类、接口、枚举,获得它们的结构、方法和字段信息,即使类在编译时是不可访问的。我们还可以使用反射来实例化一个对象,调用它的方法,更改字段值。
Java中的反射
Java中的反射是一个非常强大的概念,它在普通编程中用处不大,但它是大多数Java、J2EE框架的主干。使用java反射的一些框架包括:
- JUnit–使用反射来解析
@Test
注释以获取测试方法,然后调用它。 - Spring–依赖注入,请阅读Spring依赖注入
- Tomcat web容器通过解析
web.xml
文件文件和请求URI。 - 方法名的Eclipse自动完成
- Struts
- Hibernate
列表是无穷无尽的,它们都使用java反射,因为所有这些框架都没有用户定义的类、接口、它们的方法等的知识和访问权限。
由于以下缺点,我们不应该在已经可以访问类和接口的普通编程中使用反射。
- 性能差–由于java反射动态地解析类型,因此它涉及到诸如扫描类路径以查找要加载的类的处理,导致性能低下。
- 安全限制–反射需要运行时权限,这些权限对于在安全管理器下运行的系统可能不可用。这可能导致应用程序在运行时因安全管理器而失败。
- 安全问题——使用反射,我们可以访问不应该访问的部分代码,例如,我们可以访问类的私有字段并更改其值。这可能是一个严重的安全威胁,并导致应用程序异常运行。
- 高维护性——反射代码很难理解和调试,而且代码中的任何问题在编译时都找不到,因为类可能不可用,这使得它不太灵活,也很难维护。
类的Java反射
在java中,每个对象要么是一个基元类型 primitive type
,要么是一个引用。所有的类、枚举、数组都是引用类型并继承自java.lang.Object
. 基本类型是–boolean
、byte
、short
、int
、long
、char
、float
和double
。
java.lang.Class
是所有反射操作的入口点。对于每种类型的对象,JVM实例化java.lang.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;
@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;
}
@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{}
}
让我们看看一些重要的方法:
获取类对象
我们可以用三种方法得到一个对象的类——通过静态变量类,使用object
和java.lang.Class.forName(String fullyClassifiedClassName)
。对于基元类型和数组,我们可以使用静态变量类。包装类提供另一个静态变量类型来获取类。
// 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 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 arrays
Class<?> booleanClass = boolean.class;
System.out.println(booleanClass.getCanonicalName()); // prints boolean
Class<?> cDouble = Double.TYPE;
System.out.println(cDouble.getCanonicalName()); // prints double
Class<?> 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
使用泛型,它帮助框架确保检索到的类是框架基类的子类。查看Java泛型教程,了解泛型及其通配符。
获得超类 Super Class
类对象上的getSuperclass()
方法返回类的超级类。如果该类表示对象类、接口、基元类型或void
,则返回null。如果此对象表示数组类,则返回表示该对象类的类对象。
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()
方法返回一个数组,该数组包含表示该类对象所表示的类的所有公共类、接口和枚举的类对象。这包括从超类继承的公共类和接口成员,以及由类声明的公共类和接口成员。如果该类对象没有公共成员类或接口,或者该类对象表示基元类型、数组类或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));
获取声明类 Declared Classes
getDeclaredClasses()
方法返回一个类对象数组,该数组反映声明为该类对象表示的类的成员的所有类和接口。返回的数组不包括在继承的类和接口中声明的类。
//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));
获取声明类 Declaring Class
getDeclaringClass()
方法返回类对象,该对象表示在其中声明它的类。
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()
方法返回此类的包。该类的类装入器用于查找包。我们可以调用包的getName()
方法来获取包的名称。
//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()
返回TypeVariable
的数组。参数的声明顺序与参数的声明顺序相同。
//Get Type parameters (generics)
TypeVariable<?>[] typeParameters = Class.forName("java.util.HashMap").getTypeParameters();
for(TypeVariable<?> t : typeParameters)
System.out.print(t.getName()+",");
获取实现的接口
getGenericInterfaces()
方法返回由具有泛型类型信息的类实现的接口数组。我们还可以使用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[] 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()
方法返回类的公共字段数组,包括其超类和超级接口的公共字段。
//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()
方法返回元素的所有注释,也可以与类、字段和方法一起使用。请注意,只有反射可用的注释才具有运行时的保留策略。
java.lang.annotation.Annotation[] annotations = Class.forName("com.journaldev.reflection.ConcreteClass").getAnnotations();
//prints [@java.lang.Deprecated()]
System.out.println(Arrays.toString(annotations));
关于Java反射机制的讲解可以参考这篇文章:https://javakk.com/682.html
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/696.html
暂无评论