为何Lambda会触发非法前向引用,匿名类却不会?
Java枚举实现状态转移图的引用差异解析
我尝试用Java枚举实现状态转移图,已知可以通过Map<K, V>或枚举静态初始化块实现,但想搞明白以下几种实现的差异:
直接引用枚举常量的实现(RPS0)
enum RPS0 { ROCK(SCISSORS), PAPER(ROCK), SCISSORS(PAPER); public final RPS0 winsAgainst; RPS0(final RPS0 winsAgainst) { this.winsAgainst = winsAgainst; } }
这段代码会触发非法前向引用错误:
ScratchPad.java:150: error: illegal forward reference ROCK(SCISSORS), ^
原因是初始化时会形成循环引用,这个情况很好理解。
使用Lambda的实现(RPS1)
enum RPS1 { ROCK(() -> SCISSORS), PAPER(() -> ROCK), SCISSORS(() -> PAPER); private final Supplier<RPS1> winsAgainst; RPS1(final Supplier<RPS1> winsAgainst) { this.winsAgainst = winsAgainst; } public RPS1 winsAgainst() { return this.winsAgainst.get(); } }
这段代码同样会触发非法前向引用错误,哪怕调整Lambda的写法也无法解决。
匿名类实现(RPS2)
enum RPS2 { ROCK { public RPS2 winsAgainst() { return SCISSORS; } }, PAPER { public RPS2 winsAgainst() { return ROCK; } }, SCISSORS { public RPS2 winsAgainst() { return PAPER; } }; public abstract RPS2 winsAgainst(); }
这段代码可以正常运行,执行System.out.println(RPS2.ROCK.winsAgainst());会输出SCISSORS。
补充讨论:RPS4实现
enum RPS4 { ROCK { public RPS4 winsAgainst() { return SCISSORS; } }, PAPER { public RPS4 winsAgainst() { return ROCK; } }, SCISSORS { public RPS4 winsAgainst() { return PAPER; } }, ; public final RPS4 winsAgainst; RPS4() { this.winsAgainst = this.winsAgainst(); } public abstract RPS4 winsAgainst(); }
核心差异原因
查阅Java 19语言规范相关章节未找到明确说明,经提示得知:匿名类拥有独立的上下文,其内部对枚举常量的引用不会触发非法前向引用检查;而Lambda表达式遵循内联引用规则,和直接引用枚举常量一样,会被编译器判定为非法前向引用。
内容的提问来源于stack exchange,提问作者davidalayachew
相关产品推荐
相关产品推荐

