从内部匿名类访问外部匿名类的方法

Rul*_*lle 22 java methods anonymous-class java-8 method-reference

我使用一个实例化另一个匿名类的方法实例化一个匿名类,并且从这个内部匿名类我想调用一个属于外部匿名类的方法.为了说明它,假设我有这个界面:

interface ReturnsANumber {
    int getIt();
}
Run Code Online (Sandbox Code Playgroud)

然后,在我的代码中的某个地方,我这样做:

    ReturnsANumber v = new ReturnsANumber() {
            int theNumber() {
                return 119;
            }

            public int getIt() {

                // In a modern version of Java, maybe I could do
                //   var a = this;
                // and then call a.theNumber();

                ReturnsANumber w = new ReturnsANumber() {
                        int theNumber() {
                            return 1;
                        }

                        public int getIt() {
                            return this.theNumber();
                        }
                    };

                return w.getIt();
            }
        };
    System.out.println("The number is " + v.getIt());
Run Code Online (Sandbox Code Playgroud)

问题: 在最里面的方法中getIt,我想调用theNumber()属于最外层的匿名类.如何在不使用Java 10 var功能的情况下实现这一目标(如代码中所示).

澄清:理想情况下,外部匿名类不应该知道内部类想要调用它的theNumber方法.我们的想法是提出一些代码,让内部类明确地调用外部类的任何方法.

换句话说,如何显示此代码:( The number is 119 而不是显示The number is 1)

动机:有人可能会问我为什么要这样做:我正在编写某种代码生成器,并希望确保我生成的代码不是模棱两可的.

ETO*_*ETO 16

从Java 8开始,解决方案非常简单.只需将方法引用存储在变量中.

ReturnsANumber v = new ReturnsANumber() {
        int theNumber() {
            return 119;
        }

        public int getIt() {

            Supplier<Integer> supplier = this::theNumber;

            ReturnsANumber w = new ReturnsANumber() {
                int theNumber() {
                    return 1;
                }

                public int getIt() {
                    return supplier.get();
                }
            };

            return w.getIt();
        }
    };
Run Code Online (Sandbox Code Playgroud)

存储外部对象也可以解决问题.但仅限于继承方法:

interface ReturnsANumber {
    int theNumber();
    int getIt();
}

public int getIt() {
    ReturnsANumber outer = this;

    ReturnsANumber w = new ReturnsANumber() {
        public int theNumber() {
            return 1;
        }

        public int getIt() {
            return  outer.theNumber();
        }
     };

     return w.getIt();
 }
Run Code Online (Sandbox Code Playgroud)

您也可以将方法引用或外部对象存储为字段.

更新

@Holger提出了另一种解决方法.您可以将外部对象传递给lambda:

ReturnsANumber v = new ReturnsANumber() {
    ...
    @Override
    public int getIt() {
        ReturnsANumber w = Optional.of(this).map(outer ->
                new ReturnsANumber() {
                    int theNumber() {
                        return 1;
                    }
                    public int getIt() {
                        return outer.theNumber();
                    }
                }).get();
        return w.getIt();
    }
};
Run Code Online (Sandbox Code Playgroud)


ern*_*t_k 13

访问封闭的匿名类没有关键字.

但是一个解决方案可能是在外部匿名类中代理该方法并进行非限定引用:

ReturnsANumber v = new ReturnsANumber() {


    int theNumber() {
        return 119;
    }

    //Just a different name for theNumber()
    int theNumberProxy() {
        return theNumber();
    }

    public int getIt() {

        ReturnsANumber w = new ReturnsANumber() {
                int theNumber() {
                    return 1;
                }

                public int getIt() {
                    return theNumberProxy(); //calls enclosing class's method
                }
            };

        return w.getIt();
    }
};
Run Code Online (Sandbox Code Playgroud)

这种操作的必要性应足以证明你的班级结构不理想,可能是一个维护陷阱.例如,您可以简单地用嵌套的静态类替换第一个匿名类.


Ort*_*ier 5

如果可以扩展接口:

public class Test {

    interface ReturnsANumber {
        int theNumber();
        int getIt();
    }

    public static void main(String[] args) {
        ReturnsANumber v = new ReturnsANumber() {

            public int theNumber() {
                return 119;
            }

            public int getIt() {

                final ReturnsANumber that = this;

                // In a modern version of Java, maybe I could do
                //   var a = this;
                // and then call a.theNumber();

                ReturnsANumber w = new ReturnsANumber() {
                    public int theNumber() {
                        return 1;
                    }

                    public int getIt() {
                        return that.theNumber();
                    }
                };

                return w.getIt();
            }
        };

        System.out.println("The number is " + v.getIt());
    }
}
Run Code Online (Sandbox Code Playgroud)