tags:

views:

272

answers:

5

Assuming the following class stub:

public class Foo<T> {
  private Class<T> type;

  public Foo<T> () {}
}

Can I store the generic type T into the field type in the constructor, without changing the constructor's signature to "public Foo<T> (Class<T> type)"?

If yes, how? If no, why?

"type = T" doesn't seem to work.

A: 

Does

type = T.getClass();

work?

JTeagle
no, it doesn't work, because I can't refer to T inside the method ("T cannot be resolved")
Henrik Paul
A: 

You should try this maybe:

type = T.GetType();
Charles Graham
no, it doesn't work, because I can't refer to T inside the method ("T cannot be resolved").
Henrik Paul
+5  A: 

No - type erasure means that you have to provide something at execution time. You could provide either an instance of T or Class<T> but the class itself will just have every occurrence of T replaced with Object.

This kind of thing is one of the biggest disadvantages of Java's generics vs those in .NET. (On the other hand, the variance story is stronger - if more confusing - in Java than in .NET.)

Jon Skeet
+1  A: 

Well, why not have an instance of T in your class? I mean what does T buy you anything if this is not the case? So if yout have T x, they you cando an x.GetType().

Charles Graham
Hmm, I thought this was .Net. I forgot that Java as different generics.
Charles Graham
+4  A: 

As said in this thread,

for Example List<Integer>

list.get (index).getClass()

will not give you type of object stored in list:

  • when the list is empty
  • even when the list is NOT empty, because any element can be any subclass of the generic type parameter.

Since type parameters are erased at compile time, they do not exist at runtime (sorry Jon, at execution time): Hence you cannot get generic type info via reflection in java.

There is a case for more reification which is on the table (Java 7 ?), and would facilitate what you are after.

One would hope that a bad type, casted into T, would provoke a Cast exception that would, at execution time, reveal the original type used for T, but alas, that does not work either.

Consider the following test class:

import java.util.ArrayList;

/**
 * @param <T>
 */
public class StoreGerenericTypeInField<T>
{

    private T myT = null;
    private ArrayList<T> list = new ArrayList<T>();

    private void setT(final T aT) { myT = aT; }
    /**
     * Attempt to do private strange initialization with T, in the hope to provoke a cast exception
     */
    public StoreGerenericTypeInField()
    {
     StringBuilder aFirstType = new StringBuilder();
     StringBuffer aSecondType = new StringBuffer();
     this.list.add((T)aFirstType);
     this.list.add((T)aSecondType);
     System.out.println(this.list.get(0).getClass().getName());
     System.out.println(this.list.get(1).getClass().getName());

     setT((T)aFirstType);
     System.out.println(this.myT.getClass().getName());
     setT((T)aSecondType);
     System.out.println(this.myT.getClass().getName());
    }
    /**
     * @param args
     */
    public static void main(String[] args)
    {
     StoreGerenericTypeInField<Integer> s = new StoreGerenericTypeInField<Integer>();
    }
}

The constructor attempt to store nasty thing into its T variable (or its List of T)... and everything run smoothly!?

It prints:

java.lang.StringBuilder
java.lang.StringBuffer
java.lang.StringBuilder
java.lang.StringBuffer

The type erasure in in itself is not to blame... that is the combination of type erasure (new to java) and unsafe casting (java legacy old feature) which makes T truly out of reach at execution time (until you actually try to use it with 'T' specific methods)

VonC
Upvoted mostly for the amazement factor that you not only read that bit, but remembered it and bothered to find the right link :) (Oh, and because you're correct of course!)
Jon Skeet
Hmmm.... That would be mostly because I am in the process of watching your Copenhagen videos (I am at DEL 4) http://msmvps.com/blogs/jon_skeet/archive/2008/11/19/copenhagen-c-talk-videos-now-up.aspx.You began that presentation by reminding your audience about that distinction.
VonC
You're disturbing me more and more... Shame that I got it wrong almost *every* time I mentioned runtime/execution time during the day...
Jon Skeet
And yes, Jon, I will buy your book, I promise ;)
VonC
I disagree with the idea that type erasure isn't a problem. It means you just can't do T.class etc which is *so* handy. It may not be at fault for this particular code, but it's still a pain :(
Jon Skeet
And note that the compiler *knows* we're using unsafe/unchecked operations here - it's not like it compiles without warning.
Jon Skeet