|
Replies:
11
-
Last Post:
Jan 15, 2006 4:42 AM
by: aviadbd
|
|
|
|
|
|
|
Identifying Generics
Posted:
Dec 17, 2005 9:56 PM
|
|
|
Anyone thought of adding the ability to discover which generics types are currently effective on a certain class?
Meaning: I have a field defined as:
Collection<Integer> myCollection;
Reflecting it's type would reveal only the type parameters (using getTypeParameters) which would be named "E" with no bounds. There is no way to get "Integer" with the current reflection ability - Even though the JRE could keep that information when a generic class is instantiated.
Two options I can see on doing that: * Saving the info for each instance. Adds some info to a class, indeed. * Creating a different Class for each type parameters set (like what's being done with arrays of different compound types and dimensions?). Might slow down reflection even more, but that's what reflection's all about.. 
Aviad.
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Dec 18, 2005 1:53 AM
in response to: aviadbd
|
|
|
Generics is implemented through type-erasure, hence the information that you want (Integer in Collection<Integer> ) would not be present in the class file.
Although I often find that such information can be rendered redundant by a change of design, when one needs to one can employ the following constructor pattern to preserve such information:
public class A<T> {
private final Class<T> type;
// Option 1 public A(T obj) // and other params { type = (Class<T> ) obj.getClass(); // ... }
// Option 2 public A(Class<T> type) // and other params { this.type = type; // ... }
}
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Dec 18, 2005 2:26 AM
in response to: alexlamsl
|
|
|
Oh I know about Erasure. You can read my thoughts about it, which are similar to what I wrote above, here: http://javachaos.blogspot.com/2005/12/avoiding-erasure.html
What I'm saying is that Erasure and keeping the identity of the generic types aren't contradictive. If the JVM is of version 6, it can save the data in Object or generate a different Class instance. That's my suggestion - To maintain this data during the runtime.
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Jan 9, 2006 10:09 AM
in response to: aviadbd
|
|
|
It seems to me that, if you don't do erasure, you have to add the generics information to the Object memory structure. For small objects this could be a substantial increase in overhead, plus a significant change in the JVM. And there are small generic objects (e.g. references).
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Jan 9, 2006 10:56 AM
in response to: soupdragon
|
|
|
Currently objects have a pointer to their runtime class information. If they had runtime generic parameter information, they would still only need a single pointer.
The necessary change is that instead of pointing to class information, a structure is referenced containing the old erased class pointer and pointers to the generic arguments. In most cases there would be a one-to-one correspondence between these type information structures and non-abstract classes, so the memory overhead is quite minimal.
Reference objects may be bigger than you expect. To be useful, they also need to point to something.
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Jan 9, 2006 11:47 AM
in response to: tackline
|
|
|
> Currently objects have a pointer to their runtime > class information. If they had runtime generic > parameter information, they would still only need a > single pointer. >
You could do it that way, of course, but wouldn't that signifcantly increase access times to class, which I presume the JVM needs to do rather a lot?
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Jan 9, 2006 1:12 PM
in response to: soupdragon
|
|
|
> You could do it that way, of course, but wouldn't > that signifcantly increase access times to class, > which I presume the JVM needs to do rather a lot?
Not significantly. One extra load. It's not like anyone cares too much about "virtual" method call overhead as it is. I'd be surprised if reduction in runtime type checking didn't more than make up for the penalty.
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Jan 9, 2006 11:47 AM
in response to: tackline
|
|
|
Also, you need to remember that the data needs to be stored in the bytecode of the .class file itself. Currently, it doesn't seem like instances in inner scopes carry on their generic definitions.
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Jan 15, 2006 4:42 AM
in response to: aviadbd
|
|
|
Basically, it sounds like its about claiming that some things just won't work on earlier JVMs. Or, produce a minor version for each that knows to ignore this extra data in the .class files.
I don't know the exact complications of it. Anyone?
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Dec 18, 2005 3:17 AM
in response to: aviadbd
|
|
|
It's retrieving full type information from objects which is the problem (as it doesn't exist). Type information from fields and the like is straightforward. I put a little code together to dump a field's type.
import java.lang.reflect.*;
class DumpFieldType { public static void main(String[] args) throws Throwable { dumpFieldType(Example.class, "field"); } private static void dumpFieldType( Class<?> clazz, String fieldName ) throws Throwable { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); dumpType(field.getGenericType()); dump("\n"); } private static void dumpType(Type type) { if (type instanceof GenericArrayType) { // Type[] GenericArrayType t = (GenericArrayType)type; dumpType(t.getGenericComponentType()); dump("[]"); } else if (type instanceof ParameterizedType) { // TypeA<X>.TypeB<Y, Z> or Map.Entry<String,Object> ParameterizedType t = (ParameterizedType)type; Type owner = t.getOwnerType(); if (owner != null) { dumpType(owner); dump("."); } dumpType(t.getRawType()); Type[] actualTypes = t.getActualTypeArguments(); if (actualTypes != null) { dump(""); } } else if (type instanceof TypeVariable) { // T extends X&Y TypeVariable t = (TypeVariable)type; dump(t.getName()); dumpUpperBounds(t.getBounds()); } else if (type instanceof WildcardType) { // ? extends X&Y super Z WildcardType t = (WildcardType)type; dump("?"); dumpUpperBounds(t.getUpperBounds()); dumpTypes(" super " , "|", t.getLowerBounds()); } else if (type instanceof Class) { // Type Class t = (Class)type; dump(t.getSimpleName()); } else if (type == null) { // We probably messed up. dump("?[? null ?]?"); } else { // Eh? dump("?[" + type.getClass() + "]?"); } } private static void dumpUpperBounds(Type[] types) { if (types.length == 1 && types[0] == Object.class) { return; } dumpTypes(" extends ", "&", types); } private static void dumpTypes(String prefix, String sep, Type[] types) { String s = prefix; for (Type type : types) { dump(s); dumpType(type); s = sep; } } private static void dump(String str) { System.out.print(str); } }
import java.util.Collection;
public class Example { private Collection<Integer> field; }
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Dec 18, 2005 9:10 AM
in response to: tackline
|
|
|
However, as you stated yourself, this is only accessible through methods and fields. What happens if I get a POJO?
And it should be much simpler than what you've shown. Seriously, we're not talking about a language for rocket scientists. This is something that the framework Could know about, just chooses not to! It should be simple to access it.
|
|
|
|
|
|
|
|
Re: Identifying Generics
Posted:
Dec 19, 2005 9:27 PM
in response to: aviadbd
|
|
|
What about a parameter to the compiler? When -no-erasure is specified, it will Not perform erasure. The code will Not be compatible and runnable at JVMs lower than 1.4, and any method in Class which would normally return the parameter types' Real types would return an empty list (or a list of the highest bound, as left currently by erasure).
Would that make more sense?
|
|
|
|
|