添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
微笑的白开水  ·  北京大学新闻网·  1 年前    · 
单身的菠萝  ·  android ...·  1 年前    · 
温柔的泡面  ·  当前不会命中断点 ...·  1 年前    · 

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{}
    

    让我们看看一些重要的方法:

    获取类对象

    我们可以用三种方法得到一个对象的类——通过静态变量类,使用objectjava.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

    无代码侵入的数据采集和Mock,支持Spring、Dubbo、Redis、Mybatis等开源框架的录制和回放;

    支持各种复杂业务场景的验证:多线程并发、异步回调、写操作等;

    欢迎扫码进QQ群交流

    官网:http://arextest.com
    github:https://github.com/arextest