2014-01-15 4 views
0

Я просмотрел каждую запись, связанную с отражением Java, которую я могу найти, и никто, кажется, не обращается к ситуации, с которой я имею дело. У меня есть класс A со статическим вложенным классом, B. Класс A также имеет одно из своих полей - массив типа B, называемый bArray. Мне нужно получить доступ к этому полю вне класса, а также к частным членам элементов bArray. Мне удалось получить статический вложенный класс, используя getDeclaredClasses, и я обычно получаю личное поле bArray с getDeclaredFields и setAccessible, но я не могу собрать все это вместе, чтобы иметь возможность выполнять итерацию через bArray вне класса.Используя отражение Java, могу ли я получить доступ к частному полю типа private static вложенного класса?

Вот пример структуры классов, с которой я работаю.

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 
    } 
} 

я в конечном итоге нужно получить в Баррэ и его полей рять ж, и они из-за пределов класса А.

Я не могу использовать имена классов, как Class.forName («Classname»), так как код все запускается через обфускатор, и все имена меняются, за исключением тех, что указаны в строках. Я могу использовать порядковый номер поля (индекс), но не имя из-за обфускации. Мне удалось выделить все поля, методы и многое, что мне нужно, кроме этого частного поля статического вложенного массива.

Это направление, которое я пробовал. Первая 3 строки это, кажется, делать то, что я хочу, но четвёртый говорит 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; 
} 
+2

Не могли бы вы предоставить то, что вы уже пробовали? – sp00m

+1

Обфускация и отражение обычно взаимоисключающие. Вы можете исключить выбранные классы из обфускации, чтобы сохранить способность отражения. Вместо classForName() используйте литералы класса (например, Integer.class). – Durandal

+1

вы можете наложить 'bArray' на' Object [] 'и перебрать его, что обычно –

ответ

2

Class экземпляры не являются типами в смысле языка программирования Java. Это просто объекты. Таким образом, вы не можете сделать

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, как вход все равно. Конечно, вы потеряете безопасность типа компиляции и обнаружите ошибки только во время выполнения, но это неизбежное ограничение рефлексии.

6

Да, вы можете просто перебирать над Баррэ:

// 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) + "]"); 
} 

Когда вы проверяете его, убедитесь, что ваш массив полностью инициализирован (т.е. содержит ненулевые значения).

Смежные вопросы