Get the parameterized type of a subclass

C

cdvr

Hi,
I have the following setup....

public interface Foo<T> { ....}

public abstract class AbstractFoo<T> implements Foo<T> {
public void printParamType() {
// print the actual type of T
}
}

public class MyFoo extends AbstractFoo<Blah> {

public void static main(String[] args) {
MyFoo f = new MyFoo();
f.printParamType();
}
}

What I'd like to get is the type "Blah"....how can I get that Type or
reference to the Class object at run-time?

Thanks
 
N

nebulous99

What I'd like to get is the type "Blah"....how can I get that Type or
reference to the Class object at run-time?

public interface Foo<T> { ... }

public abstract class AbstractFoo<T> implements Foo<T> {
private Class<T> paramType;

protected AbstractFoo (Class<T> paramType) {
this.paramType = paramType;
}

public void printParamType() {
System.out.println(paramType);
}
}

public class MyFoo extends AbstractFoo<Blah> {
public MyFoo () {
super(Blah.class);
}

public void static main(String[] args) {
MyFoo f = new MyFoo();
f.printParamType();
}
}


You might want to specify printParamType in the interface, or better
yet make it getParamType and leave it up to the caller what to do with
the Class object. Of course the param type class object has to be
passed to the AbstractFoo constructor by its subclasses. Any instance
can be queried regarding the param type. Subtypes that are still
parametrized can continue to ask for it in their constructors to pass
to the superclass constructor; ones that are not parametrized,
extending Superclass<SpecificType>, can call super(SpecificType.class)
in their constructors.
 
P

Piotr Kobzda

cdvr said:
public abstract class AbstractFoo<T> implements Foo<T> {
public void printParamType() {
// print the actual type of T

Class subclass = getClass();
for(Class c; (c = subclass.getSuperclass())
!= AbstractFoo.class; subclass = c);
ParameterizedType type = (ParameterizedType)
subclass.getGenericSuperclass();
System.out.println(type.getActualTypeArguments()[0]);
}
}

public class MyFoo extends AbstractFoo<Blah> {

public void static main(String[] args) {
MyFoo f = new MyFoo();
f.printParamType();
}
}

What I'd like to get is the type "Blah"....how can I get that Type or
reference to the Class object at run-time?

The sample code above shows how to do that. It assumes that you pass an
actual type directly from the superclass (as in a case of your MyFoo
class). However, in general, it may be more complex (e.g. actual type
passed from non direct subclass), or even impossible to infer what the
actual type argument type is (type erasure). BTW -- Maybe the later
limitation will become weaker soon, thanks to the Neal Gafter proposal
of making generic types fully reifiable.


piotr
 
R

Roedy Green

What I'd like to get is the type "Blah"....how can I get that Type or
reference to the Class object at run-time?

Type erasure says you can't. That information is erased at compile
time. It is strictly for compile-time checking.

see http://mindprod.com/jgloss/generics.html

Type erasure was done to make generics easy for the JVM makers to
implement. It also hoped for strict compatibility with JDK 1.4.
 
P

Piotr Kobzda

Roedy said:
Type erasure says you can't. That information is erased at compile
time. It is strictly for compile-time checking.

Not all information about generics is being erased at compile time.

You probably will need to update a bit your valuable glossary page,
because not the whole true is there.

There is a lot of generic information preserved for runtime in a class
files. In particular, there is a full information about generic
declaration preserved. Type erasure, in general, affects a direct use
of a generic types in a code only. (Of course, the method declarations,
and many others language elements are affected also, but that's not
important here I think).

For example, if you put the following line into some method body:

List<String> list = new ArrayList<String>();

there is no information at runtime that a String is the actual type
argument for both List, and ArrayList.

But when you put the above line into a class' declaration body (making a
field), then the information about actual the type argument type of a
List is preserved in that field declaring class file
(Field.getGenericType() allows to access it).

There is still no full information preserved about actual type argument
used for ArrayList. However, we can preserve that info also in
ArrayList subclass declaration (that's what the OP did).

So when we change our field declaration to:

List<String> list = new ArrayList<String>() {};

There is all information about List and ArrayList actual type arguments
present at runtime (retrievable the way demonstrated in my previous post
to this thread).

Type erasure was done to make generics easy for the JVM makers to
implement. It also hoped for strict compatibility with JDK 1.4.

The type erasure was mainly designed to allow binary backward
compatibility. The generic information already preserved do not breaks
that. There was not clear idea previously on how to add more info
without breaking the compatibility. But now we have the Neal Gafter's
proposal (mentioned in my previous post) to allow fully reified generic
types to coexist with these that we have currently, still without
breaking binary backward compatibility.

For more details see:
http://gafter.blogspot.com/2006/11/reified-generics-for-java.html
http://tech.puredanger.com/java7#reified


piotr
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top