Java: How can I pass a value representing an Enum class? - java

Motivation: I would like to construct an enum that represents all possible values for some family of values (I hesitate to say "class" here). The enum will have additional methods, fields, and perhaps even implement other interfaces. I would then like to pass this enum to another method, where it will iterate over all of the possible values (using Enum.values() and do some work.
I've researched and found that enum Foo actually becomes Foo extends Enum<Foo>. This is why I cannot extend an enum. I have tried to define my method arguments as:
myMethod(Class<?> bar) {...}
myMethod(Class<? extends Enum> bar) {...}
myMethod(Class<? extends Enum<?>> bar) {...}
but inside the method when I try something basic like:
int i = bar.values().length;
it fails. Is there some other way I can do this (or avoid the need to do this)?
Note: I could pass an actual instance of the enum and use bar.getDeclaringClass() to find the enum class (rather than an instance) but this is pretty ugly.

Try using the following:
<E extends Enum<E>> void myMethod(Class<E> enumType) {
E[] values = enumType.getEnumConstants();
...
}
From the getEnumConstants() documentation:
Returns the elements of this enum class or null if this Class object
does not represent an enum type.
Edit: if you're using different enum types implementing a shared interface, you can modify your method in order to be able to call the interface methods. For example:
interface Fooable {
void foo();
}
...
<E extends Enum<E> & Fooable> void myMethod(Class<E> enumType) {
E[] values = enumType.getEnumConstants();
for (E value : values) {
value.foo();
}
}

Related

Using interface methods of enum in method accepting class

I have a method that needs to accept a Enum class. These enums implement an interface. Now I need access to both Enum methods like ordinal(), name(), etc and my interface methods. What I've tried:
public <T extends ConfigFeature, Enum> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// My interface's method, works fine
item.getMask();
// Enum method doesn't work:
// item.ordinal();
});
}
Reversing the order reverses the working:
public <T extends Enum, ConfigFeature> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// My interface's method, doesn't work now
// item.getMask();
// Enum method now works:
item.ordinal();
});
}
Is there a way to get access to both methods from interface and Enum?
You are using the wrong syntax to say that T must implement this interface AND is an enum.
This:
<T extends ConfigFeature, Enum>
is not constraining T to Enum, but actually creating a new generic parameter called Enum.
Similarly,
<T extends Enum, ConfigFeature>
is not constraining T to ConfigFeature. You are declaring a new generic parameter called ConfigFeature.
The correct syntax is to use &:
<T extends Enum<T> & ConfigFeature>
Note that the order is actually important here! Enum can only come first.
According to here, only the first constraint can be a class, and then the ones after it must all be interfaces:
TypeParameter:
{TypeParameterModifier} Identifier [TypeBound]
TypeParameterModifier:
Annotation
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
AdditionalBound:
& InterfaceType
Your syntax is wrong; you need:
public <T extends Enum<T> & ConfigFeature>
That syntax that you used creates two generic type parameters one called T and one called Enum (where Enum isn't bounded and T is bounded to extend ConfigFeature).
Note that, to avoid any generics warnings about the use of raw types, you also have to provide a type parameter to the Enum bound. An enum called X always extends Enum<X>, so you can use T extends Enum<T>, and the full text of the method local generic declaration becomes <T extends Enum<T> & ConfigFeature>
Replace the , in your second example with &. You can use & to declare multiple bounds as long as they’re interfaces from the second type onwards. If you use a comma it’s a separate type parameter, not a bound.
Just to add to existing answers, instead of using Mutliple Bounds as described in other answers, you can define interface that combines interface you want with return method for enum, like:
public interface ConfigFeatureEnumI <T extends Enum<T>> extends ConfigFeatureI{
#SuppressWarnings("unchecked")
default public T asEnum() {
return (T) this;
}
}
You can implement asEnum() in enum used, or just use default method if Java 8 is available as I show here.
public enum ConfigEnum implements ConfigFeatureEnumI<ConfigEnum>{//...
Then showEnabledFeatures can look like:
public <T extends ConfigFeatureEnumI<?>> void showEnabledFeatures(Class<T> enumType, long mask) {
List<T> list = Arrays.asList(enumType.getEnumConstants());
list.forEach(item -> {
// Interface method works:
item.getMask();
// Enum method works via asEnum():
item.asEnum().ordinal();
});
}
While adding new Interfaces is not ideal, it can be easier to use for programmers who do not know Java generics that well or never used Multiple bounds (I use generics a lot, but never needed such feature , so I was a bit off when I did see it).

Using Java reflection and generics: can a method specify an actual type as its return value?

I have a class that is maintaining a list of objects of type Baz. However, I want to put some objects in this list that are instantiated from subclasses of type Baz (for overridden behavior).
So far, this is simple enough -- polymorphism in a List. However, the class maintaining the list is itself abstract, and different implementations will require that different types be placed in the list. Some abstract function getTypeToUse should specify the type of the element to insert into the list. Is this possible in Java?
Consider the following pseudocode:
public abstract class Foo {
public void Bar() {
List<Baz> qux = new ArrayList<>();
Type buzz = getTypeToUse();
Baz fizz = new buzz();
qux.add(fizz);
}
// The returned Type should be some subclass of Baz
// It would be nice to enforce this, like <? extends Baz>
public abstract Type getTypeToUse();
}
Thank you!
You could return a class object instead. The class Class<T> implements the interface Type. Define your method like this:
public abstract Class<? extends Baz> getClassToUse();
Then implement it like this (in class Baz):
#Override
public Class<? extends Baz> getClassToUse() {
return Baz.class;
}

using enum (as type) in generic class and looping through its elements

I have a generic class with enum type as generic, and I want to iterate through all elements in the enum. Hope the following example (not working) will make more clear what I want. What is the correct syntax?
public class GenericClass<T extends Enum<T>>{
T myEnum;
public void doSomething(){
for(T element : myEnum.values()){// <-- values() not available
....
}
}
}
I would use the class this way
GenericClass<OtherClass.MyEnumType> manager;
manager.doSomething();
You're attempting to hold a reference to an instance of an enum which isn't very useful, but you can require that the enum class is passed to the constructor (called a type token).
With a class, you can use the (typed) class method getEnumConstants() (which returns null if the class isn't an enum class, but we've bound it to be an enum class).
This compiles:
public class GenericClass<T extends Enum<T>> {
Class<T> enumClass;
public GenericClass(Class<T> enumClass) {
this.enumClass = enumClass;
}
public void doSomething() {
for (T element : enumClass.getEnumConstants()) {
}
}
}
Not really possible. values() method is not part of the Enum class but of a class derived by the compiler from your enum: public class YourEnum extends Enum<YourEnum>.
See this SO question for more info: How is values() implemented for Java 6 enums?
this is equivalent to the static values() method:
T[] items = myEnum.getDeclaringClass().getEnumConstants();
See Enum.getDeclaringClass()
(Basically this returns the class defining the enum item, which may or may not be == myEnum.getClass(), depending on whether or not the enum item has a body)

How to declare a Class<?> object such that is is an Enum AND an Interface in Java

I have a utility class that needs to work on a generic Class but must be restricted to those that are an enum and implement a particular interface.
// These two work
Class<? extends Enum<?>> enumClass;
Class<? extends MyInterface> interfaceClass;
// This is what I want but does not work
Class<? extends MyInterface & Enum<?>> enumAndInterfaceClass;
For generics I can successfully use this
public class MyClass<T extends Enum<T> & MyInterface> {
public MyClass(Class<T> theClass) {
...
}
}
However I can't use the Generics everywhere and need to declare it separately. I am not sure if this is even possible.
So my question boils down to how can I declare a member variable with those constraints?
So Currently MyClass is a singleton then as needed the enum/interface can be updated. The return values of its operations will change depending on which enum it is given. I would like to not have the generics on it since that would require creating a new instance for every change to the enum. There is a lot of code using it already so deviating from the singleton is not going to be approved. So a reference must be kept. I suppose I could only enforce the Interface requirement then check in the setter method that it is an enum throwing an exception otherwise but that is not ideal.
Edit (Updated question and added more detail)
As far as I remember, you can only declare intersection types (this is what & creates) for type parameters of classes and methods. You can not declare a local variable with an intersection type directly; you can create such variables with the aid of a class or method type parameter, as seen in the answer of milkplusvellocet.
See the JLS reference in this answer to a similar question:
https://stackoverflow.com/a/6643378/282229
This should work:
public interface MyInterface {
void foo();
}
public final class Utils {
public static <E extends Enum<E> & MyInterface> void doWork(Class<E> clazz) {
for(E enumConstant : clazz.getEnumConstants) {
enumConstant.foo();
}
}
}
EDIT I didn't notice your line about using the captured type as a local variable. You can of course use this throughout the body of the parameterised method, see revised snippet above.

Java Enums: List enumerated values from a Class<? extends Enum>

I've got the class object for an enum (I have a Class<? extends Enum>) and I need to get a list of the enumerated values represented by this enum. The values static function has what I need, but I'm not sure how to get access to it from the class object.
Class.getEnumConstants
If you know the name of the value you need:
Class<? extends Enum> klass = ...
Enum<?> x = Enum.valueOf(klass, "NAME");
If you don't, you can get an array of them by (as Tom got to first):
klass.getEnumConstants();
I am suprised to see that EnumSet#allOf() is not mentioned:
public static <E extends Enum<E>> EnumSet<E> allOf(Class<E> elementType)
Creates an enum set containing all of the elements in the specified element type.
Consider the following enum:
enum MyEnum {
TEST1, TEST2
}
Simply call the method like this:
Set<MyEnum> allElementsInMyEnum = EnumSet.allOf(MyEnum.class);
Of course, this returns a Set, not a List, but it should be enough in many (most?) use cases.
Or, if you have an unknown enum:
Class<? extends Enum> enumClass = MyEnum.class;
Set<? extends Enum> allElementsInMyEnum = EnumSet.allOf(enumClass);
The advantage of this method, compared to Class#getEnumConstants(), is that it is typed so that it is not possible to pass anything other than an enum to it. For example, the below code is valid and returns null:
String.class.getEnumConstants();
While this won't compile:
EnumSet.allOf(String.class); // won't compile
using reflection is simple as calling Class#getEnumConstants():
List<Enum<?>> enum2list(Class<? extends Enum<?>> cls) {
return Arrays.asList(cls.getEnumConstants());
}

Categories