使用Java反射,我可以访问类型为private静态嵌套类的private字段吗? [英] Using Java reflection, can I access a private field of type private static nested class?

查看:110
本文介绍了使用Java反射,我可以访问类型为private静态嵌套类的private字段吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经仔细阅读了所有与Java反射相关的条目,但似乎都无法解决我正在处理的情况.我有一个带有静态嵌套类B的类A.类A还具有一个称为bArray的类型B数组作为其字段之一.我需要从类外部以及bArray元素的私有成员访问此字段.我已经能够使用getDeclaredClasses获得静态嵌套类,并且我通常会使用getDeclaredFields和setAccessible获得私有字段bArray,但我似乎无法将它们放在一起,以便能够从类外部遍历bArray.

这是我正在使用的示例类结构.

public class A {
    private A.B[] bArray = new A.B[16];

    private static class B {
        private int theX;
        private int theY;

        B(int x, int y) {
            this.theX = x;
            this.theY = y;
        }
        // More methods of A.B not included   
    }
}

我最终需要从类A的外部获取bArray及其字段theX和theY.

我不能使用诸如Class.forName("classname")之类的类的名称,因为所有代码都通过混淆器运行,并且除了字符串中的名称以外,其他所有名称都发生了变化.由于混淆,我可以使用字段顺序(索引),但不能使用名称.除了这个私有静态嵌套数组字段,我设法挑选了所有我需要的字段,方法和其他内容.

这是我尝试的方向.前三行似乎可以满足我的要求,但是第四行说ABArray无法解析:

A myA = new A();
Class AB = stealNamedInnerClass(A.class);
Class ABArray = Array.newInstance(AB, 0).getClass();
ABArray myABArray = (ABArray)stealAndGetField(myA, ABArray);

这些是我引用的实用程序功能:

public static Field stealField(Class typeOfClass, Class typeOfField)
{
    Field[] fields = typeOfClass.getDeclaredFields();
    for (Field f : fields) {
        if (f.getType().equals(typeOfField)) {
            try {
                f.setAccessible(true);
                return f;
            } catch (Exception e) {
                break; // Throw the Exception
            }
        }
    }
    throw new RuntimeException("Couldn't steal Field of type \"" + typeOfField + "\" from class \"" + typeOfClass + "\" !");
}

public static Object stealAndGetField(Object object, Class typeOfField)
{
    Class typeOfObject;

    if (object instanceof Class) { // User asked for static field:
        typeOfObject = (Class)object;
        object = null;
    } else {
        typeOfObject = object.getClass();
    }

    try {
        Field f = stealField(typeOfObject, typeOfField);
        return f.get(object);
    } catch (Exception e) {
        throw new RuntimeException("Couldn't get Field of type \"" + typeOfField + "\" from object \"" + object + "\" !");
    }
}

public static Class stealNamedInnerClass(Class clazz)
{
    Class innerClazz = null;
    Class[] innerClazzes = clazz.getDeclaredClasses();
    if (innerClazzes != null) {
        for (Class inner : innerClazzes) {
            if (!inner.isAnonymousClass())
                return inner;
        }
    }
    return null;
}

解决方案

Class 实例不是类型.它们只是对象.所以你不能做

Class ABArray = Array.newInstance(AB, 0).getClass();
ABArray myABArray = (ABArray)stealAndGetField(myA, ABArray);

因为ABArray只是类型Class的对象,而不是类型.如果是类型,则无论如何都无济于事,因为该代码无法访问您要使用的类型.这就是您尝试做的所有事情,您正在尝试访问private类,这是使用常规Java语言构造无法实现的.但是您只能使用Object[],因为A.B[]Object[]的子类:

A myA = new A();
Class AB = stealNamedInnerClass(A.class);
Class ABArray = Array.newInstance(AB, 0).getClass();
Object[] myABArray = (Object[])stealAndGetField(myA, ABArray);

