Chapter 3. Java Interfaces

3.1.  Create and use methods in interfaces

Java 9 introduced private methods and private static method in interfaces. In Java 9 (and hence Java 11 too) an interface can have seven different things:

  1. constant variables (since Java 1.0)

  2. abstract methods (since Java 1.0)

  3. nested types (since Java 2.0)

  4. default methods (since Java 8.0)

  5. static methods (since Java 8.0)

  6. private methods (since Java 9.0)

  7. private static methods (since Java 9.0)

The private methods added in Java 9.0 will improve code re-usability inside interfaces and will provide choice to expose only intended method implementations to users. The private methods are only accessible within an interface only and cannot be accessed or inherited from the interface to another interface or class.

Constant variables

public interface GreeterIntf {
    String GREETING = "Greeting from Interface";
}
					

public class Client {
    public static void main(String[] args) {
        System.out.print(GreeterIntf.GREETING);
    }
}
					

[Important]

Every field declaration in the body of an interface is implicitly public, static, and final. It is permitted to redundantly specify any or all of these modifiers for such fields.

Interface variables are static because Java interfaces cannot be instantiated in their own right; the value of the variable must be assigned in a static context in which no instance exists. The final modifier ensures the value assigned to the interface variable is a true constant that cannot be re-assigned by program code.

abstract methods

public interface GreeterIntf {
    void greet();
}

					

public class Client {
    public static void main(String[] args) {
        GreeterIntf g = () -> {
            System.out.print("Greeting from Interface");
        };
        g.greet();
    }
}					
					

[Important]

Every method declaration in an interface with body represented by a semicolon is implicitly public and abstract.

[Important]

It is a compile-time error if a method declaration that contains the keyword abstract also contains any one of the keywords: private, static, final, native, strictfp, or synchronized.

It would be impossible for a class to implement a private abstract method, because private methods are not inherited by subclasses; therefore such a method could never be used.

nested types

public interface GreeterIntf {
    class GreeterException extends RuntimeException {
        public GreeterException() { super(); };
    }    
    interface Helper {
        String GREETING = "Greeting from Interface";
    }
}
					

public class Client {
    public static void main(String[] args) {
        try {
            System.out.print(GreeterIntf.Helper.GREETING);
        } catch (GreeterIntf.GreeterException e) {
            // never ignore exception handling !
        }
    }
}
					

[Important]

Interfaces may contain member type declarations. A member type declaration in an interface is implicitly static and public. It is permitted to redundantly specify either or both of these modifiers.

default methods

Before Java 8.0, interfaces could have only abstract methods. The implementation of these methods has to be provided in a separate class. So, if a new method is to be added in an interface, then its implementation code has to be provided in all classes implementing this interface. To overcome this issue, Java 8.0 has introduced the concept of default methods which allow the interfaces to have methods with implementation without affecting the classes that implement the interface.

Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary backward compatibility with code written for older versions of those interfaces.

Unlike abstract interface methods, they are declared with the default keyword at the beginning of the method signature, and they provide an implementation.

An implementing class can override the default implementation provided by the interface.

public interface GreeterIntf {
    default void greet() {
        System.out.print("Greeting from Interface");    
    }
}
					

public class Client {
    public static void main(String[] args) {
      GreeterIntf g = new GreeterIntf() { // we do not override default method
      };
      g.greet();
    }
}
					

[Important]

The default methods are implicitly public — there's no need to specify the public modifier.

If a class implements two interfaces, both of which have a default method with the same name and parameter types, then you must resolve the conflict.

public interface GreeterIntfA {
    default void greet() {
        System.out.println("Greeting from GreeterIntfA");
    }
}
					

public interface GreeterIntfB {
    default void greet() {
        System.out.println("Greeting from GreeterIntfB");
    }
}
					

public class MyGreeter implements GreeterIntfA, GreeterIntfB {
	// WILL NOT COMPILE !!!    
}

					

The MyGreeter class inherits two greet() methods provided by the GreeterIntfA and GreeterIntfB interfaces. There is no way for the Java compiler to choose one over the other. The compiler reports an error. You should provide a greet() method in the MyGreeter class and either implement your own greeting, or delegate to one of the conflicting methods, like this:

public class MyGreeter implements GreeterIntfA, GreeterIntfB {
    @Override
    public void greet() {
        GreeterIntfA.super.greet();
    }
}
					

The super keyword lets you call a supertype method. In this case, we need to specify which supertype we want.

If a class extends a superclass and implements an interface with default method, inheriting the same method from both, then only the superclass method matters, and default method from the interface is ignored.

static methods

In Java 8.0 and later you can define static methods in interfaces. Like static methods in classes, you specify that a method definition in an interface is a static method with the static keyword at the beginning of the method signature.

A static method can be invoked from other static or from default method.

public interface GreeterIntf {
    static void greet() {
        System.out.print("Greeting from Interface");    
    }
}
					

public class Client {
    public static void main(String[] args) {
      GreeterIntf.greet();
    }
}
					

A static method cannot be overridden or changed in the implementation class. It can be shadowed.

[Important]

The static methods are implicitly public — there's no need to specify the public modifier.

private methods

As of Java 9.0, methods in an interface can be private.

These private methods will improve code reusability inside interfaces and encapsulation. For example, if two default methods needed to share code, a private method in the interface would allow them to do so, but without exposing that private method to interface implementing class.

public interface GreeterIntf {
    default void greet() {
        System.out.print(getGreeting());    
    }
    
    private String getGreeting() {
        return "Greeting from Interface";
    }
}
					

public class Client {
    public static void main(String[] args) {
      GreeterIntf g = new GreeterIntf() {        
      };
      g.greet();
    }
}
					

Rules for private methods in interfaces:

  1. We must use private modifier to define them.

  2. No private and abstract modifiers together, it will give compiler error. The private method means fully implemented method because subclasses cannot inherit and override this method. The abstract method means no-implementation method -- subclass must inherit and override this method.

  3. No private and default modifiers together, it will give compiler error. The default methods in an interface are always public.

  4. The private methods must contain body.

As private methods can only be used in the methods of the interface itself, their use is limited to being helper methods for the other methods of the interface.

private static methods

public interface GreeterIntf {
    static void greet() {
        System.out.print(GreeterIntf.getGreeting());    
    }
    
    private static String getGreeting() {
        return "Greeting from Interface";
    }
}					

public class Client {
    public static void main(String[] args) {
      GreeterIntf.greet();
    }
}					

The private static methods are useful when you have multiple public static methods that share some common code. So, you can only extract that shared code into a private static method, but not into an instance method (because static method cannot access instance method without creating an instance of type).

A private static methods can be called from instance (i.e. default or private non-static) method or static method inside the interface.

A private non-static method is not allowed to be called from static or private static method within the interface (unless an instance of the interface is passed in).

Professional hosting         Exam 1Z0-817: Upgrade OCP Java 6, 7 & 8 to Java SE 11 Developer Quiz     Exam 1Z0-810: Upgrade to Java SE 8 Programmer Quiz