考虑以下sscce
public enum Flippable
A (Z), B (Y), Y (B), Z (A);
private final Flippable opposite;
private Flippable(Flippable opposite) {
this.opposite = opposite;
}
public Flippable flip() {
return opposite;
}
}
这不会编译,因为Z
和Y
未被声明为允许A
和B
的构造函数的参数。
潜在解决方案1: 硬编码方法
public enum Flippable {
A {
public Flippable flip() { return Z; }
}, B {
public Flippable flip() { return Y; }
}, Y {
public Flippable flip() { return B; }
}, Z {
public Flippable flip() { return A; }
};
public abstract Flippable flip();
}
虽然功能齐全,但在风格上看起来相当粗糙。虽然我无法理解为什么这会成为一个真正的问题。
潜在解决方案2: 静态加载
public enum Flippable {
A, B, Y, Z;
private Flippable opposite;
static {
for(Flippable f : Flippable.values()) {
switch(f) {
case A:
f.opposite = Z;
break;
case B:
f.opposite = Y;
break;
case Y:
f.opposite = B;
break;
case Z:
f.opposite = A;
break;
}
}
}
public Flippable flip() {
return opposite;
}
}
这比第一个解决方案更加严重,因为该领域不再是最终的,并且容易受到反思。最终这是一个模糊的担忧,但暗示代码味道不好。
有没有办法与第一个示例基本相同,但是编译正确?
答案 0 :(得分:12)
也许不像你想要的那样漂亮......
public enum Flippable {
A, B, Z, Y;
static {
A.opposite = Z;
B.opposite = Y;
Y.opposite = B;
Z.opposite = A;
}
public Flippable flip() {
return opposite;
}
private Flippable opposite;
public static void main(String[] args) {
for(Flippable f : Flippable.values()) {
System.out.println(f + " flips to " + f.flip());
}
}
}
答案 1 :(得分:3)
正如您所看到的那样,由于枚举常量是静态的,因此无法初始化A
,直到Z
未初始化为止。
所以这个技巧应该有效:
public enum Flippable {
A ("Z"), B ("Y"), Y ("B"), Z ("A");
private final String opposite;
private Flippable(String opposite) {
this.opposite = opposite;
}
public Flippable flip() {
return valueOf(opposite);
}
}
答案 2 :(得分:2)
只是映射对立面:
import java.util.*;
public enum Flippable
{
A, B, Y, Z;
private static final Map<Flippable, Flippable> opposites;
static
{
opposites = new EnumMap<Flippable, Flippable>(Flippable.class);
opposites.put(A, Z);
opposites.put(B, Y);
opposites.put(Y, B);
opposites.put(Z, A);
// integrity check:
for (Flippable f : Flippable.values())
{
if (f.flip().flip() != f)
{
throw new IllegalStateException("Flippable " + f + " inconsistent.");
}
}
}
public Flippable flip()
{
return opposites.get(this);
}
public static void main(String[] args)
{
System.out.println(Flippable.A.flip());
}
}
编辑:切换到EnumMap
答案 3 :(得分:0)
好问题。也许你会喜欢这个解决方案:
public class Test {
public enum Flippable {
A, B, Y, Z;
private Flippable opposite;
static {
final Flippable[] a = Flippable.values();
final int n = a.length;
for (int i = 0; i < n; i++)
a[i].opposite = a[n - i - 1];
}
public Flippable flip() {
return opposite;
}
}
public static void main(final String[] args) {
for (final Flippable f: Flippable.values()) {
System.out.println(f + " opposite: " + f.flip());
}
}
}
结果:
$ javac Test.java && java Test
A opposite: Z
B opposite: Y
Y opposite: B
Z opposite: A
$
如果你想保持实例字段“final”(这当然很好),你可以在运行时索引到数组:
public class Test {
public enum Flippable {
A(3), B(2), Y(1), Z(0);
private final int opposite;
private Flippable(final int opposite) {
this.opposite = opposite;
}
public Flippable flip() {
return values()[opposite];
}
}
public static void main(final String[] args) {
for (final Flippable f: Flippable.values()) {
System.out.println(f + " opposite: " + f.flip());
}
}
}
也可以。
答案 4 :(得分:0)
只要该字段对于枚举而言仍然是私有的,我不确定它的最终状态是否真的非常令人担忧。
也就是说,如果在构造函数中定义了相反的(它不必是!),则该条目将相反的内容转移到其自己的字段中,同时将其自身分配给相反的字段。这一切都应该很容易解决,直到决赛。
答案 5 :(得分:0)
我正在使用这个解决方案:
public enum Flippable {
A, B, Y, Z;
public Flippable flip() {
switch (this) {
case A:
return Z;
case B:
return Y;
case Y:
return B;
case Z:
return A;
default:
return null;
}
}
}
测试:
public class FlippableTest {
@Test
public void flip() throws Exception {
for (Flippable flippable : Flippable.values()) {
assertNotNull( flippable.flip() ); // ensure all values are mapped.
}
assertSame( Flippable.A.flip() , Flippable.Z);
assertSame( Flippable.B.flip() , Flippable.Y);
assertSame( Flippable.Y.flip() , Flippable.B);
assertSame( Flippable.Z.flip() , Flippable.A);
}
}
此版本更短,但灵活性有限:
public enum Flippable {
A, B, Y, Z;
public Flippable flip() {
return values()[ values().length - 1 - ordinal() ];
}
}
答案 6 :(得分:0)
以下代码编译良好,符合OP的所有要求,但在运行时失败Exception in thread "main" java.lang.ExceptionInInitializerError
。它留在这里腐烂作为所有那些偶然发现它的人不做的例子。
public enum Flippable {
A, B, Y, Z;
private final Flippable opposite;
private Flippable() {
this.opposite = getOpposite(this);
verifyIntegrity();
}
private final Flippable getOpposite(Flippable f) {
switch (f) {
case A: return Z;
case B: return Y;
case Y: return B;
case Z: return A;
default:
throw new IllegalStateException("Flippable not found.");
}
}
private void verifyIntegrity() {
// integrity check:
Arrays.stream(Flippable.values())
.forEach(f -> {
if(!f.flip().flip().equals(f)) {
throw new IllegalStateException("Flippable " + f + " is inconsistent.");
}
});
}
public Flippable flip() {
return opposite;
}
}