Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Interfaces

An interface describes what an object can do, but not how. It is a contract: a class that signs it must implement every method listed.

Declaring and implementing

An interface is declared with the word interface, and a class connects it with the word implements. Interface methods are public and abstract by default, so in the implementation they are marked public too:

interface Greeter {
    String greet(String name);
}
 
class FriendlyGreeter implements Greeter {
    @Override
    public String greet(String name) {
        return "Hello, " + name + "!";
    }
}
 
void main() {
    Greeter greeter = new FriendlyGreeter();
    IO.println(greeter.greet("Anna"));
}

Output:

Hello, Anna!

An interface as a type

A variable or parameter of an interface type accepts any object that implements it. The classes do not have to be related at all:

interface Priced {
    double price();
}
 
class Book implements Priced {
    @Override
    public double price() {
        return 15;
    }
}
 
class Delivery implements Priced {
    @Override
    public double price() {
        return 5;
    }
}
 
void main() {
    Priced[] cart = { new Book(), new Book(), new Delivery() };
    double total = 0;
    for (Priced item : cart) {
        total += item.price();
    }
    IO.println("Total: " + total + " €");
}

Output:

Total: 35.0 €

A book and a delivery have no common parent, but both know their price — and that is enough.

Several interfaces

A class has only one parent, but it can implement as many interfaces as it likes. They are listed with commas:

interface Swimmer {
    String swim();
}
 
interface Flyer {
    String fly();
}
 
class Duck implements Swimmer, Flyer {
    @Override
    public String swim() {
        return "The duck swims";
    }
 
    @Override
    public String fly() {
        return "The duck flies";
    }
}
 
void main() {
    Duck duck = new Duck();
    IO.println(duck.swim());
    IO.println(duck.fly());
}

Output:

The duck swims
The duck flies

Default methods

A method marked default has a body right in the interface. Classes get it ready-made and may override it if they want. An interface can also have static methods:

interface Greeter {
    String name();
 
    default String greet() {
        return "Hello, " + name() + "!";
    }
 
    static Greeter of(String name) {
        return () -> name;
    }
}
 
class Robot implements Greeter {
    @Override
    public String name() {
        return "R2";
    }
}
 
void main() {
    IO.println(new Robot().greet());
    IO.println(Greeter.of("Oleg").greet());
}

Output:

Hello, R2!
Hello, Oleg!

The notation () -> name is a lambda, a short way to implement an interface with a single abstract method. Lambdas are covered in detail in the chapter on generics and lambdas.

Interface or abstract class

An interface describes an ability ("can swim", "has a price") and does not store the object's state: it has no fields, only constants. An abstract class fits when subclasses share fields and code. If in doubt, start with an interface — a class can implement many interfaces but inherit only one class.

Common mistake

Interface methods are public. If you forget this word in the class, the method becomes less accessible than in the interface, and the compiler refuses:

interface Greeter {
    String greet(String name);
}
 
class FriendlyGreeter implements Greeter {
    String greet(String name) {
        return "Hello, " + name;
    }
}
 
void main() {
}

Output:

Main.java:6: error: greet(String) in Main.FriendlyGreeter cannot implement greet(String) in Greeter
    String greet(String name) {
           ^
  attempting to assign weaker access privileges; was public

Add public in front of the method in the class.

Thanks for reading!

Donate to the site — we work hard for you.