当前位置: 首页 > 面试题库 >

通过反射访问不可见的类

龚盛
2023-03-14
问题内容

我试图使用反射获取不可见类的实例,即AKA包私有类。我想知道是否有一种方法可以切换修饰符以使其公开,然后使用进行访问Class.forName。当我现在尝试尝试时,它会阻止我说我做不到。不幸的是,没有该类的setAccesible方法Class


问题答案:

嵌套类 -在其他类(包括静态和非静态类)中定义的类
内部类 -非静态嵌套类(内部类的实例需要外部类的实例存在)

非嵌套(顶级)类

根据您的问题,我们知道您要访问的构造函数不是公共的。因此您的班级可能看起来像这样(A班级与我们的课程有所不同)

package package1;

public class A {
    A(){
        System.out.println("this is non-public constructor");
    }
}

要创建此类的实例,我们需要进入要调用的构造函数并使之可访问。完成后,我们可以Constructor#newInstance(arguments)用来创建实例。

Class<?> c = Class.forName("package1.A");
//full package name --------^^^^^^^^^^
//or simpler without Class.forName:
//Class<package1.A> c = package1.A.class;

//In our case we need to use
Constructor<?> constructor = c.getDeclaredConstructor();
//note: getConstructor() can return only public constructors
//so we needed to search for any Declared constructor

//now we need to make this constructor accessible
constructor.setAccessible(true);//ABRACADABRA!

Object o = constructor.newInstance();

嵌套类和内部类

如果要访问嵌套(静态和非静态)类,则Class.forName需要使用语法:

Class<?> clazz = Class.forName("package1.Outer$Nested");

Outer$NestedNested该类是在Outer类内声明的。嵌套类与方法非常相似,它们可以访问其外部类的所有成员(包括私有成员)。

但是我们需要记住,内部类的实例要存在就需要其外部类的实例。通常,我们通过以下方式创建它们:

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();

因此,如您所见,内部类的每个实例都具有有关其外部类的一些信息(对该外部实例的引用存储在this$0字段中,

因此,在创建Inner类实例时,Constructor#newInstance()您需要将第一个参数引用传递给Outer类实例(以模拟outer.newInner()行为)。

这是一个例子。

包装1

package package1;

public class Outer {
    class Inner{
        Inner(){
            System.out.println("non-public constructor of inner class");
        }
    }
}

包装2

package package2;

import package1.Outer;
import java.lang.reflect.Constructor;

public class Test {
    public static void main(String[] args) throws Exception {

        Outer outerObject = new Outer();

        Class<?> innerClazz = Class.forName("package1.Outer$Inner");

        // constructor of inner class as first argument need instance of
        // Outer class, so we need to select such constructor
        Constructor<?> constructor = innerClazz.getDeclaredConstructor(Outer.class);

        //we need to make constructor accessible 
        constructor.setAccessible(true);

        //and pass instance of Outer class as first argument
        Object o = constructor.newInstance(outerObject);

        System.out.println("we created object of class: "+o.getClass().getName());

    }
}

静态嵌套类

静态嵌套类的实例不需要Outer类的实例(因为它们是静态的)。因此,在他们的情况下,我们不需要使用Outer.class第一个参数作为构造函数。而且我们不需要将外部类的实例作为第一个参数传递。换句话说,代码将与非嵌套(顶级)类的代码相同(也许除了您需要在中添加$Nested语法的事实以外Class.forName())。



 类似资料:
  • 要 动态获取一个对象方法的信息,首先需要通过下列方法之一创建一个 类型的对象或者数组。 getMethods() getMethods(String name,Class<?> …parameterTypes) getDeclaredMethods() getDeclaredMethods(String name,Class<?>...parameterTypes) 如果是访问指定的构造方法,需要

  • 问题内容: 这是一个测试类: 这是我的输出: 我缺少通过反射使注释可见的什么? 我是否仅需要检查它们的存在就需要注释处理器? 问题答案: 为了在运行时访问注释,它需要具有运行时的保留策略。 否则,注释将被丢弃,并且JVM无法识别它们。 有关更多信息,请参见此处。

  • 通过下列任意一个方法访问成员变量时将返回 Field 类型的对象或数组。 getFields() getField(String name) getDeclaredFields() getDeclaredField(String name) 上述方法返回的 Field 对象代表一个成员变量。例如,要访问一个名称为 price 的成员变量,示例代码如下: Field 类的常用方法如表 1 所示 表1

  • 为了能够 动态获取对象构造方法的信息,首先需要通过下列方法之一创建一个 类型的对象或者数组。 getConstructors() getConstructor(Class<?>…parameterTypes) getDeclaredConstructors() getDeclaredConstructor(Class<?>...parameterTypes) 如果是访问指定的构造方法,需要根据该构

  • 如何使用反射来区分类重载方法,例如: <代码>方法()和<代码>方法(int-arg) 并调用此函数: 它返回错误,这意味着默认情况下选择没有参数的方法。如果我调用没有int参数的方法,它将工作。我问如何区分重载的方法?我已经阅读了的文档https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html还有一个关于SO的旧帖子,但两个来源都

  • 我读了一大堆这么多的问题,但我似乎找不到答案。 我有以下课程: 在其他地方,我试图访问这些字符串: 为什么我会得到一个IllegalAccess异常?如果我删除field.get行,我可以在LogCat中看到以下行: 参考资料: 使用反射在Java中获取成员变量值的陷阱 反射:通过反射加载的类中的常量变量 通过反射访问Java静态最终ivar值