从内部匿名类访问外部匿名类

时间:2013-08-05 16:19:45

标签: java anonymous-class

我只是好奇。有没有办法访问另一个匿名类中的匿名类中的父级?

我让这个例子创建一个JTable子类(匿名类)覆盖changeSelection并在里面创建另一个匿名类。

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 

我如何参考super.changeSelection(..)

4 个答案:

答案 0 :(得分:13)

不幸的是,您必须为外部匿名类命名:

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 

答案 1 :(得分:4)

在您的上下文中,'super'当然是指Runnable基础,而不是JTable基础。如您所知,在内部类中使用“super”是指该内部类的超类,而不是其封闭类的超类(如果它是匿名的,则无关紧要)。由于您要调用JTable基类的方法,因此必须在其中一个JTable子类方法的上下文中使用“super”。

您可以在JTable子类中创建一个新方法,例如: jTableBaseChangeSelection(),它调用您打算调用的JTable的changeSelection()。然后从Runnable子类中调用它:

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

请注意,这个答案是试图保留匿名封闭类的原始设计。这样做肯定有理由(是的,在某些情况下,快速将某些代码放在一起 是一个正当理由)。有一些孤立的情况发生这种情况 - 没有造成伤害;但是,如果您发现自己经常遇到这样的情况,您可能仍希望重新考虑您的设计。

答案 2 :(得分:0)

我认为下面的代码将执行技术上的要求。也就是说,当更简单的选项可用时,我不建议使用这条路线。

我确信你会希望你的run方法做一些比打印“Hello World!”更有趣的事情。在一个无限循环中,但这似乎可以用于概念验证。

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

    }

}

答案 3 :(得分:0)

我认为您可以创建外部引用并在匿名内部使用它。至少在JDK 1.7和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