请注意,将元素处理为Object没问题,因为您将(并且可以)仅通过反射访问它们,并且反射方法始终将Object作为输入.当然,您将失去编译时类型的安全性,仅在运行时检测错误,但这是不可避免的反射限制.

I've looked through every entry related to Java reflection I can find and none seem to address the situation I'm dealing with. I have a class A with a static nested class in it, B. Class A also has as one of its fields, an array of type B, called bArray. I need to access this field from outside the class as well as the private members of the elements of bArray. I have been able to get the static nested class using getDeclaredClasses and I would normally get the private field bArray with getDeclaredFields and setAccessible but I can't seem to put it all together to be able to iterate through bArray from outside the class.

Here is an example class structure that I'm working with.

public class A {
    private A.B[] bArray = new A.B[16];

    private static class B {
        private int theX;
        private int theY;

        B(int x, int y) {
            this.theX = x;
            this.theY = y;
        }
        // More methods of A.B not included   
    }
}

I ultimately need to get at bArray and its fields theX and theY from outside of class A.

I cannot use the names of the classes like Class.forName("classname") because the code all gets run through an obfuscator and the names all change except the ones in strings of course. I can use the field order (index) but not the name due to obfuscation. I've managed to pick out all of the fields, methods and whatnot that I need except this private static nested array field.

This is the direction I've tried. The first 3 lines of this seem to do what I want but the 4th says ABArray cannot be resolved:

A myA = new A();
Class AB = stealNamedInnerClass(A.class);
Class ABArray = Array.newInstance(AB, 0).getClass();
ABArray myABArray = (ABArray)stealAndGetField(myA, ABArray);

These are the utility functions I'm referencing:

public static Field stealField(Class typeOfClass, Class typeOfField)
{
    Field[] fields = typeOfClass.getDeclaredFields();
    for (Field f : fields) {
        if (f.getType().equals(typeOfField)) {
            try {
                f.setAccessible(true);
                return f;
            } catch (Exception e) {
                break; // Throw the Exception
            }
        }
    }
    throw new RuntimeException("Couldn't steal Field of type \"" + typeOfField + "\" from class \"" + typeOfClass + "\" !");
}

public static Object stealAndGetField(Object object, Class typeOfField)
{
    Class typeOfObject;

    if (object instanceof Class) { // User asked for static field:
        typeOfObject = (Class)object;
        object = null;
    } else {
        typeOfObject = object.getClass();
    }

    try {
        Field f = stealField(typeOfObject, typeOfField);
        return f.get(object);
    } catch (Exception e) {
        throw new RuntimeException("Couldn't get Field of type \"" + typeOfField + "\" from object \"" + object + "\" !");
    }
}

public static Class stealNamedInnerClass(Class clazz)
{
    Class innerClazz = null;
    Class[] innerClazzes = clazz.getDeclaredClasses();
    if (innerClazzes != null) {
        for (Class inner : innerClazzes) {
            if (!inner.isAnonymousClass())
                return inner;
        }
    }
    return null;
}

解决方案

Class instances are not types in the sense of the Java programming language. They are just objects. So you can’t do

Class ABArray = Array.newInstance(AB, 0).getClass();
ABArray myABArray = (ABArray)stealAndGetField(myA, ABArray);

because ABArray is just an object of type Class, not a type. If it were a type, it wouldn’t help anyway as the type you are trying to use is not accessible from that code. Which is what your attempt is all about, you are trying to access a private class which is not possible using normal Java language constructs. But you can just use Object[] as A.B[] is a subclass of Object[]:

A myA = new A();
Class AB = stealNamedInnerClass(A.class);
Class ABArray = Array.newInstance(AB, 0).getClass();
Object[] myABArray = (Object[])stealAndGetField(myA, ABArray);

Note that processing the elements as Object is no problem as you will (and can) access them via reflection only and the reflection methods take Object as input anyway. Of course, you will lose compile-time type safety and detect mistakes at runtime only but that’s an unavoidable limitation of reflection.

这篇关于使用Java反射,我可以访问类型为private静态嵌套类的private字段吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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