【发布时间】:2023-01-11 03:28:18
【问题描述】:
我正在尝试表示 State Transition Diagram,并且我想用 Java 枚举来实现。我很清楚还有许多其他方法可以使用 Map<K, V> 或我的枚举中的静态初始化块来完成此操作。但是,我试图理解为什么会发生以下情况。
这是我正在尝试做的一个(非常)简化的例子。
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),
^
没关系,我接受。尝试手动插入 SCISSORS 需要 Java 尝试设置 SCISSORS,然后触发设置 PAPER,然后触发设置 ROCK,导致无限循环。我很容易理解为什么这种直接引用是不可接受的,并且由于编译器错误而被禁止。
因此,我尝试并尝试对 lambda 做同样的事情。
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();
}
}
它因基本相同的错误而失败。
ScratchPad.java:169: error: illegal forward reference
ROCK(() -> SCISSORS),
^
我对此有点烦恼,因为我真的觉得 lambda 应该允许它不会失败。但不可否认,我对 lambda 的规则、作用域和边界的了解还不够多,因此无法得出更坚定的意见。
顺便说一句,我尝试添加花括号并返回到 lambda,但这也没有帮助。
所以,我尝试了一个匿名类。
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()); //returns "SCISSORS"
于是,我想搜索Java Language Specification for Java 19 寻找答案,但我的搜索结果一无所获。我尝试对相关短语进行 Ctrl+F 搜索(不区分大小写),例如“非法的", "向前", "参考", "枚举", "拉姆达", "匿名的“等等。这是我搜索的一些链接。也许我错过了其中可以回答我问题的内容?
他们都没有回答我的问题。有人可以帮助我理解阻止我使用 lambda 但允许匿名类的游戏规则吗?
编辑- @DidierL 指出了指向处理类似问题的another StackOverflow post 的链接。我认为对该问题的回答与我的答案相同。简而言之,匿名类有自己的“上下文”,而 lambda 则没有。因此,当 lambda 尝试获取变量/方法/等的声明时,它就像您内联执行它一样,就像我上面的 RPS0 示例一样。
这令人沮丧,但我认为,以及@Michael 的回答都已经完整地回答了我的问题。
编辑 2- 添加这个 sn-p 用于我与@Michael 的讨论。
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();
}
【问题讨论】:
-
有趣的实验。 jenkov.com/tutorials/java/lambda-expressions.html 声明“Java lambda 表达式只能在它们匹配的类型是单个方法接口的情况下使用”。所以看起来你尝试应用 lambda 的地方不是应用它的好地方。
-
@ZackMacomber 感谢您的回复。我不确定你是否正确。我匹配的接口不应该是我的
Supplier<RPS1>吗? -
很好的问题,但为简洁起见,我对其进行了编辑。我不认为你的(不幸的是没有结果)搜索真的增加了很多,我认为没有他们这是一个更好的问题。如果您强烈不同意,请随时将其添加回去,但也许可以编辑到要点。
-
@Michael 我看到了您的编辑。感谢您所做的更改。我做了一个简单的项目符号列表,列出了我尝试进行的搜索。这应该满足简洁的要求,同时让人们的支持更加知情/更有针对性。如果您觉得应该有所不同,请编辑我的编辑。
标签: java lambda enums circular-reference anonymous-class