Submitted On 29-SEP-2004
kW
The example
GenericArrayTest<String> g = new GenericArrayTest<String>();
String[] ss = g.createAnArray(); // causes a ClassCastException
only is a valid example for an "unexpected" ClassCastException because at least one of those statements hold:
(1) The compiler was able to infer that the erasure of g.createAnArray() is Object[], but did not emit a warning or error.
(2) It is not true, that there is no reification of generic types in Java, rather: Reification is implemented in Java (and the JavaVM), but only partially. Reification is currently only implemented for arrays. Every array type (except Object[] itself) actually is a generic type, because:
(2.1) There are invariant statements about the type of what the array contains (e.g.: a String[] is an array which contains only objects of type String )
(2.2) Besides such a statements, all reference-type arrays are created equal (they all behave like Object[]). Thus, a String[] array does not differ from an List[] array, except that the invariant statement for the String[] array is different from the invariant statement for the Lis[] array.
(2.3) A generic type in relation to its raw type is not different to a reference-type array-type in relation to Object[], both generic type and reference-type array-type differ only from their raw counterparts by having additional invariant statements.
(2.4) But reification is only implemented for arrays, not for the other generic types. Thus the internal representation for array types (with reification) and other types (no reficiation, but erasure) is different, and thus, a ClassCastException like in the example above can arise.
If there was no reification of array types at all, the erasure of String[] would be Object[], and there would not be any ClassCastException
If there was full reification, there would not be any ClassCastException as well.
It is a kind of paradoxon, but because there exists a "legacy" way of implementing generic types (only for arrays), generic arrays (arrays which are both generic on the old way (not Object[]) and in the new way (member type is a generic type)) are problematic.
Submitted On 15-OCT-2004
jaubourg
This lack of RTTI makes for cumbersome workarounds. Let
Submitted On 15-OCT-2004
jaubourg
I think this could be handled optionally on a per class basis with simple annotation.
@RuntimeGenerics
class Checker<T> {
public boolean check(Object o) {
return o instanceof T;
}
public Class<T> getCheckedClass() {
return T.class;
}
}
Checker<Integer> checker = new Checker<Integer>();
Submitted On 03-JAN-2005
cowwoc
Please see http://forums.java.net/jive/thread.jspa?threadID=316 for a possible solution for the Generics binary-compatibility problem.
Submitted On 04-MAR-2005
cowwoc
As more code makes use of Generics, there is less and less need to support type-erasure. Sun should declare their intent to drop type-erasure in JDK 1.7 and provide runtime access to generic type parameters. That
Submitted On 06-MAR-2005
AlexLamSL
well, type-erasure is a decision not out of any benefition but backward-compatibility; and that's my question for the Java developers:
As of Tiger, the class files use a new format that is not backward-compatible with the older JREs, then why do we need type-erasure in these new file formats? I mean it should only be a feature that brings about when you instruct the compiler to make backward-compatible code, but not as a general contract.
Submitted On 06-MAY-2006
solmyr72
Please, please fix this !
1) J2EE is thriving on bean reflection/introspection !
This oversite *seriously* hinders tools for Object-relational mapping, web services (serialization to xml), etc... Sun started a great trend with java beans, so why ruin it now ?
2) Backward compatibility:
How about the "80-20" rule ?
Most organizations that migrate to java 5, upgrade the JRE anyway. Why make everyone suffer for the few that don't ? (And as I indicates it's a great deal of suffering).
3) If backwards compatibility is that important to you, how about adding some compiler flag, to turn off reification ? E.g:
> java -noReification ...
Thanks.
Submitted On 05-SEP-2006
return T[].class.cast(java.lang.reflect.Array.newInstance(T[].class, size));
Submitted On 05-SEP-2006
T[].class.cast(java.lang.reflect.Array.newInstance(T[].class, size));
Submitted On 25-SEP-2006
RomanPorotnikov
I believe T[].class part of Array.newInstance(T[].class, size) above is wrong.
The first argument of Array.newInstance(...) should be the type of array component, not the array type:
T[].class.cast(java.lang.reflect.Array.newInstance(T[].class.getComponentType(), size))
Submitted On 14-FEB-2007
enotecha
I think folks are missing one of the most annoying side effects of erasure in that you cannot really implement generic interfaces:
public class Foo implements Comparable<String>, Comparable<Integer> {
...
}
This doesn't work.
Submitted On 28-MAY-2007
cowwoc
Someone posted a prototype JVM that supports Reified Generics: http://japan.cs.rice.edu/nextgen/
Submitted On 29-MAY-2007
Jess_Holle
Having some the type information available at runtime somehow would be nice.
On the flip side, it depends which strings are attached to this.
For instance, if I have to use a whole new set of Collections classes to get this, then I'd say "no thanks". I don't want the Java code space being bifurcated into incompatible "reified and non-reified" ghettos which can only be crossed by copying collections, etc.
I'd propose
1) Having the information there to be programmatically queried for generics constructed from new (-source/-target) byte code,
2) Having this information automatically used by the compiler (e.g. for new T[]) without warnings when compiling to a recent enough byte code (ala -source/-target) when the compiler knows this information must exist (i.e. unless the developer lied to the compiler via an inappropriate cast, which would be the developer's fault), and
3) Allow this information to be automatically used by the compiler *with* a warning when the compiler cannot know whether the information exists.
Submitted On 29-MAY-2007
dhopwood
Here is an example in which:
- the compiler does not output any warnings;
- there are reflective operations, but none of those operations fail
at run-time;
- a non-reflective operation fails with a type error at run-time.
Note that this contradicts the often-stated position (e.g. in bug 5105887) that Java generics are statically typesafe when there are no compiler warnings. Adding full runtime type information for generics would not by itself fix this problem, but is a necessary prerequisite to fixing it.
import java.util.ArrayList;
import java.lang.reflect.*;
public class UnsafeGenerics {
public static void main(String[] args) {
// After type erasure, this is really an ArrayList of Object.
ArrayList<String> a = new ArrayList<String>();
// The reflection API can put a non-String into the ArrayList.
try {
Method m = ArrayList.class.getMethod("add", Object.class);
m.invoke(a, new Integer(42));
} catch (Exception e) {
System.err.println("reflective operation failed");
throw new RuntimeException(e);
}
// This doesn't provoke a warning, but fails with a
// ClassCastException at run-time.
String s = a.get(0); // line 32
}
}
>javac UnsafeGenerics.java
>java UnsafeGenerics
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer
cannot be cast to java.lang.String
at UnsafeGenerics.main(UnsafeGenerics.java:32)
>java -version
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)
>javac -version
javac 1.6.0_01
What is objectionable about this is that:
- the reflection API silently allowed an object to get into a state that violates its declared type;
- the compiler inserted an *implicit* cast that failed, without any warning.
Of course, in a real program the cast failure could be arbitrarily far
away (in time and code location) from the unsafe reflective operation.
Submitted On 06-JUN-2007
This is a very annoying feature. Can someone from Sun and/or other executive committee members at least explain why this was done, so we don't guess? I have read the comments and there are pros and cons, but I really think that language is the primary factor - backward compatibility is a great burden if you try to do it on such a low level. You should really sometimes admit that there is a need to change - and really this was a good moment to do that. Please change this in Java SE 7. Include things that would make programming in Java easier. You did a great job with annotations - look at other programming languages and include properties (instead of beans), regular expressions, etc. As someone said, it's a shame that 3 million Java programmers are not productive enough because of the backward compatibility. Java is here for how long - 12 years? I am sure you all understand that it must sometimes change - don't let everybody suffer for too long.
Submitted On 11-AUG-2007
As per a previous comment, I'll take interoperability with existing code over 100% type safety *any* day. The fact that I can write stupid code that ducks generic type safety is *not* a concern to me as this same ability allows me to write 100% type safe code that then passes collections, etc, efficiently to old, unsafe but implicitly trusted code. This ability trumps any ivory-tower 100% type safety arguments in my book.
All that said, it would be good to allow new code to use T in ways that assume T is not lost so that one doesn't have to pass an extra Class<T> to various methods. See my previous comment for ideas on achieving that without limiting interoperability with existing code.
Submitted On 10-FEB-2008
vrdesu-www
generic array creation is not allowed.Try following work-around.
ArrayList<Node>[] myarr = (ArrayList<Node>[])
Array.newInstance(ArrayList.class,n);
Ref : http://www.velocityreviews.com/forums/t295070-java-generic-issue-in-array.html
Submitted On 27-MAY-2008
T@sos
"javac transforms a generic Java program to a non-generic program with casts."
This is incorrect!
The correct is: "javac transforms a 'specific' (non-generic) Java program to a 'generic' program with casts." ;-)
Generics is a misnomer of what should be named Specifics!
Submitted On 27-MAY-2008
T@sos
I am voting for this though!
The current implementation is half-baked...
Submitted On 27-MAY-2008
T@sos
Keep in mind though that erasure doesn't completely erase all specific information.
Have a look at the Generics paragraph here:
"www.infoq.com/articles/groovy-1.5-new":
"through the reflection API, you are able to introspect a class to discover the types of its fields or of its methods arguments with the generics details."
Submitted On 05-JAN-2009
SteveP31415
Please extend TypeVariable to include at least the name of the type that is erased. I use generics in a control class that I reuse for a number of different objects. Now, I have to pass the Class of the types I specified so I can use .forName(). At a minimum, knowing the class would allow me to create a factory and pass the name.
Submitted On 05-FEB-2009
brettryan
I have a problem outlined in the following example, there's no way to find a generic type which makes it a pain in the backside for runtime reflection of a class that allows me to perform property assignment on objects, thus I am required to specify the class type in the constructor.
public class Action<E, OE> {
public Action(
final OE object,
final String property,
final E newValue,
final Class<E> type)
throws NoSuchMethodException,
IllegalAccessException,
InvocationTargetException {
// ... Arge checks
// ...Incance assignment....
this.object = object; // ...
Method m = object.getClass().getMethod("get" + property);
oldValue = (E) m.invoke(object);
completed = false;
}
public void perform() {
try {
if (completed || !isChangeRequired()) {
return;
}
Method m = obj.getClass().getMethod("set" + property, type);
m.invoke(obj, newValue);
this.completed = true;
performComplete();
} catch (Exception ex) {
LOG.error("Exception in perform: ", ex);
this.exception = ex;
}
}
}
Please don't flame me for this, but they managed to do it at Redmond, while this ends in two seperate packages one containing new generified versions of the old ungenerified versions it does seem to work well (just completely deprecating the old classes). They also solved the problem of `new T()' by having a construct that allows you to specify that a generic type must contain a default constructor
public class MyGen<T> where T : new() {
public T GetNew() {
return new T();
}
public T GetDefault() {
return default(T);
}
}
Submitted On 02-DEC-2009
JaedenStormes
The reflection library needs ability to say T.class, and get the same java.lang.Class<T> object I'd get if I explicitly knew the type of T. With this, I could get the majority of the stuff I need (typecasting without generating warnings, looking for Methods and Constructors, etc.)
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|