如何才能使用“<”比较两个枚举值?

28
如果枚举实现了Comparable接口,那么为什么不能使用<或>进行比较?
public class Dream    
{
    public static void main(String... args)
    {
        System.out.println(PinSize.BIG == PinSize.BIGGER); //false
        System.out.println(PinSize.BIG == PinSize.BIG); //true
        System.out.println(PinSize.BIG.equals(PinSize.BIGGER));//false
        System.out.println(PinSize.BIG > PinSize.BIGGERER);// compilation error
        //can't be compared
        System.out.println(PinSize.BIG.toString().equals(PinSize.BIGGER));// #4
        PinSize b = PinSize.BIG ;
        System.out.println( b instanceof Comparable);// true
    }  
}
enum PinSize { BIG, BIGGER, BIGGERER };

这个问题与SCJP/OCPJP有什么关系? - Joachim Sauer
这是考试主题中的一部分: 第一节:声明,初始化和作用域
  • 开发声明类(包括抽象类和所有形式的嵌套类),接口和枚举的代码,并包括适当使用包和导入语句(包括静态导入)。
  • 开发声明,初始化和使用基本类型,数组,枚举和对象作为静态,实例和局部变量的代码。此外,使用合法的标识符作为变量名。
- Joe
3个回答

47

你可以这样做:

PinSize.BIGGEST.ordinal() > PinSize.BIG.ordinal()  // evaluates to `true`

当然,前提是假设在枚举中声明BIGGESTBIG之后。枚举中的序号值会隐式地与声明顺序相关联,默认情况下,第一个值分配值0,第二个值分配值1,以此类推。

因此,如果您像这样声明枚举,程序将正常工作:

public enum PinSize {
    SMALLEST,  // ordinal value: 0
    SMALL,     // ordinal value: 1
    NORMAL,    // ordinal value: 2
    BIG,       // ordinal value: 3
    BIGGER,    // ordinal value: 4
    BIGGEST;   // ordinal value: 5
}

PinSize.BIGGEST是一个引用变量,类似于int[] array;这样的变量,这种说法正确吗? - BartoszMiller
1
@miller.bartek PinSize.BIGGEST是一个枚举值,将其与数组进行比较是不正确的。而且,在Java中,所有指向对象(包括枚举和数组)的变量都是引用。 - Óscar López
那么,可以这样说吗?由于PinSize.BIGGEST是一个引用(表示内存中的地址),因此不可能使用'<'或'>'运算符进行比较。比较内存地址没有意义,对于所有其他引用(Object、String、int[]等)也是如此。 - BartoszMiller
1
@miller.bartek 没错,你不能使用<>比较引用。这些操作符仅适用于基本类型,如intfloat等。如果需要比较引用,请使用实现了Comparator的方法compareTo() - Óscar López
我认为我更喜欢使用b1.compareTo(b2)而不是比较ordinal()的结果,因为在Enum.ordinal javadoc中指出:“大多数程序员不会使用此方法。它是为复杂的基于枚举的数据结构(例如EnumSet和EnumMap)设计的。” 在Josh Bloch的第二版31项中对此进行了更多的思考(虽然没有特别涉及< / >的情况)。 - Joshua Goldberg

19

实现 Comparable 并不意味着你可以使用 <>。你只能用这些符号来比较数字。

实现 Comparable 意味着有一个compareTo() 方法。试试这个:

System.out.println(PinSize.BIG.compareTo(PinSize.BIGGER));

compareTo() 方法将返回一个整数,该整数小于、等于或大于0,取决于哪个值更"大"。对于枚举值而言,"大小"取决于枚举值定义的顺序。


2

这些答案很好地解释了问题,但我想添加我的见解,因为我觉得它们没有回答“为什么无法与<或>进行比较”的问题。问题归结为比较引用。PinSize.BIGGEST和PinSize.BIGGERER是引用变量。与以下内容相同:

String s;
int[] array;
MyObject myObject;

它们代表内存中的地址。此外,枚举是单例的,因此始终存在一个指定类型的对象。正因为如此,下面的代码行是允许的,并返回true。

System.out.println(PinSize.BIG == PinSize.BIG); //true

试图比较内存中一个地址是否大于或小于另一个地址是不可能的。实现Comparable接口和compareTo()方法可以提供自定义比较对象而不是内存中的地址。

System.out.println(PinSize.BIG > PinSize.BIGGERER); // not possible

2
指针比较确实没有任何意义,但问题归结为为什么Java没有将a < b定义为等同于a.compareTo(b) < 0。(我不知道除了“与其他语言元素的意外交互”之外是否有任何令人信服的理由适用于Java。) - toolforger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接