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

问题描述 投票:0回答:8

是否有任何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!
    }


}

我自己的解决方案

我刚刚将所有方法和成员移至外部类。

java syntax inner-classes member
8个回答
27
投票

一旦匿名类实例被隐式转换为命名类型,它就无法被转换回来,因为匿名类型没有名称。您可以通过类内的

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;
}

17
投票

我班上的一个学生前几天问我们的教授是否可以这样做。这是我写的一个很酷的概念证明,它可以完成,虽然不值得,但实际上是可能的,方法如下:

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类,我们可以通过传入方法的字符串值和参数来调用方法。字段也可以做同样的事情。

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


5
投票

有趣的是,现在

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。 :-)

我在这里发现了更多关于

var
和匿名类的技巧:https://blog.codefx.org/java/tricks-var-anonymous-classes/


3
投票

您的调用者知道

listener
ActionListener
,因此它对这个新方法一无所知。我认为做到这一点的唯一方法(除了进行反射体操,这确实会破坏使用匿名类的目的,即快捷方式/简单性)是简单地子类化
ActionListener
并且不使用匿名类。


1
投票

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


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);
    }  
}

您可以在此处查看:当以字符串形式给出方法名称时,如何调用 Java 方法?


0
投票

是的,您可以访问匿名内部类中定义的新方法。下面是一个演示如何执行此操作的示例。

示例代码:

public class Demo {

public static void main(String[] args) {

    A obj2A = new A() {

        int apple;
        int anonymous;

        public int getApple() {
            System.out.println("new Apple is :" + this.apple);
            return this.apple;
        }

        public void setApple(int apple) {
            this.apple = apple;
        }

        private int getAnonymous() {
            System.out.println(" Anonymous is :" + this.anonymous);
            return this.anonymous;
        }

        private String setAnonymous(int anonymous) {
            this.anonymous = anonymous;
            return "anonymous is set to:";

        }

        @Override
        public String toString() {
            return setAnonymous(20) + getAnonymous();
        }

    };
    System.out.print("Old "); 
    obj2A.setApple((objA.getApple() - 2));
    obj2A.getApple();
    obj2A.toString();

}

}

A类{ 公共int苹果;

public int getApple() {
    System.out.println("Apple is :" + this.apple);
    return this.apple;
}

public void setApple(int apple) {
    this.apple = apple;
}

}

说明 匿名内部类:在此代码中,创建了扩展 A 的匿名内部类的实例。这允许添加父类中未定义的新方法(getAnonymous()和setAnonymous(int))。

方法访问:可以通过匿名类(obj2A)的实例来访问新方法。 setAnonymous(int) 方法设置匿名字段的值,而 getAnonymous() 方法检索它。

使用 toString():重写的 toString() 方法调用这两个新方法,演示了匿名内部类的封装行为。

输出示例 当您运行代码时,您将看到以下输出: 旧的新苹果是:15 苹果是:15 匿名设置为:20

结论 此示例清楚地表明您可以在匿名内部类中定义和访问新方法。代码的结构说明了如何有效地利用这些方法。


-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();
    }
  }
© www.soinside.com 2019 - 2024. All rights reserved.