tags:

views:

280

answers:

5

Hi guys, I'd like to make a class that looks basically like this:

public class MyClass<T implements Serializable) {

   void function() {
      Class c = T.class;
   }
}

Two errors:
- I cannot call T.class, even though I can do that with any other object type
- I cannot enforce that T implements Serializable in this way

How do I solve my two generics problems?

Cheers

Nik

+2  A: 

Something along these lines should do it.

private Class<T> dataType;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
    ParameterizedType paramType = (ParameterizedType) type;
    dataType = (Class<T>) paramType.getActualTypeArguments()[0];
} else if (type instanceof Class) {
    dataType = (Class<T>) type;
}
gjrwebber
Thanks for the workaround, that helped me solve the problem, and the other answers helped me understand the problem. :-) You guys are the best! :-)
niklassaers
+4  A: 

You can't get the type.

Generics are implemented using something called type-erasure.

When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.

The essence of this is that the type information is used by the compiler and discarded, hence not available at runtime.

With regards to the enforcing T implements Serializable, you just need the following:

public class MyClass<T extends Serializable>)
{
  public void function(T obj) 
  {
    ...
  }
}

This is simply referring to the is a relationship, so an class that implements Serializable, is a Serializable and can be passed to function.

Nick Holt
Thanks for the great explanation, I now understand why it doesn't work, and I've solved my practical problem with the workaround proposed by gjrwebber. Thanks a bunch! :-)
niklassaers
+1  A: 

1) Right, you can't do T.class because java does not actually no which class T is at runtime. All that information is lost at compilation. To get the class object for T you can either call getClass() on an instance of T (if you have access to one) or require the user to pass the class object as an argument to function, like:

void function(Class<T> c)
sepp2k
The syntax for generic argument bounding is <T extends Serializable> not <T implements Serializable>
Tadeusz Kopec
Ah right. I removed that part of my answer.
sepp2k
Thanks for the quick feedback. (1) The problem with that is that in my generic function I want to use functions that take T.class as an input parameter. If I cannot do it this way, a not so good workaround would be to instantiate an object of class T, but as I understand it I cannot say "new T()" either, again because of type-erasure?(2) Doh, didn't see the typo. But, my Java compiler claims it expects a comma where I write implements, that's what I meant by it. EDIT: Thanks tkopec, extends worked much better, I didn't know I could extend an interface
niklassaers
A: 

This is not possible without tricks. The Java Generics FAQ provides an idea for a workaround.

Wolfgang
+4  A: 

you do this:

public class MyClass<T implements Serializable) {

   void function(Class<T> tc) {
      ...
   }
}

Basically, you have to pass in the class at run time in order to see it. You could also do something like this:

public class MyClass<T implements Serializable) {
   Class<T> ct; 
   public MyClass(Class<T> ct){this.ct = ct;}

   void function() {
       ... //you know what the class is here
   }
}

It's kind of annoying, but not really that big of a hassle overall.

Chad Okere
Thanks a lot, that's an elegant workaround :-)
niklassaers