Java语法之内部接口的学习 —— What Is Inner Interface in Java?

 

What is Inner Interface in Java?

Inner interface is also called nested interface, which means declare an interface inside of another interface. For example, the Entry interface is declared in the Map interface.

public interface Map {
    interface Entry{
        int getKey();
    }
 
    void clear();
}

Why Use Inner Interface?

There are several compelling reasons for using inner interface:

  • It is a way of logically grouping interfaces that are only used in one place.
  • It increases encapsulation.
  • Nested interfaces can lead to more readable and maintainable code.

One example of inner interface used in java standard library is java.util.Map and Java.util.Map.Entry. Here java.util.Map is used also as a namespace. Entry does not belong to the global scope, which means there are many other entities that are Entries and are not necessary Map's entries. This indicates that Entry represents entries related to the Map.

How Inner Interface Works?

To figure out how inner interface works, we can compare it with nested classes. Nested classes can be considered as a regular method declared in outer class. Since a method can be declared as static or non-static, similarly nested classes can be static and non-static. Static class is like a static method, it can only access outer class members through objects. Non-static class can access any member of the outer class.

java-nested-classes

Because an interface can not be instantiated, the inner interface only makes sense if it is static. Therefore, by default inter interface is static, no matter you manually add static or not.

A Simple Example of Inner Interface?

Map.java

public interface Map {
    interface Entry{
        int getKey();
    }
 
    void clear();
}

MapImpl.java

public class MapImpl implements Map {
 
 
    class ImplEntry implements Map.Entry{
        public int getKey() {
            return 0;
        }        
    }
 
    @Override
    public void clear() {
        //clear
    }
}

 

 Thinking in java


Interfaces may be nested within classes and within other interfaces. This reveals a number of very interesting features:

//: c08:nesting:NestingInterfaces.java
package c08.nesting;

class A {
  interface B {
    void f();
  }
  public class BImp implements B {
    public void f() {}
  }
  private class BImp2 implements B {
    public void f() {}
  }
  public interface C {
    void f();
  }
  class CImp implements C {
    public void f() {}
  }
  private class CImp2 implements C {
    public void f() {}
  }
  private interface D {
    void f();
  }
  private class DImp implements D {
    public void f() {}
  }
  public class DImp2 implements D {
    public void f() {}
  }
  public D getD() { return new DImp2(); }
  private D dRef;
  public void receiveD(D d) {
    dRef = d;
    dRef.f();
  }
}

interface E {
  interface G {
    void f();
  }
  // Redundant "public":
  public interface H {
    void f();
  }
  void g();
  // Cannot be private within an interface:
  //! private interface I {}
}

public class NestingInterfaces {
  public class BImp implements A.B {
    public void f() {}
  }
  class CImp implements A.C {
    public void f() {}
  }
  // Cannot implement a private interface except
  // within that interface's defining class:
  //! class DImp implements A.D {
  //!  public void f() {}
  //! }
  class EImp implements E {
    public void g() {}
  }
  class EGImp implements E.G {
    public void f() {}
  }
  class EImp2 implements E {
    public void g() {}
    class EG implements E.G {
      public void f() {}
    }
  }
  public static void main(String[] args) {
    A a = new A();
    // Can't access A.D:
    //! A.D ad = a.getD();
    // Doesn't return anything but A.D:
    //! A.DImp2 di2 = a.getD();
    // Cannot access a member of the interface:
    //! a.getD().f();
    // Only another A can do anything with getD():
    A a2 = new A();
    a2.receiveD(a.getD());
  }
} ///:~

 

The syntax for nesting an interface within a class is reasonably obvious, and just like non-nested interfaces, these can have public or package-access visibility. You can also see that bothpublic and package-access nested interfaces can be implemented as public, package-access, and private nested classes.

As a new twist, interfaces can also be private, as seen in A.D (the same qualification syntax is used for nested interfaces as for nested classes). What good is a private nested interface? You might guess that it can only be implemented as a private inner class as in DImp, but A.DImp2 shows that it can also be implemented as a public class. However, A.DImp2 can only be used as itself. You are not allowed to mention the fact that it implements the private interface, so implementing a private interface is a way to force the definition of the methods in that interface without adding any type information (that is, without allowing any upcasting).

The method getD( ) produces a further quandary concerning the private interface: It’s a public method that returns a reference to a private interface. What can you do with the return value of this method? In main( ), you can see several attempts to use the return value, all of which fail. The only thing that works is if the return value is handed to an object that has permission to use it—in this case, another A, via the receiveD( ) method.

Interface E shows that interfaces can be nested within each other. However, the rules about interfaces—in particular, that all interface elements must be public—are strictly enforced here, so an interface nested within another interface is automatically public and cannot be made private.

NestingInterfaces shows the various ways that nested interfaces can be implemented. In particular, notice that when you implement an interface, you are not required to implement any interfaces nested within. Also, private interfaces cannot be implemented outside of their defining classes.

Initially, these features may seem like they are added strictly for syntactic consistency, but I generally find that once you know about a feature, you often discover places where it is useful.

 

Stackoverflow


The static keyword in the above example is redundant (a nested interface is automatically "static") and can be removed with no effect on semantics; I would recommend it be removed. The same goes for "public" on interface methods and "public final" on interface fields - the modifiers are redundant and just add clutter to the source code.

Either way, the developer is simply declaring an interface named Foo.Bar. There is no further association with the enclosing class, except that code which cannot access Foo will not be able to access Foo.Bar either. (From source code - bytecode or reflection can access Foo.Bar even if Foo is package-private!)

It is acceptable style to create a nested interface this way if you expect it to be used only from the outer class, so that you do not create a new top-level name. For example:

 

 

public class Foo {
    public interface Bar {
        void callback();
    }
    public static void registerCallback(Bar bar) {...}
}
// ...elsewhere...
Foo.registerCallback(new Foo.Bar() {
    public void callback() {...}
});
posted on 2016-01-02 07:32  gyt929458988  阅读(864)  评论(0编辑  收藏  举报