Reputation: 945
After much searching I've found lots of relevant questions to normal classes, but none that really relate to enums.
This works fine:
package list;
public interface Testing {
//treat as a tag interface.
}
package list;
public class Foo implements Testing {
}
package list;
import java.util.ArrayList;
import java.util.List;
public class Bar {
public Bar(){
List<Foo> myList = new ArrayList<Foo>();
myList.add(new Foo());
testList(myList);
testMethod(new Foo());
}
public void testMethod(Testing myInstance){
//do nothing
}
public <Testing> void testList(List<Testing> myList){
//do nothing
}
}
However, my problem comes in the understanding of what happens when I try and do the same with
Enums
instead of
Foo
The example here is there is an interface definition that is defined as accepting an interface parameter which, in reality, is implemented by an enum that implements the interface:
I have two interfaces:
public interface MyEnumInterface {
//implemented by Enums
}
import java.util.List;
public interface SecondInterface {
public MyEnumInterface testMe(String myString);
public <MyEnumInterface> List<MyEnumInterface> testingList();
public List <MyEnumInterface> enumTestOne(String anotherString);
public List <MyEnumInterface> enumTestTwo(String anotherString);
}
Two emum as follows:
public enum MyEnum implements MyEnumInterface{
VALUE_ONE,
VALUE_TWO,
VALUE_THREE;
}
public enum MyEnum2 implements MyEnumInterface{
VALUE_A,
}
And a test java class:
import java.util.ArrayList;
import java.util.List;
class MyClass implements SecondInterface{
public MyClass(){
single(testMe(""));
enumTestOne("");
enumTestTwo("");
}
public MyEnum testMe(String someParam){
return MyEnum.VALUE_ONE;
}
public List<MyEnumInterface> enumTestOne(String anotherString) {
List<MyEnum> returnL = new ArrayList<MyEnum>();
returnL.add(MyEnum.VALUE_ONE);
returnL.add(MyEnum.VALUE_THREE);
return returnL;
}
public List<MyEnumInterface> enumTestTwo(String anotherString) {
List<MyEnum2> returnL = new ArrayList<MyEnum2>();
returnL.add(MyEnum2.VALUE_A);
return returnL;
}
public List<MyEnum> testingList(){
List<MyEnum> returnL = new ArrayList<MyEnum>();
returnL.add(MyEnum.VALUE_ONE);
returnL.add(MyEnum.VALUE_THREE);
return returnL;
}
public void single(MyEnumInterface val){
System.out.println("Value is " + val);
}
public static void main(String[] args){
MyClass clazz = new MyClass();
}
}
I'm battling with the problem that the return type of enumTestOne(..) is coded as List but the interface specifies a List. It works fine when it's an individual instance of the Enum 'MyEnum' but when it's a list of values it seems to fail with a:
"error: method listing in class MyClass cannot be applied to given types; required: List found: List reason: actual argument List cannot be converted to List by method invocation conversion"
I'm not sure of a way around this - I've tried adding the declaration you see above so that it reads
public <MyEnumInterface> List<MyEnumInterface> testingList();
but that then gives me "warnings" about unchecked casts whilst continuing to fail
This all stems from my lack of deeper understanding around Generics and how they relate to Enums.
I've seen some interesting declarations with respect to
<? extends Enum<E> & SecondInterface>
but that stretches my understanding. Please help!
As an aside, am I correct in thinking that the generic declarations before the return class are used to specify "T" for type erosion purposes?
Upvotes: 4
Views: 2777
Reputation: 13907
If you want to allow the implementing class to define which implementation of MyEnumInterface
to use, you can specify the return type of the interface methods as a List
of any MyEnumInterface
.
public List<? extends MyEnumInterface> enumTestOne(String anotherString);
public List<? extends MyEnumInterface> enumTestTwo(String anotherString);
The implementations of these methods can then define the concrete return type.
public List<MyEnum> enumTestOne(String anotherString) {
List<MyEnum> returnL = new ArrayList<MyEnum>();
returnL.add(MyEnum.VALUE_ONE);
returnL.add(MyEnum.VALUE_THREE);
return returnL;
}
public List<MyEnum2> enumTestTwo(String anotherString) {
List<MyEnum2> returnL = new ArrayList<MyEnum2>();
returnL.add(MyEnum2.VALUE_A);
return returnL;
}
By the way, you can do the same in "reverse" with super
. This specifies that any type that is a supertype of the given type may be used.
public void addToList(List<? super MyEnum> list) {
list.add(MyEnum.VALUE_ONE);
}
addToList(new ArrayList<MyEnum>());
addToList(new ArrayList<MyEnumInterface>());
Why is SomeClass not equivalent to SomeClass in Java generic types?
Upvotes: 2
Reputation: 19185
Generics are invariant
in nature. So List<String>
is not subtype of List<Object>
You will have to change your method to include List of MyEnumInterface
rather than separate enum classes.
public List<MyEnumInterface> enumTestOne(String anotherString) {
List<MyEnumInterface> returnL = new ArrayList<MyEnumInterface>();//Change
returnL.add(MyEnum.VALUE_ONE);
returnL.add(MyEnum.VALUE_THREE);
return returnL;
}
public List<MyEnumInterface> enumTestTwo(String anotherString) {
List<MyEnumInterface> returnL = new ArrayList<MyEnumInterface>();//Change
returnL.add(MyEnum2.VALUE_A);
return returnL;
}
Upvotes: 4