【问题标题】:Java Enum Methods - return opposite direction enumJava 枚举方法 - 返回相反方向的枚举
【发布时间】:2013-09-23 21:16:42
【问题描述】:

我想声明一个枚举方向,它有一个返回相反方向的方法(以下语法不正确,即无法实例化枚举,但它说明了我的观点)。这在 Java 中可行吗?

代码如下:

public enum Direction {

     NORTH(1),
     SOUTH(-1),
     EAST(-2),
     WEST(2);

     Direction(int code){
          this.code=code;
     }
     protected int code;
     public int getCode() {
           return this.code;
     }
     static Direction getOppositeDirection(Direction d){
           return new Direction(d.getCode() * -1);
     }
}

【问题讨论】:

标签: java enums enumeration


【解决方案1】:

对于那些被标题吸引的人:是的,您可以在枚举中定义自己的方法。如果您想知道如何调用这种非静态方法,您可以像使用任何其他非静态方法一样执行此操作 - 您可以在定义或继承该方法的类型实例上调用它。在枚举的情况下,此类实例只是 ENUM_CONSTANTs。

所以你只需要EnumType.ENUM_CONSTANT.methodName(arguments)


现在让我们从问题回到问题。一种解决方案可能是

public enum Direction {

    NORTH, SOUTH, EAST, WEST;

    private Direction opposite;

    static {
        NORTH.opposite = SOUTH;
        SOUTH.opposite = NORTH;
        EAST.opposite = WEST;
        WEST.opposite = EAST;
    }

    public Direction getOppositeDirection() {
        return opposite;
    }

}

现在Direction.NORTH.getOppositeDirection() 将返回Direction.SOUTH


这里有一点“hacky”的方式来说明@jedwards comment,但感觉不像第一种方法那样灵活,因为添加更多字段或更改它们的顺序会破坏我们的代码。

public enum Direction {
    NORTH, EAST, SOUTH, WEST;

    // cached values to avoid recreating such array each time method is called
    private static final Direction[] VALUES = values();

    public Direction getOppositeDirection() {
        return VALUES[(ordinal() + 2) % 4]; 
    }
}

【讨论】:

  • 我正要发起一个.values()[ordinal()] hack,但这种方法更强大
  • 你如何使用它呢?这种技术叫什么?
  • @Thufir "how do you use it" 如果您询问方法,然后像任何其他方法一样 - 您使用此方法在类的实例上调用它。 Direction 枚举类的实例是 NORTHEASTSOUTHWEST,因此您可以只使用 NORTH.getOppositeDirection(),它将返回 SOUTH。 “这种技术叫什么?”如果你问的是static{...},那么它就是static initialization block,它是第一次加载类时调用的代码(它是初始化静态的同一进程的一部分字段)。
  • @Pshemo,我想知道上面代码的 Spring 版本会如何,如果在静态块中设置的值需要从说属性文件中注入。
【解决方案2】:

对于像这样的小枚举,我发现最易读的解决方案是:

public enum Direction {

    NORTH {
        @Override
        public Direction getOppositeDirection() {
            return SOUTH;
        }
    }, 
    SOUTH {
        @Override
        public Direction getOppositeDirection() {
            return NORTH;
        }
    },
    EAST {
        @Override
        public Direction getOppositeDirection() {
            return WEST;
        }
    },
    WEST {
        @Override
        public Direction getOppositeDirection() {
            return EAST;
        }
    };


    public abstract Direction getOppositeDirection();

}

【讨论】:

  • 好主意!当您通常希望每个枚举值具有特定行为时,这也很好。
【解决方案3】:

这行得通:

public enum Direction {
    NORTH, SOUTH, EAST, WEST;

    public Direction oppose() {
        switch(this) {
            case NORTH: return SOUTH;
            case SOUTH: return NORTH;
            case EAST:  return WEST;
            case WEST:  return EAST;
        }
        throw new RuntimeException("Case not implemented");
    }
}

【讨论】:

  • 相比于返回 null ,抛出合适的 RuntimeException 的默认子句可能更好地表明在未为新添加的方向定义相反时存在程序员错误。
  • 这需要调用者处理null。它还要求维护者确保他们在每次添加新的 Direction 类型时添加一个案例。请参阅 Amir Afghani 关于使用可以被每个枚举值覆盖的抽象方法的答案,这样您就不会冒险丢失一个,并且您不必担心处理 null。
【解决方案4】:

创建一个抽象方法,并让每个枚举值覆盖它。由于您在创建时知道相反的情况,因此无需动态生成或创建它。

虽然它读起来不太好;也许switch 会更易于管理?

public enum Direction {
    NORTH(1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.SOUTH;
        }
    },
    SOUTH(-1) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.NORTH;
        }
    },
    EAST(-2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.WEST;
        }
    },
    WEST(2) {
        @Override
        public Direction getOppositeDirection() {
            return Direction.EAST;
        }
    };

    Direction(int code){
        this.code=code;
    }
    protected int code;

    public int getCode() {
        return this.code;
    }

    public abstract Direction getOppositeDirection();
}

【讨论】:

    【解决方案5】:

    是的,我们一直都这样做。你返回一个静态实例而不是一个新的对象

     static Direction getOppositeDirection(Direction d){
           Direction result = null;
           if (d != null){
               int newCode = -d.getCode();
               for (Direction direction : Direction.values()){
                   if (d.getCode() == newCode){
                       result = direction;
                   }
               }
           }
           return result;
     }
    

    【讨论】:

      【解决方案6】:
      public enum Direction {
          NORTH, EAST, SOUTH, WEST;
      
          public Direction getOppositeDirection(){
              return Direction.values()[(this.ordinal() + 2) % 4];
          }
      }
      

      枚举有一个静态值方法,它返回一个数组,该数组按照声明的顺序包含枚举的所有值。 source

      因为 NORTH 得到 1,EAST 得到 2,SOUTH 得到 3,WEST 得到 4; 你可以创建一个简单的等式来得到相反的:

      (值 + 2) % 4

      【讨论】:

      • 为什么这是答案?您希望这如何帮助未来的读者或任何人在没有任何解释的情况下学习?
      • 虽然此代码可能会回答问题,但提供有关其解决问题的方式和/或原因的附加 context 将提高答案的长期价值。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人!请编辑您的答案以添加解释,并说明适用的限制和假设。提及为什么这个答案比其他答案更合适也没有什么坏处。
      • 没有cmets就很难读代码吗?还是需要 7 行代码专用的 javadoc?
      • 这个解决方案很脆弱,因为它取决于枚举值的顺序。如果您将顺序更改为字母顺序,您的巧妙方程式将不再提供正确的对立面。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多