Uncertainty about fix for JDK-5059679

Alex Buckley alex.buckley at oracle.com
Mon Feb 13 21:15:49 UTC 2023


On 2/13/2023 10:28 AM, Archie Cobbs wrote:
> public class NarrowingNameClash2 {
> 
>      public abstract class Upper<T> {
>          abstract void method(T param);
>      }
> 
>      public abstract class Lower<R> extends Upper<Class<R>> {
>          abstract void method(Class<?> param);   // name clash here???
>      }
> }

The core of all this is that method(Class<?>) in Lower<R> is not a 
subsignature of method(Class<R>) in Upper<Class<R>>.

This means that Lower<R> inherits method(Class<R>) from its direct 
superclass type Upper<Class<R>>. (See 8.4.8)

It's dangerous for Lower<R> to have method(Class<R>) and 
method(Class<?>) at the same time.

8.4.8.3 detects the problem.

The simple way to apply 8.4.8.3 is to set C = Lower and A = Upper, so 
that m1 = method(Class<?>) and m2 = method(Class<R>).

As you say, a compile-time error is due.

 > Side note/question: Presumably when Upper.method(T) is inherited by
 > Lower, its type changes from void method(T) to void method(Class<R>) -
 > correct? Is this actually stated anywhere?

8.2 says:

   The members of a class are all of the following:
     - Members inherited from its direct superclass type (§8.1.4) ...

The terminology of "class" versus "direct superclass type" is precise 
and deliberate. The members of the (generic) class Lower<R> include the 
members inherited from the direct superclass type of Lower<R>, which is 
Upper<Class<R>>. To be clear: Lower<R> is a (generic) class, 
Upper<Class<R>> is a (parameterized) type. The members inherited from 
Upper<Class<R>> will have R in their own signatures, not T.

If you added a flag to make javac enumerate the members of every generic 
class and every parameterized type seen in the program, it would be very 
useful.

> Now consider the same thing except using interfaces:
> 
> public class NarrowingNameClash {
> 
>      public interface Upper<T> {
>          void method(T param);
>      }
> 
>      public interface Lower<R> extends Upper<Class<R>> {
>          void method(Class<?> param);        // name clash here?
>      }
> }
> 
> According to my reading, interfaces do NOT inherit methods from 
> superinterfaces. 

You might be thinking about the private methods and static methods of an 
interface, which are indeed not inherited by a subinterface. Abstract 
methods in an interface have always been inherited by a subinterface 
(see 9.1.3), unless of course they are overridden (see 9.2).

The interface Lower<R> inherits method(Class<R>) from its direct 
superinterface type Upper<Class<R>>. (See 9.4.1)

No overriding occurs in 9.4.1.1, so 9.4.1.2 has no requirements.

It's OK for Lower<R> to have method(Class<R>) and method(Class<?>) at 
the same time. 9.4.2 describes the situation. The methods are not 
override-equivalent. No compile-time error is due.

A class can implement Lower<SomeType> by declaring a concrete method 
`public void method(Class p)`. Whether an interface should allow more 
overloading of members than a class is a design discussion that I do not 
propose to revisit today.

Alex


More information about the compiler-dev mailing list