Reputation: 9047
Supposing I have several specific classes which all extend one abstract class, like so:
public abstract AbstractClass {
// abstract stuff here
}
public FirstSpecificClass extends AbstractClass {
// specific stuff here
}
public SecondSpecificClass extends AbstractClass {
// specific stuff here
}
I need to create an enum
elsewhere in which each entry is connected (associated?) with one of the specific classes; to that end, I am passing the specific class as a constructor parameter and storing it as a private field within the enum (I've also provided a getter method for that field). I also need to create a static method which takes an instance of one of the specific classes as an argument and returns the appropriate enum element (or null). I will do this by looping over each enum entry and using instanceof
in combination with the getter for the private field mentioned previously. This is my attempt:
public enum Types {
FIRST(FirstSpecificClass.class), // line 2
SECOND(SecondSpecificClass.class); // line 3
private Class<AbstractClass> classType;
private Types(Class<AbstractClass> classType) {
this.classType = classType;
}
public Class<AbstractClass> getClassType() {
return this.classType;
}
public static Types fromTypeInstance(AbstractClass instance) {
for(Types t : Types.values())
if(instance instanceof t.getClassType()) return t; // line 17
return null;
}
}
I seem to misunderstanding how to store the class type as a field so that it can be returned and used in the instanceof
check later. This code is producing several compile-time errors:
Types(Class<FirstSpecificClass>)
is undefinedTypes(Class<SecondSpecificClass>)
is undefinedboolean
and Class<AbstractClass>
I am not usually a Java programmer, and my understanding of generics and instanceof
is fuzzy at best, although I do have a pretty firm grasp on the concept of OOP. How can I resolve these errors and achieve the desired effect?
Upvotes: 3
Views: 847
Reputation: 178253
In Java, generics are invariant. This means that a Class<FirstSpecificClass>
is not a Class<AbstractClass>
, even if a FirstSpecificClass
is an AbstractClass
.
You can work around this by explicitly allowing subtypes with an upper bound wildcard. Add ? extends
before your AbstractClass
type argument where needed.
private Class<? extends AbstractClass> classType;
private Types(Class<? extends AbstractClass> classType) {
this.classType = classType;
}
public Class<? extends AbstractClass> getClassType() {
return this.classType;
}
Additionally, you must specify the type directly in the source code for the instanceof
operator, so this doesn't compile:
if(instance instanceof t.getClassType())
You can use the Class
object's isInstance
method instead, for a runtime solution:
if(t.getClassType().isInstance(instance))
Upvotes: 5