2011-02-27 60 views
3

为什么这段代码返回“class java.lang.Object”?反映嵌套匿名类的Java

Object a = new Object() { 
    public Object b = new Object(){ 
    public int c; 
    }; 
}; 

System.out.println(a.getClass().getField("b").getType()); 

为什么内心型会迷路?我如何反映c字段?

编辑:

这一个工程(如在一些答案指出):

a.getClass().getField("b").get(a) ... 

但我必须调用一个getter,有没有什么办法,以反映与只反射元数据c ?

+0

内部类型** IS **对象。这是匿名扩展对象! – Nishant 2011-02-27 17:04:14

回答

5

b由于被声明为Object

public Object b = ...; 

有由变量(运行时类型)所引用的对象的类型变量(静态型)和类型之间的区别。

Field.getType()返回该字段的静态类型。

如果你想获得由现场引用的对象的运行时类型,您需要访问该对象并在其上调用getClass()(因为a被声明为Object,因此b是不可见,因为其成员必须使用反射来访问它):

System.out.println(
    a.getClass().getField("b").get(a).getClass()); 

UPDATE:不能反映c而不访问对象的包含它的实例。这就是为什么这些类型被称为匿名 - 包含c的类型没有名称,因此您不能将字段b声明为该类型的字段。

+0

所以是'a',它不是java.lang.Object类型 – Marcus 2011-02-27 17:04:55

+3

“ab”不合法,因为b字段不存在于类型java.lang.Object中 – Marcus 2011-02-27 17:06:39

+0

您不能以这种方式访问​​b,因为只是编译器的一个普通对象。您会收到“b无法解析或不是字段”的错误。 – Boris 2011-02-27 17:07:48

1

为什么内心型会迷路?

因为您正在获取字段“b”(对象)的类型类型,而不是您将实例分配给“b”的匿名内部类的类型。

如何反映c字段?

您可以使用此

System.out.println(a.getClass().getField("b").get(a).getClass().getField("c")); 

代替。这会得到字段“b”的值,它是类,但只有在“b”保证不为空时才有效。

这样做似乎表明一个糟糕的设计,可能有其他方法来存档你想要做什么。但不知道目的,这是我能够回答的一切。

+0

嗯,我没有任何这个代码的实际用途,我只是偶然发现它,想知道它为什么表现得像它的行为。所以没有任何方法可以只用元数据反映c(即不使用get(a))? – Marcus 2011-02-27 17:08:11

+0

好吧,好奇心总是好:)据我所知,没有办法用匿名内部类,因为你没有办法得到这些类java.lang.Class-instance没有一个匿名类的实际实例(显然除了Class.forName()等) – Boris 2011-02-27 17:11:27

3

让我们来看看仔细这一行:

System.out.println(a.getClass().getField("b").getType()); 

首先,你拿的a变量。它是Object的一些匿名子类。我们称之为MyClass$1。好的,到目前为止这么好。

接下来,您调用getClass()方法。它返回a的类,即MyClass$1类的描述。尽管如此,这个描述并不依赖于那个类的任何特定的实例。这个类对于所有的实例都是一样的,不管它是a还是别的(除非使用不同的类加载器)。然而,在这种特殊情况下,只能有一个实例,因为该类是匿名的,但机制仍然相同。

现在,从课堂上,您将获得字段b。由于课程并不直接与任何这种情况联系在一起,因此该字段与a无关。这只是对MyClass$1类别的字段a究竟是什么的描述。

现在你得到它的类型。但由于它不受任何实例限制,因此无法知道运行时类型。事实上,如果班级不是匿名的,则可以有多个MyClass$1实例,每个实例在a中具有不同的值。或者你根本没有实例。所以getType()唯一可能告诉你的是b的声明类型,这正是它所做的。 b字段实际上可能是null,那么结果就是Object

Field类提供了get()方法来实际访问某个对象的特定领域,如:

System.out.println(a.getClass().getField("b").get(a).getClass()); 

现在你喜欢的东西MyClass$1$1,这是匿名类的名称对象b字段a实例