使用反射访问不可见的类

Jos*_*bel 49 java reflection class package-private

我试图使用反射获得一个不可见类,AKA包私有类的实例.我想知道是否有办法切换修饰符使其公开然后使用它来访问它Class.forName.当我尝试这一点时,它阻止我说我不能这样做.不幸的是setAccesible,Class班上没有方法.

Psh*_*emo 60

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

非嵌套(顶级)类

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

package package1;

public class A {
    A(){
        System.out.println("this is non-public constructor");
    }
}
Run Code Online (Sandbox Code Playgroud)

要创建此类的实例,我们需要获取要调用的构造函数,并使其可访问.完成后我们可以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();
Run Code Online (Sandbox Code Playgroud)

嵌套和内部类

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

Class<?> clazz = Class.forName("package1.Outer$Nested");
Run Code Online (Sandbox Code Playgroud)

Outer$Nested说这个Nested课是在Outer课堂上宣布的.嵌套类与方法非常相似,它们可以访问其外部类的所有成员(包括私有类).

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

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
Run Code Online (Sandbox Code Playgroud)

因此,当您看到Inner类的每个实例都有关于其外部类的一些信息时(对该外部实例的引用存储在this$0字段中,更多信息:在调试Java时,如果变量在IntelliJ IDEA中具有名称"this $ 0",这意味着什么?)

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

这是一个例子.

在package1中

package package1;

public class Outer {
    class Inner{
        Inner(){
            System.out.println("non-public constructor of inner class");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在package2中

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());

    }
}
Run Code Online (Sandbox Code Playgroud)

静态嵌套类

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

  • @MaheshBhuva是的(至少在标准设置下,我不是反射大师,所以我无法确定是否有防止它的方法)。Class.forName`返回类* literal *,它是拥有元信息* about *指定类的Class的实例。但是,如果我们想从中访问某些方法/字段,则可能需要在那些“方法”或“字段”的实例上调用“ setAccessible(true)”。 (2认同)