잘못된 순방향 참조 및 열거 형
타일 그리드로 구성된 자바 게임을 프로그래밍하고 있습니다. 타일의 가장자리를 직관적으로 정의하고 타일이 서로 관련되는 방식을 정의 할 수 있기를 원하지 않습니다. 예를 들어 타일의 반대쪽 가장자리를 가져 오려면을 입력하기 만하면됩니다 TOP.opposite(). 그러나 열거 형을 사용하여 이러한 가장자리를 정의 할 때 생성자에서 적어도 두 개 이상의 참조를 전달해야합니다.
public enum Edge {
TOP(Edge.BOTTOM), //illegal forward reference
BOTTOM(Edge.TOP),
LEFT(Edge.RIGHT), //illegal forward reference
RIGHT(Edge.LEFT);
private Edge opposite;
private Edge(Edge opp){
this.opposite = opp;
}
public Edge opposite(){
return this.opposite;
}
}
간단한 열거 형을 사용하여이 문제를 해결할 수있는 방법이 있습니까?
직관적이지 않은 작업을 수행 할 수 있습니다.
public enum Edge {
TOP, BOTTOM, LEFT, RIGHT;
private Edge opposite;
static {
TOP.opposite = BOTTOM;
BOTTOM.opposite = TOP;
LEFT.opposite = RIGHT;
RIGHT.opposite = LEFT;
}
public Edge opposite(){
return this.opposite;
}
}
enum Edge {
TOP {
@Override
public Edge opposite() {
return BOTTOM;
}
},
BOTTOM {
@Override
public Edge opposite() {
return TOP;
}
},
LEFT {
@Override
public Edge opposite() {
return RIGHT;
}
},
RIGHT {
@Override
public Edge opposite() {
return LEFT;
}
};
public abstract Edge opposite();
}
public enum Edge {
TOP,
BOTTOM(Edge.TOP),
LEFT,
RIGHT(Edge.LEFT);
private Edge opposite;
private Edge() {
}
private Edge(Edge opp) {
this.opposite = opp;
opp.opposite = this;
}
public Edge opposite() {
return this.opposite;
}
}
다른 방법이 있습니다.
public enum Edge {
TOP("BOTTOM"),
BOTTOM("TOP"),
LEFT("RIGHT"),
RIGHT("LEFT");
private String opposite;
private Edge(String opposite){
this.opposite = opposite;
}
public Edge opposite(){
return valueOf(opposite);
}
}
그러나 Peter Lawrey의 솔루션은 더 효율적이고 컴파일 시간이 안전합니다.
열거 형 내부에서 정적 내부 클래스를 사용할 수도 있습니다 .
public enum EnumTest
{
NORTH( Orientation.VERTICAL ),
SOUTH( Orientation.VERTICAL ),
EAST( Orientation.HORIZONTAL ),
WEST( Orientation.HORIZONTAL );
private static class Orientation
{
private static final String VERTICAL = null;
private static final String HORIZONTAL = null;
}
}
여기 에서 도난당했습니다 :)
아래와 비슷한 방법을 정의 할 수 있습니다.
public enum Edge {
TOP,
BOTTOM,
LEFT,
RIGHT;
public Edge opposite() {
switch (this) {
case TOP:
return Edge.BOTTOM;
case BOTTOM:
return Edge.TOP;
case LEFT:
return RIGHT;
case RIGHT:
return LEFT;
default:
throw new RuntimeException("Oh dear");
}
}
}
Map키가 원래 열거 형이고 값이 반대쪽 가장자리 인 정적을 만들 수 있습니다 . 정적 블록에서 초기화하고 opposite()메서드 에서 매핑을 반환합니다 .
private static Map<Edge, Edge> oppostiteMapping;
static {
oppositeMapping = new EnumMap<Edge, Edge>();
oppositeMapping.put(TOP, BOTTOM);
...
}
public Edge opposite() {
return oppositeMapping.get(this);
}
편집 : 주석에서 제안한대로 EnumMap을 사용하는 것이 더 좋으므로 그에 따라 업그레이드했습니다.
Btw. 이 접근 방식은 일반적으로 정적 fromString()메서드 등과 같은 것을 만들 때 유용합니다 .
대신 내부 맵을 사용하여 이러한 연관을 정의 할 수 있습니다. 이것은 맵을 초기화 할 때 이미 모든 열거 형 값이 생성 된 경우 작동합니다.
public enum Edge {
TOP,
BOTTOM,
LEFT,
RIGHT;
private static final Map<Edge, Edge> opposites =
new EnumMap<Edge, Edge>(Edge.class);
static {
opposites.put(TOP, BOTTOM);
opposites.put(BOTTOM, TOP);
opposites.put(LEFT, RIGHT);
opposites.put(RIGHT, LEFT);
}
public Edge opposite(){
return opposites.get(this);
}
}
내 방법은 서수를 사용하는 것입니다. 이것은 간단한 예이지만 훨씬 더 복잡한 예는 아래를 참조하십시오.
public enum Edge {
// Don't change the order! This class uses ordinal() in an arithmetic context.
TOP, // = 0
LEFT, // = 1
RIGHT, // = 2
BOTTOM; // = 3
public Edge other() {
return values()[3 - ordinal()];
}
}
서수를 사용하는 것은 취약하기 때문에 권장되지 않지만에 정의 된 것과 동일한 열거 형에서 서수를 사용하는 것은 취약하지 않으며 여기에서 주석으로 더 완화됩니다. 위의 예는 매우 사소하지만 다음 예는 덜합니다. 원래 방식과 서수를 사용하는 방식을 비교합니다.
98 개 노선에서 :
public enum Axes {
NONE,
HORIZONTAL,
VERTICAL,
BOTH;
public Axes add(Axes axes) {
switch (axes) {
case HORIZONTAL:
if (this == NONE)
return HORIZONTAL;
if (this == VERTICAL)
return BOTH;
break;
case VERTICAL:
if (this == NONE)
return VERTICAL;
if (this == HORIZONTAL)
return BOTH;
break;
case BOTH:
return BOTH;
default:
throw new AssertionError(axes);
}
return this;
}
public Axes remove(Axes axes) {
switch (axes) {
case HORIZONTAL:
if (this == HORIZONTAL)
return NONE;
if (this == BOTH)
return VERTICAL;
break;
case VERTICAL:
if (this == VERTICAL)
return NONE;
if (this == BOTH)
return HORIZONTAL;
break;
case BOTH:
return NONE;
default:
throw new AssertionError(axes);
}
return this;
}
public Axes toggle(Axes axes) {
switch (axes) {
case NONE:
return this;
case HORIZONTAL:
switch (this) {
case NONE:
return HORIZONTAL;
case HORIZONTAL:
return NONE;
case VERTICAL:
return BOTH;
case BOTH:
return VERTICAL;
default:
throw new AssertionError(axes);
}
case VERTICAL:
switch (this) {
case NONE:
return VERTICAL;
case HORIZONTAL:
return BOTH;
case VERTICAL:
return NONE;
case BOTH:
return HORIZONTAL;
default:
throw new AssertionError(axes);
}
case BOTH:
switch (this) {
case NONE:
return BOTH;
case HORIZONTAL:
return VERTICAL;
case VERTICAL:
return HORIZONTAL;
case BOTH:
return NONE;
default:
throw new AssertionError(axes);
}
default:
throw new AssertionError(axes);
}
}
}
19 개 라인 :
public enum Axes {
// Don't change the order! This class uses ordinal() as a 2-bit bitmask.
NONE, // = 0 = 0b00
HORIZONTAL, // = 1 = 0b01
VERTICAL, // = 2 = 0b10
BOTH; // = 3 = 0b11
public Axes add(Axes axes) {
return values()[ordinal() | axes.ordinal()];
}
public Axes remove(Axes axes) {
return values()[ordinal() & ~axes.ordinal()];
}
public Axes toggle(Axes axes) {
return values()[ordinal() ^ axes.ordinal()];
}
}
나는 이것을 선호했다 :
public enum Edge {
TOP,
BOTTOM,
LEFT,
RIGHT;
private Link link;
private Link getLink() {
if (link == null) {
link = Link.valueOf(name());
}
return link;
}
public Edge opposite() {
return getLink().opposite();
}
}
public enum Link {
TOP(Edge.BOTTOM),
BOTTOM(Edge.TOP),
LEFT(Edge.RIGHT),
RIGHT(Edge.LEFT);
private Edge opposite;
private Link(Edge opp) {
this.opposite = opp;
}
public Edge opposite() {
return this.opposite;
}
}
Java 8 람다 사용 :
public enum Edge {
TOP(() -> Edge.BOTTOM),
BOTTOM(() -> Edge.TOP),
LEFT(() -> Edge.RIGHT),
RIGHT(() -> Edge.LEFT);
private Supplier<Edge> opposite;
private Edge(Supplier<Edge> opposite) {
this.opposite = opposite;
}
public Edge opposite() {
return opposite.get();
}
}
참조 URL : https://stackoverflow.com/questions/5678309/illegal-forward-reference-and-enums
'Program Club' 카테고리의 다른 글
| Javascript | jQuery로 특정 인라인 스타일 제거 (0) | 2020.12.15 |
|---|---|
| 루비 날짜를 정수로 변환 (0) | 2020.12.15 |
| C ++에서 "this"키워드 사용 (0) | 2020.12.15 |
| Highcharts 차트 최대 yAxis 값을 설정하는 방법 (0) | 2020.12.15 |
| 헤드리스 모드에서 Chrome을 시작하는 방법은 없나요? (0) | 2020.12.15 |