Acces to private field from nested class when the type of reference is a generic type variable with upper bound of outer class

Dan Smith daniel.smith at oracle.com
Fri Oct 7 15:37:48 PDT 2011


On Oct 7, 2011, at 2:54 PM, Peter Levart wrote:

> And now for some puzzlers. Let's take that definition and a look at the following program:
> 
> 
> package test;
> 
> public class Test
> {
>    public static class A
>    {
>        public int field = 1;
>    }
> 
>    public static class B extends A
>    {
>        public int field = 2;
>    }
> 
>    public static class FieldGetter<T extends A>
>    {
>        public int getField(T obj)
>        {
>            return obj.field;
>        }
>    }
> 
>    public static void main(String[] args)
>    {
>        A a = new A();
>        B b = new B();
> 
>        FieldGetter<A> aFieldGetter = new FieldGetter<A>();
>        FieldGetter<B> bFieldGetter = new FieldGetter<B>();
> 
>        System.out.println(a.field); // 1
>        System.out.println(b.field); // 2
> 
>        System.out.println(aFieldGetter.getField(a)); // 1
>        System.out.println(aFieldGetter.getField(b)); // 1
> 
>        System.out.println(bFieldGetter.getField(b)); // 1 !!!
>    }
> }
> 
> 
> ... in FieldGetter the T is the most general type that is a subtype of A and any subtypes of A 
> (which includes B). Now A.field is inherited by any subtypes of A, but it can also be hidden by 
> fields of the same name in any of the subtypes of A (as is in the example by B.field).
> 
> The question is: How can compiler decide which field to access in T.getField method?
> 
> Would it be right to disallow "any" field access via the type-variable typed variables?
> 
> The joys of erasure!

This isn't a consequence of erasure.  It's a consequence of static field resolution (in contrast to dynamic resolution of methods).  The class referenced by a field name is determined at compile time.  Wouldn't matter if T were reified -- we'd still have to pick a field at compile time, and the only sound choice would be 'A.field'.

The fact that T is a type variable is, in a sense, irrelevant.  Given class T extends A and class B extends T, the same problem arises -- when the receiver is "really" a B (at runtime), a user might wish that a reference to 'field' in type T resolve to 'B.field', but that's not the way field references work.

—Dan


More information about the compiler-dev mailing list