Java枚举中的协变返回类型

时间:2012-11-10 10:23:57

标签: java generics enums covariant

正如本网站上的另一个问题所述,这样的事情是不合法的:

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

    public Object doSomething();
}

这是由于covariant返回类型显然不适用于枚举常量(再次打破了enum常量是枚举类型的单例子类的错觉......)那么,我们如何添加一些泛型:这是合法的吗?

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

    public Class<?> doSomething();
}

这里,所有三个返回Class个对象,但各个常量比整个枚举类型“更具体”......

3 个答案:

答案 0 :(得分:4)

从根本上说,问题是MyEnum.FOO的编译时类型是MyEnum不是特定生成的子类。您可以在没有任何协方差的情况下看到这一点:

enum MyEnum {
    FOO {
        public void foo() {}
    };
}

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

基本上,编译器只会 查看MyEnum中声明的签名。

答案 1 :(得分:1)

我们可以在Java枚举中使用Covariant返回类型,但我们不能将该子类型用于分配返回的变量,这与普通的类层次结构不同。

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();
}

答案 2 :(得分:0)

此代码效果很好:

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

此代码无法编译,错误为"The return type is incompatible with MyEnum2.doSomething()"Cannot cast from Class<Object> to Class<Integer>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() );
   }
}