访问匿名内部类变量

时间:2010-08-18 07:22:08

标签: java anonymous-class

如何从外部类访问我?

  HashSet<Integer> hs=new HashSet<Integer>(){
        int i=30;
    };

我可以这样做

int k=new HashSet<Integer>(){
    int i=30;
}.i;

但如果我得到'我'那么我就无法得到hashset的实例。有没有办法让两者都有?这个问题只是出于好奇。它没有太多实际的应用。我只是想知道它是否可以做到。

6 个答案:

答案 0 :(得分:7)

解决方案1:对象注册系统

提供的两个片段实际上是在存储对刚刚创建的匿名类实例的引用或立即访问其自定义字段之间做出选择。做一个似乎会失去做另一个的能力。

实现折衷的一种方法是拥有一个对象注册系统,并在匿名类中使用实例初始化程序JLS 8.6)自行注册到此系统。

这是一个简单的概念验证,使用Object[]进行简单的注册系统:

    final Object[] registrar = { null };
    int k = new HashSet<Integer>(){
        { registrar[0] = this; }
        int i= 666;
    }.i;
    Set<Integer> set = (Set<Integer>) registrar[0];

    System.out.println(k); // 666
    System.out.println(set.getClass().isAnonymousClass()); // true

基本上我们使用1元素Object[],并且在我们的匿名类的实例初始化器中,我们将this“注册”到此数组。请注意,这只是一个概念验证;在生产代码中,您将使用比此更强大且类型安全的对象注册系统。


解决方案2:元组

如果您的匿名类可能有多个“字段”,则此方法很有效。只需将它们全部打包到tuple,确保在匿名类中包含对this的引用。

这是一个简单的概念验证,使用Object[]来表示元组:

    Object[] tuple = new HashSet<Integer>(){
        Object[] tuple = { this, 666, 13, "XXX", "OMG ABUZE" };
    }.tuple;
    Set<Integer> set = (Set<Integer>) tuple[0];
    set.add(null);
    System.out.println(set.getClass().isAnonymousClass()); // true
    System.out.println(Arrays.toString(tuple));
    // [[null], 666, 13, XXX, OMG ABUZE]

在生产代码中,您将使用更加面向对象且类型安全的CustomTuple类。请注意,这是“我的方法如何返回2个值”问题的类似解决方案:只需返回1个值即可捕获所有这些信息。

答案 1 :(得分:5)

拯救的反思,我想:

HashSet<Integer> hs = new HashSet<Integer>() {
    int i = 30;
};
int i = hs.getClass().getDeclaredField("i").getInt(hs);
System.out.println(i);

P.S。写完之后我觉得很脏。

答案 2 :(得分:2)

当你想到它时,这是有道理的。

表达式

new HashSet<Integer>(){
    int i=30;
}

的类型为java.util.HashSetjava.util.HashSet没有名为i的字段,因此

new HashSet<Integer>(){
   int i=30;
}.i

不会编译。换句话说,尝试分解复合表达式,以便将new的结果分配给变量x,然后调用x.i。您可以给x哪种类型允许x.i编译?没有这样的类型名称,它是一个匿名类。

这是匿名类的“缺点” - 它们只能有意义地覆盖扩展类型中存在的成员。如果添加新成员,则只能通过反射访问它们。

答案 3 :(得分:1)

我不相信你可以。您不能将变量的类型声明为匿名类型 1 。您可以在方法中引入命名的类:

import java.util.*;

public class Test
{
    public static void main(String[] args)
    {
        class Foo extends Hashtable
        {
            int i = 30;
        }

        Foo f = new Foo();
        System.out.println(f.i);
    }
}

这太可怕了(真的,非常可怕)而且我认为我曾经看到它在生产代码中使用过 - 但它确实有效。


1 C#使用var解决了这个问题 - 编译器使用初始化表达式来确定变量的类型。 Java中的匿名类型与C#中的匿名类型有所不同,但如果Java类似var,我相信您的代码可以正常工作。

答案 4 :(得分:0)

嗯,在我看来,总会有反思的方式,但对我来说似乎有点矫枉过正。

当你将课程设置为匿名时,我看不到任何其他方式来做你的工作。

答案 5 :(得分:0)

匿名内部类不是为此目的而设计的,所以从我记忆中,你无法做到这一点。如果你想要,你可以创建一个“正常”的内部类。