Three ways to use nested interfaces in your Java code Credit: FILO / Aleksei Derin / Getty Images If you’ve read my Java 101 tutorial introducing static classes and inner classes, you should be familiar with the basics of working with nested classes in Java code. In this Java tip, you’ll learn three common ways to use nesting techniques with Java interfaces. I’ll also briefly demonstrate nesting interfaces with static methods, also known as static method interfaces. Nesting interfaces in classes Java lets you declare interfaces inside of classes. Once declared, an interface is automatically a static member of the class. There is no need to declare the interface with the static keyword. Consider the following example: class EnclosingClass { interface EnclosedInterface1 { } static interface EnclosedInterface2 { } } EnclosedInterface1 and EnclosedInterface2 are static member interfaces. There’s no equivalent to local classes because interfaces cannot be declared in blocks. However, interfaces can be used in anonymous class contexts. Nested interfaces are typically not accessed from beyond their enclosing classes. Otherwise, you could declare them as top-level interfaces. Instead, they’re accessed from inside their enclosing classes, as demonstrated here: class EnclosingClass { interface EnclosedInterface1 { } static interface EnclosedInterface2 { } static class EnclosedClass1 implements EnclosedInterface1, EnclosedInterface2 { } class EnclosedClass2 implements EnclosedInterface1, EnclosedInterface2 { } void m() { class EnclosedClass3 implements EnclosedInterface1, EnclosedInterface2 { } new EnclosedInterface1() { }; } } Note that static member class EnclosedClass1, non-static member class EnclosedClass2, and local class EnclosedClass3 implement both nested interfaces. However, only one interface can be implemented in an anonymous class context. (See Static classes and inner classes in Java for more about anonymous classes.) Nesting interfaces in interfaces Java also lets you declare interfaces inside of interfaces. In this case, a nested interface is a static member of its enclosing interface, and once again the static keyword is redundant. Also, the nested interface is implicitly public. Here’s an example: interface EnclosingInterface { interface EnclosedInterface1 // implicitly static and public { } static interface EnclosedInterface2 // explicitly static and implicitly public { } } You access an enclosed interface by prefixing its name with the enclosing interface’s name and member access operator. For example, specify EnclosingInterface.EnclosedInterface1 to access EnclosedInterface1. Nesting classes in interfaces One of Java’s stranger language features is the ability to nest a class inside an interface. As with a nested interface, the nested class is implicitly public and static. Here’s an example: interface EnclosingInterface { class EnclosedClass { } } Despite its strangeness, being able to nest a class inside an interface can be useful, especially when there is a tight relationship between the enclosing interface and the enclosed class. Capturing this relationship improves the source code’s readability. In cases where the class and interface carry the same name, nesting can also help you avoid a name conflict between the two. Example: Addressable interface encloses Address class Suppose you want to model addressable entities such as letters, postcards, and parcels. Each entity will be described by its own class, but they all share the commonality of being addressable to some destination. Each class could be designed with duplicate address fields, or you might abstract these details into a common superclass. Alternatively, you could leverage Listing 1’s Addressable interface. Listing 1. Addressable.java public interface Addressable { public class Address { private String boxNumber; private String street; private String city; public Address(String boxNumber, String street, String city) { this.boxNumber = boxNumber; this.street = street; this.city = city; } public String getBoxNumber() { return boxNumber; } public String getStreet() { return street; } public String getCity() { return city; } public String toString() { return boxNumber + " - " + street + " - " + city; } } public Address getAddress(); } The Addressable interface describes an addressable entity as containing an address. This address is described by the nested Address class. The getAddress() method is implemented by whatever class implements Addressable. Listing 2 presents the source code to a Letter class that implements Addressable. Listing 2. Letter.java public class Letter implements Addressable { private Addressable.Address address; public Letter(String boxNumber, String street, String city) { address = new Addressable.Address(boxNumber, street, city); } public Address getAddress() { return address; } } Letter stores a single address field of type Addressable.Address. This nested class is instantiated by Letter‘s constructor. The implemented getAddress() method returns this object. Now consider what happens when we add Postcard and Parcel classes to the Addressables application. Listing 3 presents the source code to an Addressables application, which demonstrates the Postcard, Parcel, and Letter types. Listing 3. Addressables.java public class Addressables { public static void main(String[] args) { Addressable[] addressables = { new Letter("100", "Main Street", "Town A"), new Postcard("200", "Waterfront Drive", "Town B"), new Parcel("300", "10th Ave", "Town C") }; for (int i = 0; i < addressables.length; i++) System.out.println(addressables[i].getAddress()); } } The main() method first creates an array of Addressable objects. It then iterates over these objects, invoking getAddress() on each object. The returned Addressable.Address object’s toString() method is invoked by System.out.println() to return a string representation of the object, and this representation is subsequently output. Compile Listings 2 and 3 along with Postcard.java and Parcel.java as follows: javac *.java Run the application as follows: java Addressables You should observe the following output: 100 - Main Street - Town A 200 - Waterfront Drive - Town B 300 - 10th Ave - Town C Nested interfaces with static methods (static method interfaces) Many developers believe that nesting a class in an interface violates object-oriented programming and the purpose for an interface. However, it’s good to know about this capability because you might encounter it when maintaining someone else’s code. Furthermore, now that interfaces have evolved to include default and static methods, you might encounter additional reasons to nest a class in an interface. As an example, here is a local class nested within a static method interface: interface I { static void m() { class C { } } } Conclusion I’ve presented three common ways to use nesting techniques with Java classes and interfaces, and also demonstrated a controversial technique of nesting interfaces with static methods. See the complete Java 101 tutorial to learn more about nesting with static classes and inner classes in Java. Related content news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages analysis And the #1 Python IDE is . . . PyCharm, VS Code, and five other popular Python IDEs duke it out. Which one do you think takes home the prize? By Serdar Yegulalp Nov 15, 2024 2 mins Python Programming Languages Software Development news JDK 24: The new features in Java 24 21 features are proposed for the next version of Java including quantum-resistant cryptographic keys designed to secure Java apps against future quantum computing attacks. By Paul Krill Nov 15, 2024 11 mins Java Programming Languages Software Development news Rust Foundation moves forward on C++ and Rust interoperability Problem statement released to address the challenges to making cross-language development with C++ and Rust more accessible and approachable. By Paul Krill Nov 14, 2024 2 mins C++ Rust Programming Languages Resources Videos