17

Is there any Java syntax to access new methods defined within anonymous inner classes from outer class? I know there can be various workarounds, but I wonder if a special syntax exist?

For example

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


}

MY OWN SOLUTION

I just moved all methods and members up to outer class.

Suzan Cioc
  • 26,725
  • 49
  • 190
  • 355

7 Answers7

21

Once the anonymous class instance has been implicitly cast into the named type it can't be cast back because there is no name for the anonymous type. You can access the additional members of the anonymous inner class through this within the class, in the expression immediate after the expression and the type can be inferred and returned through a method call.

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;
}
Tom Hawtin - tackline
  • 139,906
  • 30
  • 206
  • 293
8

A student in my class asked our professor if this could be done the other day. Here is what I wrote as a cool proof of concept that it CAN be done, although not worth it, it is actually possible and here is how:

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

By making use of Java's Method class we can invoke a method by passing in the string value and parameters of the method. Same thing can be done with fields.

Just thought it would be cool to share this!

Matthew Lang
  • 81
  • 1
  • 1
3

Your caller knows listener as an ActionListener and therefore it doesn't know anything about that new method. I think the only way to do this (other than doing reflection gymnastics, which really would defeat the purpose of using an anonymous class, i.e. shortcut/simplicity) is to simply subclass ActionListener and not use an anonymous class.

mprivat
  • 20,572
  • 4
  • 51
  • 62
1

No, it's imposible. You would need to cast the ActionListener to its real subclass name, but since it's anonymous, it doesn't have a name.

JB Nizet
  • 633,450
  • 80
  • 1,108
  • 1,174
  • But they could create some keyword for this like `listener.that.MyGloriousMethod()` or `((Anonymous) listener).MyGloriousMethod()` since anonymous class is not actually anonymous for JVM but just it's name unknown to the programmer and so the problem is just to denote it somehow. – Suzan Cioc May 29 '12 at 14:08
  • They could have imagined something, but they didn't, because it's already doable very simply: by creating a non-anonymous inner class. – JB Nizet May 29 '12 at 14:12
1

The right way to do it is using reflection:

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

You can check here: How do I invoke a Java method when given the method name as a string?

Community
  • 1
  • 1
Paulo
  • 2,508
  • 1
  • 17
  • 30
0

Funny enough, this is now allowed with var construct (Java 10 or newer). Example:

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

Here with method reference, but works with dot method call as well, of course. It works with fields as well. Enjoy new Java. :-)

I found more tricks with var and anonymous classes here: https://blog.codefx.org/java/tricks-var-anonymous-classes/

virgo47
  • 2,061
  • 21
  • 26
-2

Yes you can access the method see the example below if any doubt please comment

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();
    }
  }
Piyush Yawalkar
  • 252
  • 3
  • 17