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
  • 26,609
  • 8
  • 70
  • 109
St.Antario
  • 26,175
  • 41
  • 130
  • 318

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,421,763
  • 867
  • 9,128
  • 9,194
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
  • 57,427
  • 7
  • 48
  • 90
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
  • 66,971
  • 31
  • 131
  • 216
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,761
  • 19
  • 49
  • 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
  • 36,381
  • 8
  • 49
  • 73