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 :  
Description
A DESCRIPTION OF THE REQUEST :
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
    

JUSTIFICATION :
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.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the program must not compile
ACTUAL -
the program compile

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

    l1.getClass().newInstance().addAll(l2.getClass().newInstance());
  }
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
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 {
      wildcardGetClass(l1).newInstance().addAll(
         wildcardGetClass(l2).newInstance());
  }
###@###.### 10/26/04 22:47 GMT

Comments
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.
07-03-2015

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.
31-10-2006