Question

I'm just curious. Is there a way to access parent in anonymous class that is inside another anonymous class?

I make this example create a JTable subclass (anonymous class) override changeSelection and inside i create another anonymous class.

MCVE:

public class Test{

    public static void main(String args []){

        JTable table = new JTable(){

            @Override
            public void changeSelection(
                final int row, final int column,
                final boolean toggle, final boolean extend) {

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        super.changeSelection(row, column, toggle, extend); 
                        //more code here
                    }
                });
            }
        };

    }//end main

}//end test 

How can i refer to super.changeSelection(..) ?

Was it helpful?

Solution

Unfortunately, you will have to give a name to the outer anonymous class:

public class Test{

    public static void main(String args []){

        class Foo extends JTable {

            @Override
            public void changeSelection(
                final int row, final int column,
                final boolean toggle, final boolean extend) {

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        Foo.super.changeSelection(row, column, toggle, extend); 
                        //more code here
                    }
                });
            }
        };

        JTable table = new Foo();

    }//end main

}//end test 

OTHER TIPS

In your context, 'super', of course, refers to the Runnable base, not the JTable base. As you know, using 'super' in an inner class refers to the superclass of that inner class, not the superclass of its enclosing class (it does not matter if it's anonymous or not). Since you want to call a method of the JTable base, you must use 'super' in the context of one of the JTable subclass methods.

You could create a new method in your JTable subclass, e.g. jTableBaseChangeSelection(), that calls the JTable's changeSelection() that you are intending to call. Then you call that from the Runnable subclass:

public static void main(String args []){

    JTable table = new JTable(){

        // calls JTable's changeSelection, for use by the Runnable inner
        // class below, which needs access to the base JTable method.
        private void jTableBaseChangeSelection (int row, int column, boolean toggle, boolean extend) {
            super.changeSelection(row, column, toggle, extend);
        }

        @Override
        public void changeSelection(
            final int row, final int column,
            final boolean toggle, final boolean extend) {

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    // call JTable base changeSelection, since we don't have access
                    // to the JTable base class at this point.
                    jTableBaseChangeSelection(row, column, toggle, extend); 
                    //more code here
                }
            });
        }
    };

}//end main

Please note, this answer is attempting to retain your original design of an anonymous enclosing class. There are certainly reasons for doing that (and yes, quickly putting together some code is a valid reason in some cases). Having a few isolated situations where this happens -- no harm done; however, you may still wish to rethink your design if you find yourself getting into situations like this often.

I think you can create outer reference and use it in your anonymous inner. At least that works for me on JDK 1.7 and JDK 1.8.

public class Test{

        public static void main(String args []){

            class Foo extends JTable {

                @Override
                public void changeSelection(
                    final int row, final int column,
                    final boolean toggle, final boolean extend) {
                    final Foo outer = this; // reference to itself

                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            outer.changeSelection(row, column, toggle, extend); 
                            //more code here
                        }
                    });
                }
            };

            JTable table = new Foo();

        }//end main

 }//end test 

I think the code below will do what is technically being asked. That said, I wouldn't recommend going this route when simpler options are available.

I'm sure you will want your run method to do something more interesting than print "Hello World!" in an infinite loop, but this seemed ok for a proof-of-concept.

package test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.swing.JTable;
import javax.swing.SwingUtilities;

public class GetOuterAnonymousClass {

    public static void main(String args []){

        JTable table = new JTable(){

            @Override
            public void changeSelection(
                final int row, final int column,
                final boolean toggle, final boolean extend) {
                Runnable runnable = new Runnable() {
                    private Object caller;
                    public void setCaller(Object caller){
                        this.caller = caller;
                    }

                    @Override
                    public void run() {
                        System.out.println("Hello World!");
                        try {
                            Class clazz = this.getClass().getEnclosingClass();
                            Method method = clazz.getDeclaredMethod("changeSelection", new Class[]{Integer.TYPE, Integer.TYPE, Boolean.TYPE, Boolean.TYPE});
                            method.invoke(caller, 1, 1, true, true);
                        } catch (SecurityException e) {
                            e.printStackTrace();
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalArgumentException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                };
                Method method;
                try {
                    method = runnable.getClass().getDeclaredMethod("setCaller", new Class[]{Object.class});
                    method.invoke(runnable, this);
                } catch (SecurityException e1) {
                    e1.printStackTrace();
                } catch (NoSuchMethodException e1) {
                    e1.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
                SwingUtilities.invokeLater(runnable);
            }
        };
        table.changeSelection(1, 1, true, true);

    }

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top