2014-10-08 80 views
0

我想知道如何使用我的JUnit测试反射来访问私有内部类的私有字段。使用反射访问私人内部类字段

这里是什么,我需要一个例子:

public class A 
{ 
    private Map<Integer, InnerClass> objectMap = new TreeMap<Integer, InnerClass>.descendingMap(); 

    private class InnerClass  
    { 
     private int fieldOne 
     private int fieldTwo 
    } 
} 

在这个例子中,我希望访问在

我已经试过了A的实例fieldOne和fieldTwo的值以下:

A instanceA = new A(); 

Field privateObjectMapField = A.class.getDeclaredField("objectMap"); 
privateObjectMapField.setAccessible(true); 
NavigableMap<Integer, Class<?>> fieldValue = (NavigableMap<Integer, Class<?>>) privateObjectMapField.get(instanceA); 

// 5 is a key in the map so this should set declaredClass to an instance of InnerClass 
Class<?> declaredClass = fieldValue.get(5).getClass(); 
Field fieldOne = declaredClass.getDeclaredField("fieldOne"); 
fieldOne.setAccessible(true); 
Assert.assertEquals(100, fieldOne.getInt(declaredClass)); 

在这种情况下,它crashses在:Class<?> declaredClass = fieldValue.get(5).getClass(); 出现错误:

java.lang.ClassCastException: com.test.A$InnerClass cannot be cast to java.lang.Class

有没有人知道这里有什么问题?

我希望这个例子很清楚。

感谢

回答

0

应该

NavigableMap<Integer, InnerClass> fieldValue = (NavigableMap<Integer, InnerClass>) privateObjectMapField.get(instanceA); 
+0

InnerClass是私人的,所以我的JUnit类无法看到它 – sam 2014-10-08 21:59:38

+0

所以也许你必须改变你的类结构,因为在这个例子中,InnerClass不能被测试/达到。 – ToYonos 2014-10-08 22:01:40

0

简短的回答:

objectMapMap<Integer, A.InnerClass>,并且如果它是一个Map<Integer, Class<?>>你对待它。

试试这个,而是:

NavigableMap<Integer, ?> fieldValue = ... 

详细的解答(你应该阅读,如果你想了解泛型了解这一点)

fieldValue方法声明为NavigableMap<Integer, Class<?>>,这意味着即:

fieldValue.get(5) 

只是将这样的:

((Class<?>) fieldValue.get(5)) 

这是因为如何erasure作品。基本上,declaredClass不是真的是 a NavigableMap<Integer, Class<?>>,它只是一个NavigableMap(这是它的“原始类型”),编译器可以向其添加类型检查和自动投射。

那么,如果在关键5的对象不是真的Class会发生什么?当你尝试转换它时,你会得到一个ClassCastException。这就是你正在发生的事情,因为关键5的对象是A.InnerClass,而不是Class。它基本上没有什么不同:

Object o = new InnerClass(); 
Class<?> boom = (Class<?>) o; // ClassCastException 

至于修复,这取决于你实际上正在尝试做什么。如果仅用于测试,则可以考虑使InnerClass具有默认可见性(又名包私有)而不是私有。您也可以检索objectMap作为Map<Integer, ?>,然后致电fieldValue.get(5).getClass()。这将得到关键的5的对象,碰巧是InnerClass(但你不需要在编译时指定它),然后调用Object.getClass()来获得它的类。

+0

感谢您的信息。但我仍然有问题。 我有这个: 'NavigableMap fieldValue =(NavigableMap )privateObjectMapField.get(instanceA); 类 declaredClass = fieldValue.get(5).getClass(); FieldOne = declaredClass.getDeclaredField(“fieldOne”); fieldOne.setAccessible(true); Assert.assertEquals(100,fieldOne.getInt(declaredClass)); ' 这一次它调用getInt失败: '不能设置INT场com.test.A $ InnerClass.fieldOne到java.lang.Class' 是否应宣告类仍然是类在这里? – sam 2014-10-08 22:18:59

+0

听起来像是一个新问题 - 很难阅读如此多的代码,使其成为评论。但我鼓励你尝试挑选每一步并自行调试,并用对泛型工作原理的新理解武装起来。 :) – yshavit 2014-10-08 23:56:05