3

I'm in Java 7 and I have the following enum:

public enum BooleanEnum implements StringRepresentable{
    YES {
        @Override
        public String getStringRepresentation() {
            return "true";
        }
    },
    NO {
        @Override
        public String getStringRepresentation() {
            return "false";
        }
    };
    public abstract String getStringRepresentation();
}

Now I have the method:

List<StringRepresentable> getValues(){
    return Arrays.asList(BooleanEnum.values()); //Type mismatch: 
                  //cannot convert from List<BooleanEnum> to List<StringRepresentable>
}

What's wrong with that enum? It implements the interface, therefore the code should have compiled fine.

Jordi Castilla
  • 25,851
  • 7
  • 65
  • 105
St.Antario
  • 24,791
  • 31
  • 112
  • 278

5 Answers5

8

It implements the interface, therefore the code should have compiled fine.

No, because the type argument is being inferred as BooleanEnum - and a List<BooleanEnum> isn't a List<StringRepresentation>... you can add instances of other StringRepresentation implementations to the latter.

Four possible options:

  • Specify that you're returning a list of some subclass of StringRepresentation:

    List<? extends StringRepresentation> get Values() {
        // Implementation as before
    }
    
  • Specify the type argument:

    return Arrays.<StringRepresentation>asList(BooleanEnum.values());
    
  • Use an intermediate variable for clarity:

    StringRepresentation[] array = BooleanEnum.values();
    return Arrays.asList(array);
    
  • Don't return a List<StringRepresentation> at all; return an Iterable<StringRepresentation> at which point you can use EnumSet instead:

    Iterable<? extends StringRepresentable> getValues() {
        return EnumSet.allOf(BooleanEnum.class);
    }
    
Jon Skeet
  • 1,335,956
  • 823
  • 8,931
  • 9,049
2

If this compiled, someone could do this:

List<StringRepresentation> values = getValues();
values.set(0, new SomeOtherStringRepresentation());

(since modifying the list returned by Arrays.asList modifies the original array) and then you'd have stored a SomeOtherStringRepresentation in the original array of BooleanEnums! That's obviously not allowed.

Instead, you could make a copy, say as an ArrayList:

List<StringRepresentation> getValues(){
    return new ArrayList<StringRepresentation>(Arrays.asList(BooleanEnum.values()));
}
user253751
  • 50,383
  • 6
  • 45
  • 81
2

First BooleanEnum.values() returns an BooleanEnum[], then with Arrays.asList you return a List<BooleanEnum>.

Since a List<BooleanEnum> is not a subset of List<StringRepresentation>, this code will not compile.

You could in theory get this code to compile by returning a List<? extends StringRepresentation>, however I would not recommend that as it is not really useful to the caller side.

skiwi
  • 63,319
  • 30
  • 127
  • 205
2

The type of your List is StringRepresentation, and BooleanEnum just implements StringRepresentable, an interface can't be converted into any types of class which implements the interface.

SilentKnight
  • 13,435
  • 18
  • 48
  • 78
2

You should return something like:

 return Arrays.<StringRepresentable>asList(BooleanEnum.values());

Since List of BooleanEnum is not same as List of StringRepresentable.

SMA
  • 35,277
  • 7
  • 46
  • 71