ChatGPT解决这个技术问题 Extra ChatGPT

What's the advantage of a Java enum versus a class with public static final fields?

I am very familiar with C# but starting to work more in Java. I expected to learn that enums in Java were basically equivalent to those in C# but apparently this is not the case. Initially I was excited to learn that Java enums could contain multiple pieces of data which seems very advantageous (http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html). However, since then I have found a lot of features missing that are trivial in C#, such as the ability to easily assign an enum element a certain value, and consequently the ability to convert an integer to an enum without a decent amount of effort (i.e. Convert integer value to matching Java Enum).

So my question is this: is there any benefit to Java enums over a class with a bunch of public static final fields? Or does it just provide more compact syntax?

EDIT: Let me be more clear. What is the benefit of Java enums over a class with a bunch of public static final fields of the same type? For example, in the planets example at the first link, what is the advantage of an enum over a class with these public constants:

public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6);
public static final Planet EARTH = new Planet(5.976e+24, 6.37814e6);
public static final Planet MARS = new Planet(6.421e+23, 3.3972e6);
public static final Planet JUPITER = new Planet(1.9e+27, 7.1492e7);
public static final Planet SATURN = new Planet(5.688e+26, 6.0268e7);
public static final Planet URANUS = new Planet(8.686e+25, 2.5559e7);
public static final Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7);

As far as I can tell, casablanca's answer is the only one that satisfies this.

@Bohemian: It may not be a duplicate, since the OP only mentioned public static final fields, which may be typed values and not necessarily ints.
@Shahzeb Hardly. Clearly using enums instead of string constants is an EXTREMELY good idea and more than encouraged. Type-safety, doesn't need static utility functions, and so on.. absolutely no reason to use strings instead.
@Voo Yes I knew there will be disagreements .And here is one in 49 seconds. Enums are great (and I love them and use them very often) but What type safety do you need when declaring a constant or using it. It is an overkill to create enum every time you need to declare a constant for String literal .
@Shahzeb If you have a single variable, sure use a string, not much can happen here (a single value is rather pointless as a parameter). But note that we're talking about constantS, so now we're talking about probably passing them into functions, etc. Do we need type-saftey? Well, no, but then most people consider c-style types of "everything's a void*" good style and it can stop bugs (especially if passing more than one enum/string parameter!). Also it puts the constants into their own namespace, etc. Contrary to that, there's no real advantage to just have plain variables.
@Bohemian: I don't see how. With ints, there is no type safety because one could pass any value. Typed objects, on the other hand, are no different from enums in terms of type safety.

u
user207421

Type safety and value safety. Guaranteed singleton. Ability to define and override methods. Ability to use values in switch statement case statements without qualification. Built-in sequentialization of values via ordinal(). Serialization by name not by value, which offers a degree of future-proofing. EnumSet and EnumMap classes.


Having said all that, every time I've put code into an Enum I've regretted it.
Why did you regret it? I did never…
@glglgl Becasue it put application-specific code into a place where I felt it was didn't really belong, that was really only defining a set of values. If I had it to do again I would have included it in one of the numerous switch statements that were the original motivation for using an Enum at all.
c
casablanca

Technically one could indeed view enums as a class with a bunch of typed constants, and this is in fact how enum constants are implemented internally. Using an enum however gives you useful methods (Enum javadoc) that you would otherwise have to implement yourself, such as Enum.valueOf.


There is also .values() to iterate over the list of values.
This seems to be the right answer, although it's not very satisfying. In my opinion it was barely worthwhile for Java to add support for enums just for the more compact syntax and access to the Enum methods.
@Craig your instincts are right - this is a very bad answer, because it missed entirely the purpose of enums. See my comments under the question for part of the reasons why.
@Bohemian: I didn't "miss the purpose" of enums -- I use them all the time. See my response to your comment above.
Enum.valuesOf method does return same object if called twice?
D
Dave Newton

Nobody mentioned the ability to use them in switch statements; I'll throw that in as well.

This allows arbitrarily complex enums to be used in a clean way without using instanceof, potentially confusing if sequences, or non-string/int switching values. The canonical example is a state machine.


Anyway, You didn't mentioned any benefits from enums vs static fields, You can use enough types in switch statements with static fields. Op Need real functionals or perfomance differences
@Genaut The benefit is that enums have more functionality than a string or int-the question was about differences, which I provided. The OP is already aware of what enums are, and nobody else had mentioned switch statements when I posted this 4.5 yrs ago, and at least a few people found it provided new info ¯_(ツ)_/¯
@Genaut how do you switch over Planet instances when Planet is not an enum?
J
Jim Garrison

The primary advantage is type safety. With a set of constants, any value of the same intrinsic type could be used, introducing errors. With an enum only the applicable values can be used.

For example

public static final int SIZE_SMALL  = 1;
public static final int SIZE_MEDIUM = 2;
public static final int SIZE_LARGE  = 3;

public void setSize(int newSize) { ... }

obj.setSize(15); // Compiles but likely to fail later

vs

public enum Size { SMALL, MEDIUM, LARGE };

public void setSize(Size s) { ... }

obj.setSize( ? ); // Can't even express the above example with an enum

classes are also type safe ... :/ (assuming static field are of the type of the container class)
You could still pass it an invalid value but it would be a compile time error which is much easier to spot.
You could call setSize(null) in your second example, but it is likely to fail much sooner than the first example's error.
J
Jeffrey

There is less confusion. Take Font for instance. It has a constructor that takes the name of the Font you want, its size and its style (new Font(String, int, int)). To this day I cannot remember if style or size goes first. If Font had used an enum for all of its different styles (PLAIN, BOLD, ITALIC, BOLD_ITALIC), its constructor would look like Font(String, Style, int), preventing any confusion. Unfortunately, enums weren't around when the Font class was created, and since Java has to maintain reverse compatibility, we will always be plagued by this ambiguity.

Of course, this is just an argument for using an enum instead of public static final constants. Enums are also perfect for singletons and implementing default behavior while allowing for later customization (I.E. the strategy pattern). An example of the latter is java.nio.file's OpenOption and StandardOpenOption: if a developer wanted to create his own non-standard OpenOption, he could.


Your 'Font' case is still ambiguous if two of the same enums were asked for. The canonical answer to that problem is what many languages call Named Parameters. That or better IDE method signature support.
@aaaaaa I haven't seen many cases where a constructor would take two of the same enum without using varargs or a Set to take an arbitrary number of them.
@aaaaaa The main issue with named parameters it relies on implementation details (the name of the parameter). I can make an interface interface Foo { public void bar(String baz); }. Someone makes a class which invokes bar: someFoo.bar(baz = "hello");. I change the signature of Foo::bar to public void bar(String foobar). Now the person who called someFoo will need to modify their code if they still want it to work.
I don't remember seeing consecutive enum types either, but thought a common one might be DAY_OF_WEEK or something similar. And good point about the interface - hadn't thought of that. Personally I would take that problem over the widespread ambiguity caused by un-named parameters, necessitating stronger IDE support. I understand that's a judgement call however, and that breaking API changes are something to seriously consider.
i
icza

There are many good answers here, but none mentiones that there are highly optimized implementations of the Collection API classes/interfaces specifically for enums:

EnumSet

EnumMap

These enum specific classes only accept Enum instances (the EnumMap only accept Enums only as keys), and whenever possible, they revert to compact representation and bit manipulation in their implementation.

What does this mean?

If our Enum type has no more that 64 elements (most of real-life Enum examples will qualify for this), the implementations store the elements in a single long value, each Enum instance in question will be associated with a bit of this 64-bit long long. Adding an element to an EnumSet is simply just setting the proper bit to 1, removing it is just setting that bit to 0. Testing if an element is in the Set is just one bitmask test! Now you gotta love Enums for this!


I knew about these two before, but I just learned a lot from your What does this mean? section. I knew there was a divide in implementation at size 64, but I didn't actually know why
Might be worth mentioning that the EnumSet has the same optimizations for types containing more than 64 constants as well. It just has to use a long[] array instead of a single long. And while reducing add, remove, and contains operations to single bit operations is great, the real fun starts with operations like addAll, removeAll, and retainAll which do not go bit by bit but process 64 elements (in other words, all of them, usually) at once.
P
Pang

example:

public class CurrencyDenom {
   public static final int PENNY = 1;
 public static final int NICKLE = 5;
 public static final int DIME = 10;
public static final int QUARTER = 25;}

Limitation of java Constants

1) No Type-Safety: First of all it’s not type-safe; you can assign any valid int value to int e.g. 99 though there is no coin to represent that value.

2) No Meaningful Printing: printing value of any of these constant will print its numeric value instead of meaningful name of coin e.g. when you print NICKLE it will print "5" instead of "NICKLE"

3) No namespace: to access the currencyDenom constant we need to prefix class name e.g. CurrencyDenom.PENNY instead of just using PENNY though this can also be achieved by using static import in JDK 1.5

Advantage of enum

1) Enums in Java are type-safe and has there own name-space. It means your enum will have a type for example "Currency" in below example and you can not assign any value other than specified in Enum Constants.

public enum Currency {PENNY, NICKLE, DIME, QUARTER};

Currency coin = Currency.PENNY; coin = 1; //compilation error

2) Enum in Java are reference type like class or interface and you can define constructor, methods and variables inside java Enum which makes it more powerful than Enum in C and C++ as shown in next example of Java Enum type.

3) You can specify values of enum constants at the creation time as shown in below example: public enum Currency {PENNY(1), NICKLE(5), DIME(10), QUARTER(25)}; But for this to work you need to define a member variable and a constructor because PENNY (1) is actually calling a constructor which accepts int value , see below example.

public enum Currency {
    PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
    private int value;

    private Currency(int value) {
            this.value = value;
    }
}; 

Reference: https://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html


佚名

The first benefit of enums, as you have already noticed, is syntax simplicity. But the main point of enums is to provide a well-known set of constants which, by default, form a range and help to perform more comprehensive code analysis through type & value safety checks.

Those attributes of enums help both a programmer and a compiler. For example, let's say you see a function that accepts an integer. What that integer could mean? What kind of values can you pass in? You don't really know right away. But if you see a function that accepts enum, you know very well all possible values you can pass in.

For the compiler, enums help to determine a range of values and unless you assign special values to enum members, they are well ranges from 0 and up. This helps to automatically track down errors in the code through type safety checks and more. For example, compiler may warn you that you don't handle all possible enum values in your switch statement (i.e. when you don't have default case and handle only one out of N enum values). It also warns you when you convert an arbitrary integer into enum because enum's range of values is less than integer's and that in turn may trigger errors in the function that doesn't really accept an integer. Also, generating a jump table for the switch becomes easier when values are from 0 and up.

This is not only true for Java, but for other languages with a strict type-checking as well. C, C++, D, C# are good examples.


P
Peter Lawrey

An enum is implictly final, with a private constructors, all its values are of the same type or a sub-type, you can obtain all its values using values(), gets its name() or ordinal() value or you can look up an enum by number or name.

You can also define subclasses (even though notionally final, something you can't do any other way)

enum Runner implements Runnable {
    HI {
       public void run() {
           System.out.println("Hello");
       }
    }, BYE {
       public void run() {
           System.out.println("Sayonara");
       }
       public String toString() {
           return "good-bye";
       }
    }
 }

 class MYRunner extends Runner // won't compile.

To add on to this answer, you can also have a "default" implementation of any method defined in the interface. That way, not every enum needs to have the curly braces and a method implementation. You can simply provide an inline implementation for the enum values that need it.
N
Nico Haase

enum Benefits:

Enums are type-safe, static fields are not There is a finite number of values (it is not possible to pass non-existing enum value. If you have static class fields, you can make that mistake) Each enum can have multiple properties (fields/getters) assigned - encapsulation. Also some simple methods: YEAR.toSeconds() or similar. Compare: Colors.RED.getHex() with Colors.toHex(Colors.RED)

"such as the ability to easily assign an enum element a certain value"

enum EnumX{
  VAL_1(1),
  VAL_200(200);
  public final int certainValue;
  private X(int certainValue){this.certainValue = certainValue;}
}

"and consequently the ability to convert an integer to an enum without a decent amount of effort" Add a method converting int to enum which does that. Just add static HashMap containing the mapping.

If you really want to convert ord=VAL_200.ordinal() back to val_200 just use: EnumX.values()[ord]


C
Community

You get compile time checking of valid values when you use an enum. Look at this question.


P
Premraj

The biggest advantage is enum Singletons are easy to write and thread-safe :

public enum EasySingleton{
    INSTANCE;
}

and

/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
     private volatile DoubleCheckedLockingSingleton INSTANCE;

     private DoubleCheckedLockingSingleton(){}

     public DoubleCheckedLockingSingleton getInstance(){
         if(INSTANCE == null){
            synchronized(DoubleCheckedLockingSingleton.class){
                //double checking Singleton instance
                if(INSTANCE == null){
                    INSTANCE = new DoubleCheckedLockingSingleton();
                }
            }
         }
         return INSTANCE;
     }
}

both are similar and it handled Serialization by themselves by implementing

//readResolve to prevent another instance of Singleton
    private Object readResolve(){
        return INSTANCE;
    }

more


P
Pang

Another important difference is that java compiler treats static final fields of primitive types and String as literals. It means these constants become inline. It's similar to C/C++ #define preprocessor. See this SO question. This is not the case with enums.


B
Basil Bourque

Enums can be local

As of Java 16, an enum can be defined locally (within a method). This scope is in addition to being able to define an enum as nested or as separate class.

This new local definition scope came along with the new records feature. See JEP 395: Records for details. Enums, interfaces, and records can all be defined locally in Java 16+.

In contrast, public static final fields always have global scope.


Part of the same change, is that local classes now can have static final fields. Their scope would be the same as for the constants of a local enum. However, when you’re within an instance method, ordinary local classes still have an implicit reference to the surrounding this, which prevents them from being used like an enum.
C
Community

I think an enum can't be final, because under the hood compiler generates subclasses for each enum entry.

More information From source


Internally, they are not final, because – as you say – can internally be subclassed. But alas, you cannot subclass them on your own, e. g. for extending it with own values.
A subclass is only generated when you request it explicitly. Then, the subclasses will be final. Otherwise, the enum type itself will be final.
B
Bikas Katwal

There are many advantages of enums that are posted here, and I am creating such enums right now as asked in the question. But I have an enum with 5-6 fields.

enum Planet{
EARTH(1000000, 312312321,31232131, "some text", "", 12),
....
other planets
....

In these kinds of cases, when you have multiple fields in enums, it is much difficult to understand which value belongs to which field as you need to see constructor and eye-ball.

Class with static final constants and using Builder pattern to create such objects makes it more readable. But, you would lose all other advantages of using an enum, if you need them. One disadvantage of such classes is, you need to add the Planet objects manually to the list/set of Planets.

I still prefer enum over such class, as values() comes in handy and you never know if you need them to use in switch or EnumSet or EnumMap in future :)


r
radfast

Main reason: Enums help you to write well-structured code where the semantic meaning of parameters is clear and strongly-typed at compile time - for all the reasons other answers have given.

Quid pro quo: in Java out of the box, an Enum's array of members is final. That's normally good as it helps value safety and testing, but in some situations it could be a drawback, for example if you are extending existing base code perhaps from a library. In contrast, if the same data is in a class with static fields you can easily add new instances of that class at runtime (you might also need to write code to add these to any Iterable you have for that class). But this behaviour of Enums can be changed: using reflection you can add new members at runtime or replace existing members, though this should probably only be done in specialised situations where there is no alternative: i.e. it's a hacky solution and may produce unexpected issues, see my answer on Can I add and remove elements of enumeration at runtime in Java.


z
zettsu

You can do :

public enum Size { SMALL(1), MEDIUM(2), LARGE(3) };

private int sizeValue;

Size(sizeValue) {this.sizeValue = value; }

So with this you can get size value like this SMALL.getSizeValue();

If you want to set sizes Enums are not for you, if you will be only define constants and fixed values are fine.

Check this link maybe can help you