Доступ к внешнему анонимному классу из внутреннего анонимного класса

Мне просто интересно. Есть ли способ доступа к родительскому элементу в анонимном классе, который находится внутри другого анонимного класса?

Я делаю этот пример, создаю подкласс 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(..)?

Ответ 1

К сожалению, вам нужно будет присвоить имя внешнему анонимному классу:

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 

Ответ 2

В вашем контексте "супер" , конечно, относится к базе Runnable, а не к базе JTable. Как вы знаете, использование "супер" во внутреннем классе относится к суперклассу этого внутреннего класса, а не к суперклассу его охватывающего класса (неважно, анонимно или нет). Поскольку вы хотите вызвать метод базы JTable, вы должны использовать "супер" в контексте одного из методов подкласса JTable.

Вы можете создать новый метод в своем подклассе JTable, например. jTableBaseChangeSelection(), который вызывает JTable changeSelection(), который вы намереваетесь вызывать. Затем вы вызываете это из подкласса Runnable:

public static void main(String args []){

    JTable table = new JTable(){

        // calls JTable 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

Обратите внимание, что этот ответ пытается сохранить ваш первоначальный дизайн анонимного закрывающего класса. Разумеется, есть причины для этого (и да, быстро составление некоторого кода в некоторых случаях является веской причиной). Имея несколько изолированных ситуаций, когда это происходит - никакого вреда; тем не менее, вы все равно можете переосмыслить свой дизайн, если часто встречаетесь с такими ситуациями.

Ответ 3

Я думаю, что приведенный ниже код будет делать то, что технически задают. Тем не менее, я бы не стал рекомендовать этот маршрут, когда доступны более простые варианты.

Я уверен, что вы захотите, чтобы ваш метод запуска делал что-то более интересное, чем печать "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);

    }

}

Ответ 4

Я думаю, вы можете создать внешнюю ссылку и использовать ее в своем анонимном внутреннем. По крайней мере, это работает для меня на 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