Reputation: 2549
I've a class like this:
public class GenericClass<T> {
public void wrap(T item) {...}
}
public abstract class AbstractClass<T, G extends GenericClass<T>> {
protected G wrapper;
public AbstractClass(Class<G> generic, T something) {
wrapper = generic.newInstance();
wrapper.wrap(something);
}
public G wrapAndGet(T item) throws Exception {
wrapper.wrap(item);
return wrapper;
}
}
// 90% of the time people only need this:
public class GeneralClass<T> extends AbstractClass<T, GenericClass<T>> {
public GeneralClass(T something) {
super(GenericClass.class, something); // !error, asking for Class<GenericClass<T>>
}
}
// and use it like this:
new GeneralClass<String>("foo").wrapAndGet("bar");
// but sometimes you might need:
public class AdvancedWrapper<T> extends GenericClass<T> {
public T advancedMethod();
}
public class ClassUseAdvancedWrapper<T> extends AbstractClass<T, AdvancedWrapper<T>> {
public ClassUseAdvancedWrapper(T something) {
super(AdvancedWrapper.class, something); // error, but let's say it compiles
}
}
// then you can use:
new ClassUseAdvancedWrapper<String>("foo").wrapAndGet("bar").advancedMethod();
This doesn't make sense to me: aren't GenericClass<T>
and GenericClass having the same class at runtime? How can I get the class object of GenericClass<T>
then?
EDIT: add use case
Upvotes: 0
Views: 3069
Reputation: 11020
This is what I had to do to get some code to compile. I don't know what you are trying to do, but at least this gives a blueprint to follow. The main problem I saw was that AbstractClass
needs two arguments for its CTOR, and you can't do that by passing only one argument to the CTOR of GeneralClass
, so I had to add a second argument.
public class GenericTest {
public static void main(String[] args) {
GenericClass<Integer> generic = null;
AbstractClass<Integer, GenericClass<Integer>> abstr = new AbstractClass( generic.getClass(), 1 );
GeneralClass<Integer, GenericClass<Integer>> general = new GeneralClass( generic.getClass(), 1 );
}
}
class GenericClass<T> {
}
class AbstractClass<T, G extends GenericClass<T>> {
public AbstractClass(Class<G> generic, T something) {
}
}
class GeneralClass<T,G extends GenericClass<T>>
extends AbstractClass<T, G> {
public GeneralClass( Class<G> generic, T something) {
super( generic, something);
}
}
EDIT: So to echo the discussion in the comments, I made AbstractClass
concrete so I could show what arguments its constructor takes. (Also, I had to do that in my own code to figure out what the heck was going on, so I'm showing my work.)
I hope the examples/test cases in the main method above make it clear what's going on. To reiterate what Sotirios Delimanolis said:
How can I get the class object of GenericClass then?
You can't. It doesn't exist. At runtime, there is no Class object for GenericClass, there's only a Class object for GenericClass.
GenericClass in this case sets T = Integer. There's clearly no relationship between the system class Integer and the class you just declared. There's no get()
you can call on an integer to get your class GenericClass
. I think my example makes this plain as day.
You could I suppose make some sort of processing tool that scans .java files or .class files, and builds a database of type parameters used by GenericClass (and its subclasses?), but that's boarding on crazy unfeasible. If you have the resources, it could be done, but it won't make sense for any but the largest projects, and probably only a public framework at that.
Upvotes: 2
Reputation: 279930
Class literals, ex. Foo.class
, don't include generic type information. The JLS states
The type of
C.class
, whereC
is the name of a class, interface, or array type (§4.3), isClass<C>
.
This also means that the type of the expression contains a raw type, ie. inClass<GenericClass>
, GenericClass
is not parameterized and is therefore raw.
So, the problem here is your abstract class' constructor expects
Class<G> generic
where G
is
G extends GenericClass<T>>
so (close to)
Class<G extends GenericClass<T>>
but you are providing
Class<GenericClass>
Those are not assignable.
You ask
How can I get the class object of GenericClass then?
You can't. It doesn't exist. At runtime, there is no Class
object for GenericClass<T>
, there's only a Class
object for GenericClass
.
You'd have to explain what you are trying to do in more detail, but you could make your code compile with
abstract class AbstractClass<T, G extends GenericClass<T>> {
public AbstractClass(Class<? super G> generic, T something) {
}
}
Now your constructor expects a Class<? super G extends GenericClass<T>>
and you are providing a Class<GenericClass>
. In your super
constructor invocation GenericClass<T>
is bound to G
and GenericClass
is a supertype of GenericClass<anything>
, so Class<GenericClass>
is assignable to a Class<? super GenericClass<T>>
. You'll find there are many other limitations with this solution. It all depends on your goal.
Upvotes: 5