user121330
user121330

Reputation: 229

Java enum implements interface with Class<T> return type

OK, be nice.

Here's an enum that implements an interface with a method that returns a 'raw type' which gives me a warning on the getCaste() method in the interface.

public enum Thing implements HasCaste {

    Type1 {
        @Override
        public Class getCaste() {
            return String.class;
        }
    };
}

interface HasCaste {
    public Class getCaste();
}

If I change the interface's method to:

public <T> Class<T> getCaste();

it changes to an unchecked warning on Type1's method signature. If I then change Type1.getCaste()'s signature to:

public <T> Class<T> getCaste()

then the return has an incompatible types error because Class<String> can't be converted to Class<T>. If I then change the return to (Class<T>) String.class, we get an unchecked cast warning.

Is there a way to do this without a warning?

EDIT:

Sorry I didn't add this in earlier, but it'd be good to do this:

  , Type2 {
        @Override
        public Class getCaste() {
            return Integer.class;
        }
    };

Upvotes: 3

Views: 5221

Answers (3)

EpicPandaForce
EpicPandaForce

Reputation: 81539

As it was determined in the question I asked a while ago that was linked by Radiodef, you cannot do that with an enum, only by a simulated enum that's actually a class, like this.

public abstract class Thing<T> implements HasCaste<T> {
    public static final Thing<String> Type1 = new Thing<String>() {
        @Override
        public Class<String> getCaste() {
            return String.class;
        }
    };
    public static final Thing<Integer> Type2 = new Thing<Integer>() {
        @Override
        public Class<Integer> getCaste() {
            return Integer.class;
        }
    };

    private Thing() {
    }
}

As you can see, that is not an enum though. It is not possible with a mere enum, because enums cannot have type parameters.

p.s.: If you found this helpful, please look at Radiodef's answer for a more complete explanation, I learned this from him, after all :)

Upvotes: 2

Joop Eggen
Joop Eggen

Reputation: 109557

Assuming you want to define several differently "typed" enum constants, then one could do:

interface HasCaste {
    public Class<?> getCaste();
}

public enum Thing implements HasCaste<?> {

    Type1(String.class),
    Type2(Integer.class);

    public final Class<?> clazz;

    private Thing(Class<?> clazz) {
        this.clazz = clazz;
    }

    @Override
    public Class<?> getCaste() {
        return clazz;
    }
}

One then delays the typing to the future usage of getCaste. The main characteristic of an enum is a closed value domain; one has to list all possible values inside the class.

Upvotes: 1

fabian
fabian

Reputation: 82461

You could just leave the type parameter of the returned class unspecified:

public enum Thing implements HasCaste {

    Type1 {
        @Override
        public Class<String> getCaste() {
            return String.class;
        }
    }, Type2 {
        @Override
        public Class<Integer> getCaste() {
            return Integer.class;
        }
    };
}

interface HasCaste {
    public Class<?> getCaste();
}

Upvotes: 2

Related Questions