簡體   English   中英

使用Java反射,我可以訪問類型為private靜態嵌套類的private字段嗎?

[英]Using Java reflection, can I access a private field of type private static nested class?

我瀏覽了所有與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;
}

是的,您可以簡單地遍歷bArray:

// First, get bArray
Class<A> aClass = A.class;
A instance = new A();
Class<?> bClass = aClass.getDeclaredClasses()[0];
Field field = aClass.getDeclaredField("bArray");
field.setAccessible(true);
Object[] bArray = (Object[]) field.get(instance);

// Then iterate and get field value
Field xField = bClass.getDeclaredField("theX");
xField.setAccessible(true);
Field yField = bClass.getDeclaredField("theY");
yField.setAccessible(true);
for (int i = 0; i < bArray.length; ++i) {
    Object bInstance = bArray[i];
    System.out.println("Item " + i + ": [x = " + xField.get(bInstance) + ", y = " + yField.get(bInstance) + "]");
}

在測試時,請確保您的數組已完全初始化(即包含非null值)。

Class實例不是Java編程語言意義上的類型。 它們只是對象。 所以你做不到

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

因為ABArray只是Class類型的對象,而不是類型。 如果是類型,則無論如何都無濟於事,因為您嘗試使用的類型無法從該代碼訪問。 這就是您嘗試做的所有事情,您正在嘗試訪問一個private類,而這是使用常規Java語言構造無法實現的。 但是您可以使用Object[]因為AB[]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作為輸入。 當然,您將失去編譯時類型的安全性,僅在運行時檢測錯誤,但這是反射不可避免的限制。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM