The supertype of anonymous class is expected to be a raw type

Georgiy Rakov georgiy.rakov at oracle.com
Tue Aug 4 16:08:42 UTC 2015


Hello Alex,

sorry for the mistakes made.... but it seems another one has been 
made..... that is assertion I specified in step 1 covers 
diamond-expression-cases only, namely this assertion:

    - The superclass or superinterface type of the anonymous class is
    the return type, T, determined for mj (15.12.2.6).

but the original example provided type arguments instead; so the 
consequent steps (that is all of them) were wrong and according to 
following assertions 
<https://bugs.openjdk.java.net/browse/JDK-8073593?focusedCommentId=13622110&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13622110> 
the supertypes of anonymous classes should be parameterized when type 
arguments for class are provided:

    If ***'Identifier' refers to*** a class, ***C***, then an anonymous
    direct subclass of ***C*** is declared. ***/_*The type arguments to
    C, if any, are given by [TypeArgumentsOrDiamond]*_/, or, if this
    denotes '<>', will be inferred in 15.9.3.*** The body of the
    subclass is the ClassBody given in the class instance creation
    expression.

    ***If 'Identifier' refers to an interface, I, then an anonymous
    direct subclass of 'Object' that implements I is declared. /_*The
    type arguments to I, if any, are given by
    [TypeArgumentsOrDiamond]*_/, or, if this denotes '<>', will be
    inferred in 15.9.3. The body of the anonymous class is the ClassBody
    given in the class instance creation expression.***

.... it seems it's better to continue this thread because of the mess 
having been discovered; and thanks, I've taken into account the issues 
you found in my original letter .....

So the conclusion I made earlier seems to be wrong now. However it looks 
strange that, say, constructor invocation type, determines anonymous 
class supertypes for diamond cases only. So could you please tell if 
this is really the intention of the spec. For instance code below 
outputs that just for diamond case anonymous class super class is not 
parameterized:

    When class type arguments are given, the super type is parameterized.
    When class type arguments and ctor type arguments are given, the
    super type is parameterized.
    When diamond is used, the super type is /_*not*_/ parameterized.

The code:

    import java.lang.reflect.ParameterizedType;

    class MyType<T> {}

    public class Test24  {
         public static void main(String argv[]) {
             Bar foo;
             boolean isParameterized;

             foo =new Bar<String>("str",new MyType()){ };
             isParameterized = foo.getClass().getGenericSuperclass()instanceof ParameterizedType;
             System.out.println("When class type arguments are given, the super type is " + (isParameterized?"":"not ") +"parameterized.");

             foo =new <String>Bar<String>("str",new MyType()){ };
             isParameterized = foo.getClass().getGenericSuperclass()instanceof ParameterizedType;
             System.out.println("When class type arguments and ctor type arguments are given, the
    super type is " + (isParameterized?"":"not ") +"parameterized.");

             foo =new Bar<>("str",new MyType()){ };
             isParameterized = foo.getClass().getGenericSuperclass()instanceof ParameterizedType;
             System.out.println("When diamond is used, the super type is " + (isParameterized?"":"not ") +"parameterized.");
         }
    }

    class Bar<T> {
         public <U> Bar(T a1, MyType<U> a2){ }
    }

Thanks, Georgiy.
On 03.08.2015 21:53, Alex Buckley wrote:
> Georgiy, Good analysis but you have a non-generic ctor in class Bar<T> 
> (the class is generic but the ctor isn't). You also seem to say that 
> the return type of the method derived from the ctor is MyType, but 
> it's obviously Bar. I don't actually disagree with your conclusion 
> since 15.12.2.6 would still give raw Bar as the return type for the 
> non-generic ctor. But it would be helpful to clarify your mail and 
> restart the thread. Alex On 8/3/2015 5:46 AM, Georgiy Rakov wrote:
>> Hello, let's consider following example:     
>> importjava.lang.reflect.Type;     
>> importjava.lang.reflect.ParameterizedType;     classMyType<T> {}     
>> public classTest22  {          public static voidmain(String argv[]) 
>> {              Bar foo =new<String>Bar<String>("str",newMyType()){ }; 
>>              Type actualSuperType = 
>> foo.getClass().getGenericSuperclass();              if( 
>> actualSuperTypeinstanceofParameterizedType ) {                  
>> System.out.println("Parameterized");              }          }     } 
>>     classBar<T> {          publicBar(Ta1, MyType<String> a2){ }     } 
>> When compiled and run by JDK9b75 "Parameterized" is printed. However 
>> according to my understanding it shouldn't have to. The reasons for 
>> this are presented below: 1. According to the following assertion 
>> specified in JDK-8073593 
>> <https://bugs.openjdk.java.net/browse/JDK-8073593?focusedCommentId=13612188&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13612188> 
>> the superclass of anonymous class should be equal to the return type 
>> of the method derived from Bar class constructor:     - The 
>> superclass or superinterface type of the anonymous class is     the 
>> return type, T, determined for mj (15.12.2.6). 2. The second actual 
>> argument for the constructor is of a raw type MyType while the 
>> corresponding formal parameter is a parameterized type 
>> MyType<String>. So unchecked conversion is necessary in order for the 
>> only Bar constructor to become applicable for the provided 
>> invocation. 3. According to assertion presented above the return type 
>> is determined by 15.12.2.6 which states following:   * If the chosen 
>> method is generic and the method invocation provides     explicit 
>> type arguments, let Pi be the type parameters of the method     and 
>> let Ti be the explicit type arguments provided for the method     
>> invocation (1 ≤ i ≤ p). Then:       o If unchecked conversion was 
>> necessary for the method to be         applicable, then the 
>> invocation type's parameter types are         obtained by applying 
>> the substitution [P1:=T1, ..., Pp:=Tp] to         the parameter types 
>> of the method's type, and the invocation         type's return type 
>> and thrown types are given by the erasure of         the return type 
>> and thrown types of the method's type. Namely it says that the return 
>> type of the invocation type is the erasure of the return type of the 
>> method's type, provided unchecked conversion was necessary for the 
>> method to be applicable. According to step 2 unchecked conversion was 
>> necessary for the method to be applicable so the return type of the 
>> method is the erasure of MyType<! T>, i .e. MyType. 4. So according 
>> to step 1 given above the superclass of the anonymous class is MyType 
>> which is a raw type, that is, it shouldn't not considered as a 
>> parameterized one. 5. As a resultgetGenericSuperclass method should 
>> return an instance of a class not implementing ParameterizedType 
>> interface, but actually it returns an instance of a class 
>> implementing ParameterizedType interface. Could you please tell if 
>> you consider this as a bug. Please note that javap prints following 
>> when it runs against anonymous class Test22$1:     final class 
>> Test22$1 extends *Bar<java.lang.String>* {     
>> Test22$1(java.lang.String, MyType);} So if this is a bug it seems to 
>> be javac bug. Thanks, Georgiy. 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20150804/8740aaaa/attachment-0001.html>
-------------- next part --------------
import java.lang.reflect.ParameterizedType;

class MyType<T> {}

public class Test24  {
    public static void main(String argv[]) {
        Bar foo;
        boolean isParameterized;

        foo = new Bar<String>("str", new MyType()){ };
        isParameterized = foo.getClass().getGenericSuperclass() instanceof ParameterizedType;
        System.out.println("When class type arguments are given, the super type is " + (isParameterized? "": "not ") + "parameterized.");

        foo = new <String>Bar<String>("str", new MyType()){ };
        isParameterized = foo.getClass().getGenericSuperclass() instanceof ParameterizedType;
        System.out.println("When class type arguments and ctor type arguments are given, the super type is " + (isParameterized? "": "not ") + "parameterized.");

        foo = new Bar<>("str", new MyType()){ };
        isParameterized = foo.getClass().getGenericSuperclass() instanceof ParameterizedType;
        System.out.println("When diamond is used, the super type is " + (isParameterized? "": "not ") + "parameterized.");
    }
}

class Bar<T> {
    public <U> Bar(T a1, MyType<U> a2){ }
}


More information about the compiler-dev mailing list