Nonstatic nested interfaces can be used independent of instance of the enclosing class?

Asked

Viewed 96 times

4

I was reading about JsInterop and I come across an example of code:

package com.example;

@JsType
public class Bar {
    @JsFunction
    public interface Foo {
        int exec(int x);
    }

    public static int action1(Foo foo) {
        return foo.exec(40);
    }

    public static Foo action2() {
        return (x) -> x + 2;
    }
}

The question has nothing to do with JsInterop, was just where I took the example

Note that here, Foo is a nested interface within class Bar. Different than what I’m used to nested classes, Foo is not marked as static.

I know that if the nested class is not declared static, as for example:

package com.example;

public class Marm {

  public class Ota {
  }
}

every instance of the class Ota has a reference to Marm.this, passed as implicit argument to your constructor, and you can then access the private fields and methods of the class that encapsulates it:

package com.example;

public class Marm {

    public class Ota {
        @Override
        public String toString() {
            return "" + Marm.this.n;
        }
    }

    private int n;
    public Marm(int n) {
        this.n = n;
    }

    public static void main(String... args) {
        Ota a;
        // se eu fizesse: a = new Ota();
        // teria este erro: No enclosing instance of type Marm is accessible. Must qualify the allocation with an enclosing instance of type Marm (e.g. x.new A() where x is an instance of Marm).
        a = new Marm(5).new Ota();
        System.out.println(a); // imprime 5
    }
}

However, I have a question: a nested interface has the same effect if it were "static"? And, with Java 8 allowing methods default in interfaces, the nested interfaces are unrelated to the Marm.this and could not refer to it?

And, taking advantage, and as for the private and static methods of the class that enclosed it, the methods default could have access to them?

  • 1

    A nested interface is static for default: https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.5.1

  • 1

    @hkotsubo, reply by RTFM, I liked it. If I didn’t have duplication (I don’t think so), I think it’s worth an answer, however brief it is

1 answer

3


According to the language specification, a nested interface is static for default. That is, the two forms below are equivalent:

public class Foo {
    public interface Bar {
        void fazAlgo();
    }
}

// ou
public class Foo {
    public static interface Bar {
        void fazAlgo();
    }
}

In both cases, the interface will be used in the same way (statically):

package outro.pacote.completamente.diferente;

import pacote.onde.esta.foobar.Foo;

public class TestFoo {
    public static void main(String[] args) {
        Foo.Bar bar = new Foo.Bar() {
            @Override
            public void fazAlgo() {
                System.out.println("fazendo algo");
            }
        };
        bar.fazAlgo(); // imprime "fazendo algo"
    }
}

Or else:

// importando direto a interface
import pacote.onde.esta.foobar.Foo.Bar;

public class TestFoo {
    public static void main(String[] args) {
        Bar bar = () -> {
            System.out.println("fazendo algo");
        };
        bar.fazAlgo();
    }
}

In the above example, one could even note the interface Bar with @FunctionalInterface, although the documentation say it’s not mandatory: "the Compiler will Treat any interface Meeting the Definition of a Functional interface as a Functional interface regardless of whether or not a Functionalinterface Annotation is present on the interface declaration".

Important to note that the visibility rules are still valid: if the interface was not public, the class TestFoo I couldn’t see her.

And any attempt to access the interface in a non-static way will give build error. Ex:

Foo.Bar b = new Foo().new Bar() { // error: anonymous class implements interface; cannot have qualifier for new
    // etc...
};

So to summarize:

A nested interface has the same effect if it were "static"?

A nested interface is always static.

And, with Java 8 enabling methods default in interfaces, the nested interfaces are unrelated to the Marm.this and could not refer to it?

How they are static, are not associated with a specific instance and therefore cannot reference the this external class. So the code below does not compile:

public class Foo {

    private int x;

    public interface Bar {    
        void fazAlgo();

        default void metodoDefault() {
           // error: non-static variable this cannot be referenced from a static context
           System.out.println(Foo.this.x);
        }
    }
}

And, taking advantage, and as for the private and static methods of the class that enclosed it, the methods default could have access to them?

For private methods, the same problem occurs above. As the interface Bar cannot access Foo.this, so she can’t access the private methods of Foo.

For static methods, there is no problem in accessing them:

public class Foo {
    static void fooStatic() {
        System.out.println("método estático de Foo");
    }

    public interface Bar {
        void fazAlgo();

        default void metodoDefault() {
            Foo.fooStatic();
        }
    }
}

public class TestFoo {
    public static void main(String[] args) {
        Foo.Bar bar = () -> {};
        bar.metodoDefault(); // imprime "método estático de Foo"
    }
}

Remembering that a method default of an interface is automatically public, so I can call you in the example above.

It is also interesting to note that the above example would work even if the method fooStatic were private.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.