Covariant return types in Java enums

As mentioned in another question on this site, something like this is not legal:

public enum MyEnum { FOO { public Integer doSomething() { return (Integer) super.doSomething(); } }, BAR { public String doSomething() { return (String) super.doSomething(); } }; public Object doSomething(); } 

This is because the covariant return data types do not seem to work with enum constants (again breaking the illusion that enum constants are singleton subclasses of an enum type ...) So, how about adding a few generics: is this legal?

 public enum MyEnum2 { FOO { public Class<Integer> doSomething() { return Integer.class; } }, BAR { public Class<String> doSomething() { return String.class; } }; public Class<?> doSomething(); } 

Here all three return Class objects, but the individual constants are "more specific" than the type of the enumeration as a whole ...

+4
source share
3 answers

The main problem is that the MyEnum.FOO type is MyEnum.FOO time MyEnum , and not a specific generated subclass. You can see this without any covariance:

 enum MyEnum { FOO { public void foo() {} }; } public class Test { public static void main(String[] args) throws Exception { MyEnum.FOO.foo(); // Error } } 

Basically, the compiler will only see signatures declared in MyEnum .

+4
source

We can use Covariant return types in Java enums, but we cannot use this child type for the variable to which the return is assigned, unlike the usual class hierarchy.

 public class EnumCovariance { public static void main(String[] args) { // Type mismatch: cannot convert from Class<capture#1-of ?> to Class<Integer> Class<Integer> something = MyEnum2.FOO.doSomething(); Child child = new Child(); Base base = child; // ok Class<Integer> something3 = child.doSomething(); // Type mismatch: cannot convert from Class<capture#2-of ?> to Class<Integer> Class<Integer> something2 = base.doSomething(); } } abstract class Base { public abstract Class<?> doSomething(); } class Child extends Base { @Override public Class<Integer> doSomething() { return Integer.class; } } enum MyEnum2 { FOO { public Class<Integer> doSomething() { return Integer.class; } }, BAR { public Class<String> doSomething() { return String.class; } }; public abstract Class<?> doSomething(); } 
+1
source

This code works well:

 public enum MyEnum { FOO { @Override public Integer doSomething() { return (Integer)super.doSomething(); } }, BAR { @Override public String doSomething() { return (String)super.doSomething(); } }; public Object doSomething() { System.err.println( this ); return null; } public static void main( String[] args ) { MyEnum toto = MyEnum.FOO; System.err.println( toto.doSomething() ); } } 

:

 FOO null 

this code does not compile, error "The return type is incompatible with MyEnum2.doSomething()" , Cannot cast from Class<Object> to Class<Integer> and Cannot cast from Class<Object> to Class<String> :

 public enum MyEnum2 { FOO { @Override public Class<Integer> doSomething() { return (Class<Integer>)super.doSomething(); } }, BAR { @Override public Class<String> doSomething() { return (Class<String>)super.doSomething(); } }; public Class<Object> doSomething() { System.err.println( this ); return null; } public static void main( String[] args ) { MyEnum2 toto = MyEnum2.FOO; System.err.println( toto.doSomething() ); } } 
0
source

Source: https://habr.com/ru/post/1445200/


All Articles