if we can use "T.class"
/**
* this class can not be compiled in jdk5.0
*/
publicclass GenericClass<T>{
public T someMethod()throws Exception{
return T.class.newInstance();
}
publicstaticvoid main(String[] args){
GenericClass<Object> foo =new GenericClass<Object>();
System.out.println(foo.someMethod().getClass());
}
}
/**
* so we have to write more codes
*/
publicclass GenericClass<T>{
private Class<T> clsOfT;
public GenericClass(Class<T> clsOfT){
this.clsOfT = clsOfT;
}
public T someMethod()throws Exception{
return clsOfT.newInstance();
}
publicstaticvoid main(String[] args){
GenericClass<Object> foo =new GenericClass<Object>(Object.class);
System.out.println(foo.someMethod().getClass());
}
}
/**
* but why not to ask compiler to do that for us ?
*/
publicclass GenericClass<T>{
// private Class<T> clsOfT; // compiler will do this job
public T someMethod()throws Exception{
return T.class.newInstance();// compiler will replace T.class with clsOfT
}
publicstaticvoid main(String[] args){
GenericClass<Object> foo =new GenericClass<Object>();
// foo.clsOfT = Object.class; // compiler will do this job
System.out.println(foo.someMethod().getClass());
}
}
[3161 byte] By [
zxcca] at [2007-10-3 5:26:24]

I've often wondered this. Just like the implicit 'this' parameter, why not give constructors an implicit Class parameter for each of the type parameters and automatically use them in any expression involving the type parameters.
I guess the answer is something to do with backward compatibility.
The answer is that T.class doesn't really exist, or to put it another way it is really only Object.class, or whatever further constraint you put on it. Calling it T just names it but there is no actual 'instance' of the class for each different T.
So there is no way to implement it.
Generics are not C++ templates.
ejpa at 2007-7-14 23:33:39 >

ejp, I think you may have missed the point.
There is no reason why the compiler can't add additional hidden parameters to the constructor of type class (one for each type parameter) and then provide values for those parameters when parameterised objects are constructed. It knows the concrete types of the type parameters.
If we can write code according to the "type token" pattern, there is no reason why the compiler can't do it automatically for us.
This is very similar to the implicit 'this' parameter provided on non-static method calls.
However, this will also change the signature of the constructor, so it will break compatibility with old code. This could be solved by also automatically providing a regular constructor which sets the type tokens to Object.class.
Or, to put it in more concrete terms, why, when I write this:
public class TypeTokens<T, U> {
private String blah;
public TypeTokens(String blah) {
this.blah = blah;
}
public void doSomething() {
// Make a new T (doesn't work today)
T t = T.newInstance();
}
public void testMe() {
new TypeTokens<Integer, String>("one");
new TypeTokens<NumberFormat, Socket>("two");
}
}
can't the compiler emit bytecode equivalent to this:
public class TypeTokens<T, U> {
private Class<T> $classT;
private Class<U> $classU;
private String blah;
public TypeTokens(Class<T> $classT, Class<U> $classU, String blah) {
this.$classT = $classT;
this.$classU = $classU;
this.blah = blah;
}
public void doSomething() {
// Make a new T (doesn't work today)
T t = $classT.newInstance();
}
public void testMe() {
new TypeTokens<Integer, String>(Integer.class, String.class, "one");
new TypeTokens<NumberFormat, Socket>(NumberFormat.class, Socket.class, "two");
}
}
But I think we needn't change the signature of constructor,
compiler can initialize those implecit fields after construction
of generic class like this:
public class TypeTokens<T, U> {
private Class<T> $classT = null;
private Class<U> $classU = null;
private String blah;
public TypeTokens(String blah) {
this.blah = blah;
}
public void doSomething() {
// Make a new T (doesn't work today)
T t = $classT.newInstance();
}
public void testMe() {
new TypeTokens<Integer, String>("one") foo;
foo.$classT = Integer.class;
foo.$classU = String.class;
new TypeTokens<NumberFormat, Socket>("two") bar;
bar.$classT = Integer.class;
bar.$classU = String.class;
}
}
zxcca at 2007-7-14 23:33:39 >

nullnull
zxcca at 2007-7-14 23:33:39 >

sorry!
But I think we needn't change the signature of constructor,
compiler can initialize those implicit fields after construction
of generic class like this:
public class TypeTokens<T, U> {
private Class<T> $classT = null;
private Class<U> $classU = null;
private String blah;
public TypeTokens(String blah) {
this.blah = blah;
}
public void doSomething() {
// Make a new T (doesn't work today)
T t = $classT.newInstance();
}
public void testMe() {
TypeTokens<Integer, String>("one") foo = new TypeTokens<Integer, String>("one") ;
foo.$classT = Integer.class;
foo.$classU = String.class;
TypeTokens<NumberFormat, Socket>("two") bar = new TypeTokens<NumberFormat, Socket>("two");
bar.$classT = NumberFormat.class;
bar.$classU = Socket.class;
}
}
zxcca at 2007-7-14 23:33:39 >

Either way! I don't think the actual implementation is important. What is important is that the compiler could very easily help in this space.
Well, yes, I had several situations, where it would have been helpful to know about the generic parameters at runtime, but I cannot see the major advantage compared to extending the constructor to take classes and infer the parameters, if knowing about the class is really necessary:
// old
new TypeTokens(U.class, V.class);
// new
new TypeTokens<U, V>();
For the newInstance() stuff: in many cases, T will be neither final nor concrete, hence, having a hand on the class object does not really help.
> Either way! I don't think the actual implementation
> is important. What is important is that the compiler
> could very easily help in this space.
Unfortunately, it's not as easy as that.
You'd only gain runtime access to unparameterized type parameters.
(You still wouldn't get the real type parameters of, e.g. an ArrayList<List><String>>.)
This would take you just one step further than the present situation, without solving the underlying problem:
all instantiations of a parameterized type share the same class object.
You can do completely without adding "hidden fields" to every generic class if you put the full type information into java.lang.Class.
This would, of course, be completely incompatible with previous Java versions!
A full implementation of this concept (using fictitious method names) would make something like this possible:
List<?> list1 = new ArrayList<String>();
List<?> list2 = new ArrayList<List><Integer>>();
assert list1.getClass() != list2.getClass();
assert list1.getClass().getRawType() == list2.getClass().getRawType();
assert list2.getClass().getTypeParameters()[0] == List<Integer>.class;
