使用反射访问不可见的类 [英] Accessing non-visible classes with reflection

查看:146
本文介绍了使用反射访问不可见的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to get an instance of a non-visible class, AKA package private class, using reflection. I was wondering if there was a way to switch the modifiers to make it public and then access it using Class.forName. When I try that now it stops me saying I can't do it. Unfortunately there is no setAccesible method of the Class class.

推荐答案

嵌套类 - 在其他类中定义的类(包括静态类和非静态类)

内部类 - 非静态嵌套类(内部类的实例需要存在外部类的实例)

nested class - class defined within other class (includes static and non-static classes)
inner class - non-static nested class (instance of inner class need instance of outer class to exist)

根据您的问题,我们知道您要访问的构造函数不是公共的。所以你的课可能看起来像这样( A 类在某些包中与我们不同)

Based on your question we know that constructor you want to access is not public. So your class may look like this (A class is in some package different than ours)

package package1;

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

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

To create instance of this class we need to get to constructor we want to invoke, and make it accessible. When it is done we can use Constructor#newInstance(arguments) to create instance.

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 访问嵌套(静态和非静态)类,则需要使用语法:


nested and inner classes

If you want to access nested (static and non-static) Class with Class.forName you need to use syntax:

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

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

Outer$Nested says that Nested class is declared within Outer class. Nested classes are very similar to methods, they have access to all members of its outer class (including private ones).

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

But we need to remember that instance of inner class to exists requires instance of its outer class. Normally we create them via:

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

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

so as you see each instance of Inner class have some information about its outer class (reference to that outer instance is stored in this$0 field, more info: What does it mean if a variable has the name "this$0" in IntelliJ IDEA while debugging Java?)

因此在使用构造函数#创建 Inner 类的实例时newInstance()你需要将第一个参数引用传递给 Outer 类的实例(以模拟 outer.new Inner( )行为)。

So while creating instance of Inner class with Constructor#newInstance() you need to pass as first argument reference to instance of Outer class (to simulate outer.new Inner() behavior).

这是一个例子。

in package1

in package1

package package1;

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

in package2

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

    }
}



静态嵌套类



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

static-nested classes

Instances of static-nested classes don't require instance of Outer class (since they are static). So in their case we don't need to look for constructor with Outer.class as first argument. And we don't need to pass instance of outer class as first argument. In other words code will be same as for non-nested (top-level) class (maybe except fact that you would need to add $Nested syntax in Class.forName()).

这篇关于使用反射访问不可见的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