Java - 如何动态创建“匿名”类

时间:2013-08-27 02:11:57

标签: java oop anonymous-class

我可以这样做:

new Object(){
    public void hi(){}
}.hi();

我(或我可以)如何做到这一点:

IWouldRatherStayAnonymous t = new IWouldRatherStayAnonymous extends Thread(){
    public void NoNoYouCantCallMe(String s){}
};
t.NoNoYouCantCallMe("some useful data that i will need later, but don't want to save this anonymous class");

如果我不能在语法上做到这一点,任何人都可以解释逻辑/实现设计,为什么这将永远不会工作?

==========================================

编辑:澄清 - 我想创建一个匿名类而不保存它,然后实例化该匿名类的实例。我只需要1个引用,因为我不打算经常使用这个引用(即使在同一个外部类中也不想使用它)。但是,我只想将一些数据传递给这个匿名类只有一次(理想情况下是构造函数,但你会注意到你实际上不能覆盖Thread()中的构造函数)。

这真的不是一个巨大的交易,我只是好奇这是否可行,但似乎从一些答案可行,但不是很漂亮。

7 个答案:

答案 0 :(得分:3)

你的问题有点令人困惑,但听起来你想要一个扩展Thread并实现某个接口的类,但是在它所使用的方法之外无法访问它(这将规则甚至私有嵌套类)。在这种情况下,请使用local class

void myMethod() {
    class Impl extends Thread implements SomeInterface {
        @Override
        public void someInterfaceMethod(String s){ }
    }
    new Impl().someInterfaceMethod("data");
}

编辑:为了响应您的更新,您可以自然地为本地类提供构造函数并传入数据,或者让它关闭外部方法中的final个变量。 / p>

答案 1 :(得分:2)

  

如果我不能在语法上做到这一点,任何人都可以解释   逻辑/实现设计,为什么这将永远不起作用?

我可以解释一下。如果Java中有表达式foo.bar(...),则编译器必须确保表达式foo的静态(编译时)类型支持方法bar()。在第一种情况下,左边的表达式是匿名类创建表达式,因此它的静态类型是具有该方法的匿名类。

但是,在第二种情况下,左边的表达式是一个变量。变量的静态类型是声明变量的类型。在Java中,必须使用显式类型声明变量(与其他语言一样,不是varauto)。因此,其静态类型必须是命名类型。 Thread并且没有其他命名类型支持方法NoNoYouCantCallMe();只有匿名类支持此方法,并且您不能声明匿名类类型的变量。这就是为什么它在语法上不可能。

  

但是,我想简单地将一些数据传递给匿名者   类只有一次(理想情况下是构造函数,但你会注意到你   实际上不能覆盖Thread()中的构造函数。

这很简单。您不需要将数据显式传递到匿名类,因为在匿名类和本地类中,您可以自动访问周围范围内的final变量。因此,您只需直接使用外部数据,而不是传入数据。

final String someData = "blah";

Thread t = new Thread() {
    public void run() { doStuffWith(someData); }
};

答案 2 :(得分:1)

有两种方法可以访问匿名类的方法:

  • 通过实现接口或扩展类,然后调用您在匿名类中实现的方法,或
  • 使用反射(我假设你知道它是如何完成的,但不想这样做。)

Java做not provide a way of capturing the type of the anonymous class statically,例如以类似于C#的var关键字的方式。

在您的情况下,您可以使用void NoNoYouCantCallMe(String)方法创建抽象类型,并使用该类作为匿名类的基础,如下所示:

abstract class MyThreadBase extends Thread {
    public abstract void YesICanCallYou(String s);
}
...
MyThreadBase t = new MyThreadBase() {
    public void YesICanCallYou(String s){}
};
...
t.YesICanCallYou();

答案 3 :(得分:1)

你可以创建一个内部类,只是不要匿名。匿名意味着您没有类型。

我建议在同一个文件中使用命名的内部类或第二个类。我经常使用第二种,它不能公开。

答案 4 :(得分:1)

如果真的想要在不使用界面或抽象类的情况下做一些像这样的淫秽,你可以通过反思来调用它:

@Test
public void testCrazyStuff() throws IllegalArgumentException, SecurityException,
    IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
    Object object = new Thread()
    {
        public void ICanBeCalled( String s )
        {
            System.out.println( s );
        }
    };
    object.getClass()
      .getMethod( "ICanBeCalled", String.class )
      .invoke( object, "Whatever string!" );
}

但这没有意义......最好采用一个简单的解决方案来设置接口或抽象类,就像其他建议一样。

答案 5 :(得分:1)

您可以使用自由变量捕获将数据传递给匿名内部类,将要捕获其值的任何变量声明为final

public void myFunction(final int magicNumber) {
  new Thread() {
    @Override public void run() {
      System.out.println("I can access the magic number: " + magicNumber);
    }
  }.start();
}

答案 6 :(得分:0)

一种选择是声明匿名类可以实现的单个抽象类:

public interface IDontWorkForSomeReasonThread {
    public void NoNoYouCantCallMe(String s);
}

public static abstract class MyAbstractThread 
extends Thread 
implements IDontWorkForSomeReasonThread { }

public static void main (String[] args) throws java.lang.Exception {
    IDontWorkForSomeReasonThread t = new MyAbstractThread() {
      public void NoNoYouCantCallMe(String s){}
    };

    t.NoNoYouCantCallMe( "foo" );
}