我可以使用一些语法访问匿名内部类中的新方法吗?

时间:2012-05-29 13:58:04

标签: java syntax inner-classes member

是否有任何Java语法可以访问外部类中匿名内部类中定义的新方法?我知道可以有各种变通方法,但我想知道是否存在特殊语法?

例如

class Outer {

    ActionListener listener = new ActionListener() {

        @Override
        void actionPerformed(ActionEvent e) { 
             // do something
        }

        // method is public so can be accessible
        public void MyGloriousMethod() {
             // viva!
        }

    };

    public void Caller() {
         listener.MyGloriousMethod(); // does not work!
    }


}

我自己的解决方案

我刚把所有方法和成员都移到了外层。

7 个答案:

答案 0 :(得分:20)

一旦匿名类实例被隐式转换为命名类型,就无法将其强制转换,因为匿名类型没有名称。您可以通过类中的this,在表达式后面的表达式中访问匿名内部类的其他成员,并且可以通过方法调用推断并返回类型。

Object obj = new Object() {
    void fn() {
        System.err.println("fn");
    }
    @Override public String toString() {
        fn();
        return "";
    } 
};
obj.toString();



new Object() {
    void fn() {
        System.err.println("fn");
    }
}.fn();


identity(new Object() {
    void fn() {
        System.err.println("fn");
    }
}).fn();
...
private static <T> T identity(T value) {
    return value;
}

答案 1 :(得分:5)

我班上的一名学生问我们的教授,这是否可以在前几天完成。以下是我作为一个很好的概念证明,它可以做到,虽然不值得,它实际上是可能的,这是如何:

public static void main(String[] args){

    //anonymous inner class with method defined inside which
    //does not override anything
    Object o = new Object()
    {
        public int test = 5;
        public void sayHello()
        {
            System.out.println("Hello World");
        }
    };

    //o.sayHello();//Does not work

    try 
    {
        Method m = o.getClass().getMethod("sayHello");
        Field f = o.getClass().getField("test");
        System.out.println(f.getInt(o));
        m.invoke(o);
    } catch (Exception e)
    {
        e.printStackTrace();
    }
}

通过使用Java的Method类,我们可以通过传入方法的字符串值和参数来调用方法。使用字段也可以完成同样的事情。

只是觉得分享这个会很酷!

答案 2 :(得分:3)

您的来电者将listener视为ActionListener,因此它对该新方法一无所知。我认为这样做的唯一方法(除了做反射体操,这实际上会破坏使用匿名类的目的,即快捷/简单)是简单地继承ActionListener而不使用匿名类。

答案 3 :(得分:1)

不,这是不可能的。您需要将ActionListener强制转换为其真正的子类名称,但由于它是匿名的,因此它没有名称。

答案 4 :(得分:1)

正确的方法是使用反射:

import java.lang.reflect.InvocationTargetException;

public class MethodByReflectionTest {

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {

        Object obj = new Object(){
            public void print(){
                System.out.println("Print executed.");
            }
        };

        obj.getClass().getMethod("print", null).invoke(obj, null);
    }  
}

您可以在此处查看:How do I invoke a Java method when given the method name as a string?

答案 5 :(得分:0)

很有趣,var构造(Java 10或更高版本)现在允许这样做。示例:

var calculator = new Object() {
  BigDecimal intermediateSum = BigDecimal.ZERO;
  void calculate(Item item) {
    intermediateSum = Numbers.add(intermediateSum, item.value);
    item.sum= intermediateSum;
  }
};
items.forEach(calculator::calculate);

这里带有方法参考,但是当然也可以与点方法调用一起使用。它也适用于字段。享受新的Java。 :-)

我在https://blog.codefx.org/java/tricks-var-anonymous-classes/

中发现了更多关于var和匿名类的技巧。

答案 6 :(得分:-2)

是的,您可以访问该方法,如果有任何疑问请参阅下面的示例请注释

package com;
interface A
{
   public void display();
}
public class Outer {
    public static void main(String []args)
    {
        A a=new A() {
        @Override
        public void display() {
            System.out.println("Hello");
        }
     };
        a.display();
    }
  }