繁体   English   中英

访问匿名内部类变量

[英]Access anonymous inner class variables

如何从外部类访问我?

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

我可以这样做

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

但是,如果我得到“我”,那么我就无法得到hashset的实例。有没有办法获得两者?问题只是出于好奇。它没有太多实际应用。我只是想知道它是否可以完成。

解决方案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:元组

如果您的匿名类可能有多个“字段”,则此方法很有效。 简单地收拾他们都变成一个元组 ,确保包括一个参考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个值即可捕获所有这些信息。

我想是对救援的反思:

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

PS写完之后我觉得有点脏。

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

表达方式

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

java.util.HashSet类型, java.util.HashSet没有名为i字段,所以

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

不会编译。 换句话说,尝试分解复合表达式,以便将new的结果赋给变量x ,然后调用xi 你可以给x什么类型的xi来编译? 没有这样的类型名称,它是一个匿名类。

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

我不相信你能。 您不能将变量的类型声明为匿名类型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东西,我相信你的代码会起作用。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM