Home > Back-end >  Java - EnumSet.noneOf()- Why use Class<E> instead of T?
Java - EnumSet.noneOf()- Why use Class<E> instead of T?

Time:06-29

The definition is: https://developer.android.com/reference/java/util/EnumSet

noneOf(Class<E> elementType)
Creates an empty enum set with the specified element type.

But why does it require Class<E> and not, say, T as in noneOf(T elementType) ? Is it because it requires the type to be entered at runtime? But when I write code for example EnumSet.noneOf(Authority.class); I know the type (Authority) at compile time,so could it have been EnumSet.noneOf(Authority) ?

Since it seems to require though,why not use the anytype as in Class<?>

CodePudding user response:

I know the type (Authority) at compile time,so could it have been EnumSet.noneOf(Authority) ?

You can't do EnumSet.noneOf(Authority) because that's not legal Java. When you want to pass around a type then you use a Class instance, and when you know the needed class at compile-time, you use a class literal (e.g., Authority.class).


But why does it require Class<E> and not, say, T as in noneOf(T elementType) ?

Conceptually, it makes no sense to require an instance of a type when you want an empty set of said type. But then I suppose the question becomes, "Why is any argument needed in the first place?". After all, you can do something like:

Set<String> list = new HashSet<>();

Without passing a Class instance.

The reason is because EnumSet is a highly specialized Set implementation. It needs to know of all the existing enum constants, which can be queried using the Class, even when the set is empty. Also, the implementation only works with a single type. An EnumSet cannot contain constants from different enum types. The Class allows the implementation to enforce this.

Other methods, such as EnumSet#of(E), don't require a Class because they require instances of the enum (i.e., one or more constants) and the type can be grabbed from them.


Since it seems to require though,why not use the anytype as in Class<?>

Because a Class<?> would allow you to pass any type, not just an enum type. Though of course that could be solved by bounding the wildcard: Class<? extends Enum<?>>. Now only enum types are allowed, but the static type system has no idea which enum type you're using. This means methods such as noneOf would only be capable of returning an EnumSet<?>, which is not very useful.

By declaring a type variable E and bounding it to extend Enum<E>, the use of Class<E> forces you to pass an enum type and you get an EnumSet<E> back.

CodePudding user response:

The other answers don't seem to give charitable interpretations of your question, so I'll add one.

But why does it require Class and not, say, T as in noneOf(T elementType) ?

It's because the EnumSet needs to be able to verify the type later. For example:

var set = EnumSet.noneOf(Authority.class);
set.add(Authority.ADMIN); // ordinal 1

On the second line, the set needs to verify that enum being added to the set is the same type as the others. There wouldn't be a way to check the types match if someone later wrote:

set.add(Color.BLUE) // ordinal 1, oops!

It wouldn't be possible to distinguish the problem without the enum class. You ask a valid question of why this should be the type with (lightly rewritten):

EnumSet.noneOf(Authority.ADMIN)

This would be possible, except it wouldn't work for empty enums:

enum Empty {}

Finally, it's important to note the values from each enum may have different classes:

enum Authority {
  ADMIN {
    @Override void checkPermissions() {...}
  },
  USER {
    @Override void checkPermissions() {...}
  };

  abstract void checkPermissions();
}
assert Authority.ADMIN.getClass() != Authority.USER.getClass();

As a result, the outermost class needs to be passed into EnumSet, so the class object is preferred.

  • Related