Why is super.super.method(); not allowed in Java? Why is super.super.method(); not allowed in Java? java java

Why is super.super.method(); not allowed in Java?


It violates encapsulation. You shouldn't be able to bypass the parent class's behaviour. It makes sense to sometimes be able to bypass your own class's behaviour (particularly from within the same method) but not your parent's. For example, suppose we have a base "collection of items", a subclass representing "a collection of red items" and a subclass of that representing "a collection of big red items". It makes sense to have:

public class Items{    public void add(Item item) { ... }}public class RedItems extends Items{    @Override    public void add(Item item)    {        if (!item.isRed())        {            throw new NotRedItemException();        }        super.add(item);    }}public class BigRedItems extends RedItems{    @Override    public void add(Item item)    {        if (!item.isBig())        {            throw new NotBigItemException();        }        super.add(item);    }}

That's fine - RedItems can always be confident that the items it contains are all red. Now suppose we were able to call super.super.add():

public class NaughtyItems extends RedItems{    @Override    public void add(Item item)    {        // I don't care if it's red or not. Take that, RedItems!        super.super.add(item);    }}

Now we could add whatever we like, and the invariant in RedItems is broken.

Does that make sense?


I think Jon Skeet has the correct answer. I'd just like to add that you can access shadowed variables from superclasses of superclasses by casting this:

interface I { int x = 0; }class T1 implements I { int x = 1; }class T2 extends T1 { int x = 2; }class T3 extends T2 {        int x = 3;        void test() {                System.out.println("x=\t\t"          + x);                System.out.println("super.x=\t\t"    + super.x);                System.out.println("((T2)this).x=\t" + ((T2)this).x);                System.out.println("((T1)this).x=\t" + ((T1)this).x);                System.out.println("((I)this).x=\t"  + ((I)this).x);        }}class Test {        public static void main(String[] args) {                new T3().test();        }}

which produces the output:

x=              3super.x=        2((T2)this).x=   2((T1)this).x=   1((I)this).x=    0

(example from the JLS)

However, this doesn't work for method calls because method calls are determined based on the runtime type of the object.


I think the following code allow to use super.super...super.method() in most case.(even if it's uggly to do that)

In short

  1. create temporary instance of ancestor type
  2. copy values of fields from original object to temporary one
  3. invoke target method on temporary object
  4. copy modified values back to original object

Usage :

public class A {   public void doThat() { ... }}public class B extends A {   public void doThat() { /* don't call super.doThat() */ }}public class C extends B {   public void doThat() {      Magic.exec(A.class, this, "doThat");   }}public class Magic {    public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,            String methodOfParentToExec) {        try {            Type type = oneSuperType.newInstance();            shareVars(oneSuperType, instance, type);            oneSuperType.getMethod(methodOfParentToExec).invoke(type);            shareVars(oneSuperType, type, instance);        } catch (Exception e) {            throw new RuntimeException(e);        }    }    private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,            SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {        Class<?> loop = clazz;        do {            for (Field f : loop.getDeclaredFields()) {                if (!f.isAccessible()) {                    f.setAccessible(true);                }                f.set(target, f.get(source));            }            loop = loop.getSuperclass();        } while (loop != Object.class);    }}