JDK-6184881 : Object.getClass() typing rule could be improved
  • Type: Enhancement
  • Component: specification
  • Sub-Component: language
  • Affected Version: 5.0,6,7
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: linux,windows_xp,windows_7
  • CPU: x86
  • Submitted: 2004-10-26
  • Updated: 2015-04-18
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
The jls3 states that for a given t of type T,
t.getClass() is typed Class<? extends erasure(T)>.

I think the getClass() typing rule could be changed to
Class<? extends wildcard(T)>

The wildcard operation is defined by:
if T is parametrized, wildcard(T)=erasure(T)<?>
else                           , wildcard(T)=T

1) This rule introduce a raw type.
     Raw type must ONLY be used to interact with legacy code.

2) The new Rule introduce a wildcard.
     Relationship between parametrized type and wildcard are based
     on subtyping rules.
     Relationship between parametrized type and wildcard are based
     on raw type conversion.

the program must not compile
the program compile

---------- BEGIN SOURCE ----------
public void f(ArrayList<Integer> l1, ArrayList<String> l2)
   throws InstantiationException, IllegalAccessException {

---------- END SOURCE ----------

public Class<? extends ArrayList<?>> wildcardGetClass(ArrayList<?> list) {
    return (Class<? extends ArrayList<?>>)list.getClass();
  public void f(ArrayList<Integer> l1, ArrayList<String> l2)
     throws InstantiationException, IllegalAccessException {
###@###.### 10/26/04 22:47 GMT

I'd love to eliminate this spec-mandated use of a raw type from the language. On the other hand, we need to be careful about compatibility -- class objects are widely used, and subtle changes in their types could break a lot of source code.

EVALUATION The erasure of ArrayList<Integer> and ArrayList<String> to ArrayList, in Class<? extends ArrayList>, allows the unsound addition of a String in an Integer collection. (Though an unchecked warning is raised by javac.) The proposal means that getClass() would return a Class<? extends ArrayList<?>> object, which is incompatible with other Class<? extends ArrayList<?>> objects. This is compatible with existing code like: List<String> l = ... Class<? extends List> c = l.getClass(); because the new type of the RHS, Class<? extends List<?>>, is a subtype of Class<? extends List>. Note that the proposed return type: Class<? extends wildcard(T)>, where wildcard(T)=erasure(T)<?> if T is parameterized... is not rich enough, because the type of new Foo<Integer,String>.getClass() becomes Class<? extends Foo<?>> whereas the "right" answer is Class<? extends Foo<?,?>> The correct definition is wildcard(T<A1..An>)=T<?,..,?> (i.e. n wildcards) A disadvantage of enriching Class's type argument is that it will break idiomatic use of Class.cast. Today, you can write: List<Integer> x = ...; Class<? extends List> cl = x.getClass(); List<Integer> y = cl.cast(null); and get a warning at cast(), because of the unchecked conversion from List to List<Integer>. But with the proposal, the analogous code doesn't compile: List<Integer> x = ...; Class<? extends List<?>> cl = x.getClass(); List<Integer> y = cl.cast(null); because List<?> returned by cast() cannot be converted to List<Integer>. The only way to avoid the error is to cast cl.cast(..) up to List and suffer the unchecked conversion warning to List<Integer>. This is effectively what getClass() does already. Overall, the proposal seems like a good idea, but it has moderate complexity and a fairly small payoff.