使用反射访问不可见类
我正在尝试使用反射获取不可见类(AKA 包私有类)的实例。我想知道是否有一种方法可以切换修饰符以使其公开,然后使用.当我现在尝试这样做时,它阻止了我说我做不到。不幸的是,没有类的方法。Class.forName
setAccesible
Class
我正在尝试使用反射获取不可见类(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$Nested
表示该类是在类内声明的。嵌套类与方法非常相似,它们可以访问其外部类的所有成员(包括私有类)。Nested
Outer
但是我们需要记住,内部类存在的实例需要其外部类的实例。通常我们通过以下方式创建它们:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
因此,正如您所看到的,Inner 类的每个实例都有一些关于其外部类的信息(对该外部实例的引用存储在字段中,更多信息:如果在调试 Java 时,变量在 IntelliJ IDEA 中的名称为“this$0”,这意味着什么?this$0
)
因此,在创建类的实例时,您需要将第一个参数引用传递给类的实例(以模拟行为)。Inner
Constructor#newInstance()
Outer
outer.new Inner()
下面是一个示例。
在包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 类的实例(因为它们是静态的)。因此,在他们的情况下,我们不需要寻找构造函数作为第一个参数。而且我们不需要将外部类的实例作为第一个参数传递。换句话说,代码将与非嵌套(顶级)类的代码相同(也许除了在引用 like 中的嵌套类时需要添加 use 而不是在类名中)。Outer.class
$
.
Class.forName()
Class.forName("some.package.Outer$Nested1$NestedNested")
Class.forName
应该工作。如果类位于安全属性的包层次结构列表中,则需要使用适当的权限(通常是所有权限;或者没有安全管理器)执行操作。"package.access"
如果您尝试使用 ,请不要使用。 处理异常很差。相反,得到一个并调用它。如果没有异常跟踪,很难看到您遇到的问题。Class.newInstance
Class.newInstance
Constructor
newInstance
与以往一样,反射的大多数(但不是全部)用途都是坏主意。