Computer Language
Lecture 13

Interfaces

Josue Obregon

Seoul National University of Science and Technology
Information Technology Management
Lecture slides index

June 2, 2025

Class contents

  1. Introduction to Computer Programming and Java
  2. Reading Input and Strings
  3. Variables and calculation with numbers
  4. Conditional statements
  5. Repeating functionality
  6. Methods
  7. Lists
  8. Midterm
  1. Arrays and Strings
  2. Introduction to Object Oriented Programming
  3. More of Object Oriented Programming
  4. Inheritance
  5. Interfaces
  6. Project Live Code Review and Evaluation
  7. Final examination

Agenda

  • Interface Basics
  • Implementing Interfaces
  • Interface as Type
  • Interface Parameters
  • Interface Return Values
  • Built-in Interfaces

Learning Objectives

  • You’re familiar with the concept of an interface, can define your own interfaces, and implement an interface in a class.
  • You know how to use interfaces as variable types, method parameters and method return values.
  • You’re aware of some of the interfaces that come with Java.

What is an interface

  • We can use interfaces to define behavior that’s required from a class, i.e., its methods.
  • They’re defined the same way that regular Java classes are, but the syntax “public interface ...” is used instead of “public class ...” at the beginning of the file.
  • Interfaces define behavior through method names and their return values.
  • However, they don’t always include the actual implementations of the methods.
  • A visibility attribute on interfaces is not marked explicitly as they’re always public.
  • Let’s examine a Readable interface that describes readability.
public interface Readable {
    String read();
}
  • The Readable interface declares a read() method, which returns a String-type object.
  • Readable defines certain behavior: for example, a text message or an email may be readable.

Defining interfaces

  • The classes that implement the interface decide how the methods defined in the interface are implemented.
  • A class implements the interface by adding the keyword implements after the class name followed by the name of the interface being implemented.
  • Let’s create a class called TextMessage that implements the Readable interface.
public class TextMessage implements Readable {
    private String sender;
    private String content;

    public TextMessage(String sender, String content) {
        this.sender = sender;
        this.content = content;
    }

    public String getSender() {
        return this.sender;
    }

    public String read() {
        return this.content;
    }
}
  • Since the TextMessage class implements the Readable interface (public class TextMessage implements Readable), the TextMessage class must contain an implementation of the public String read() method.
  • Implementations of methods defined in the interface must always have public as their visibility attribute.

An Interfaces is a contract of behaviour

  • When a class implements an interface, it signs an agreement.
  • The agreement dictates that the class will implement the methods defined by the interface.
  • If those methods are not implemented in the class, the program will not function.
  • The interface defines only the names, parameters, and return values ​​of the required methods.
  • The interface, however, does not have a say on the internal implementation of its methods.
  • It is the responsibility of the programmer to define the internal functionality for the methods.

More Reader implementations

  • In addition to the TextMessage class, let’s add another class that implements the Readable interface.
  • The Ebook class is an electronic implementation of a book that containing the title and pages of a book.
  • The ebook is read page by page, and calling the public String read() method always returns the next page as a string.
public class Ebook implements Readable {
    private String name;
    private ArrayList<String> pages;
    private int pageNumber;

    public Ebook(String name, ArrayList<String> pages) {
        this.name = name;
        this.pages = pages;
        this.pageNumber = 0;
    }

    public String getName() {
        return this.name;
    }

    public int pages() {
        return this.pages.size();
    }

    public String read() {
        String page = this.pages.get(this.pageNumber);
        nextPage();
        return page;
    }

    private void nextPage() {
        this.pageNumber = this.pageNumber + 1;
        if(this.pageNumber % this.pages.size() == 0) {
            this.pageNumber = 0;
        }
    }
}

Object instantiation

  • Objects can be instantiated from interface-implementing classes just like with normal classes.
  • They’re also used in the same way, for instance, as an ArrayList’s type.
TextMessage message = new TextMessage("mina", "It's going great!");
System.out.println(message.read());

ArrayList<TextMessage> textMessage = new ArrayList<>();
textMessage.add(new TextMessage("private number", "I hid the body.");

Sample Output

It's going great!

Ebook object

ArrayList<String> pages = new ArrayList<>();
pages.add("Split your method into short, readable entities.");
pages.add("Separate the user-interface logic from the application logic.");
pages.add("Always program a small part initially that solves a part of the problem.");
pages.add("Practice makes the master. Try different out things for yourself and work on your own projects.");

Ebook book = new Ebook("Tips for programming.", pages);

int page = 0;
while (page < book.pages()) {
    System.out.println(book.read());
    page = page + 1;
}

Sample Output

Split your method into short, readable entities.
Separate the user-interface logic from the application logic.
Always program a small part initially that solves a part of the problem.
Practice makes the master. Try different out things for yourself and work on your own projects.

Exercise 1 - TacoBoxes

  • In the exercise template you’ll find Interface TacoBox ready for your use.
  • Adding a new Interface is quite similar to adding a new class.
  • Instead of selecting new Java class just select new Java interface.
  • It has the following methods:
    • the method int tacosRemaining() return the number of tacos remaining in the box.
    • the method void eat() reduces the number of tacos remaining by one. The number of tacos remaining can’t become negative.
public interface TacoBox {
    int tacosRemaining();
    void eat();
}
  • Implement the class TripleTacoBox, that implements the TacoBox interface.
    • TripleTacobox has a constructor with no parameters.
    • TripleTacobox has an object variable tacos which is initialized at 3 when the constructor is called.
  • Implement the class CustomTacoBox, that implements the TacoBox interface.
    • CustomTacoBox has a constructor with one parameter defining the initial number of tacos in the box(int tacos).

Interface as Variable Type

  • The type of a variable is always stated when declaring it.
  • There are two kinds of type, the primitive-type variables (int, double, …) and reference-type variables (all objects).
  • We’ve so far used an object’s class as the type of a reference-type variable.
String string = "string-object";
TextMessage message = new TextMessage("mina", "many types for the same object");
  • An object’s type can be other than its class.
  • For example, the type of the Ebook class that implements the Readable interface is both Ebook and Readable.
  • Similarly, the text message also has multiple types.
  • Because the TextMessage class implements the Readable interface, it has a Readable type in addition to the TextMessage type.
TextMessage message = new TextMessage("mina", "Something cool's about to happen");
Readable readable = new TextMessage("mina", "The text message is Readable!");

Ebook object is a Readable too

  • The type of the Ebook class that implements the Readable interface is both Ebook and Readable.
ArrayList<String> pages = new ArrayList<>();
pages.add("A method can call itself.");

Readable book = new Ebook("Introduction to Recursion", pages);

int page = 0;
while (page < book.pages()) {
    System.out.println(book.read());
    page = page + 1;
}

List of interfaces

  • Because an interface can be used as a type, it’s possible to create a list that contains objects of the interface’s type.
ArrayList<Readable> readingList = new ArrayList<>();

readingList.add(new TextMessage("mina", "never been programming before..."));
readingList.add(new TextMessage("mina", "gonna love it i think!"));
readingList.add(new TextMessage("mina", "give me something more challenging! :)"));
readingList.add(new TextMessage("mina", "you think i can do it?"));
readingList.add(new TextMessage("mina", "up here we send several messages each day"));


ArrayList<String> pages = new ArrayList<>();
pages.add("A method can call itself.");

readingList.add(new Ebook("Introduction to Recursion.", pages));

for (Readable readable: readingList) {
    System.out.println(readable.read());
}
  • Note that although the Ebook class that inherits the Readable interface class is always of the interface’s type, not all classes that implement the Readable interface are of type Ebook.

Type conversion with interfaces

  • You can assign an object created from the Ebook class to a Readable-type variable, but it does not work the other way without a separate type conversion.
Readable readable = new TextMessage("mina", "TextMessage is Readable!"); // works
TextMessage message = readable; // doesn't work

// works if, and only if, readable is of text message type
TextMessage castMessage = (TextMessage) readable; 
  • Type conversion succeeds if, and only if, the variable is of the type that it’s being converted to.
  • Type conversion is not considered good practice, and one of the few situation where it’s use is appropriate is in the implementation of the equals method.

Interfaces as Method Parameters

  • The true benefits of interfaces are obtained when they are used as the type of parameter provided to a method.
  • Since an interface can be used as a variable’s type, it can also be used as a parameter type in method calls.
  • For example, the print method in the Printer class of the class below gets a variable of type read.
public class Printer {
    public void print(Readable readable) {
        System.out.println(readable.read());
    }
}
  • The value of the print method of the printer class lies in the fact that it can be given any class that implements the Readable interface as a parameter.
  • Were we to call the method with any object instantiated from a class that inherits the Readable class, the method would function as desired.

Abstracting a reading list in a class

  • Let’s make another class called ReadingList to which we can add interesting things to read.
  • The class has an ArrayList instance as an instance variable, where the things to be read are added.
  • Adding to the reading list is done using the add method, which receives a Readable-type object as its parameter.
public class ReadingList {
    private ArrayList<Readable> readables;

    public ReadingList() {
        this.readables = new ArrayList<>();
    }

    public void add(Readable readable) {
        this.readables.add(readable);
    }

    public int toRead() {
        return this.readables.size();
    }
}

ReadingList also implements Readable

  • Reading lists are usually readable, so let’s have the ReadingList class implement the Readable interface.
  • The read method of the reading list reads all the objects in the readables list, and adds them to the string returned by the read() method one-by-one.
public class ReadingList implements Readable {
    private ArrayList<Readable> readables;

    public ReadingList() {
        this.readables = new ArrayList<>();
    }

    public void add(Readable readable) {
        this.readables.add(readable);
    }

    public int toRead() {
        return this.readables.size();
    }

    public String read() {
        String read = "";

        for (Readable readable: this.readables) {
            read = read + readable.read() + "\n";
        }

        // once the reading list has been read, we empty it
        this.readables.clear();
        return read;
    }
}

Using the ReadingList class

ReadingList mikesList = new ReadingList();
mikesList.add(new TextMessage("arthur", "have you written the tests yet?"));
mikesList.add(new TextMessage("arthur", "have you checked the submissions yet?"));

System.out.println("Mike's to-read: " + mikesList.toRead());
  • Sample Output
Mike's to-read: 2
  • Because the ReadingList is of type Readable, we’re able to add ReadingList objects to the reading list.

Adding a ReadingList to the ReadingList class

  • In the example below, Mike has a lot to read.
  • Fortunately for him, Berny comes to the rescue and reads the messages on Mike’s behalf.
ReadingList mikesList = new ReadingList();
int i = 0;
while (i < 1000) {
    mikesList.add(new TextMessage("arthur", "have you written the tests yet?"));
    i = i + 1;
}

System.out.println("Mike's to-read: " + mikesList.toRead());
System.out.println("Delegating the reading to Berny");

ReadingList bernysList = new ReadingList();
bernysList.add(mikesList);
bernysList.read();

System.out.println();
System.out.println("Mike's to-read: " + mikesList.toRead());
  • Sample Output
Mike's to-read: 1000
Delegating the reading to Berny

Mike's to-read:0

Code explanation

  • The read method called on Berny’s list goes through all the Readable objects and calls the read method on them.

  • When the read method is called on Berny’s list it also goes through Mike’s reading list that’s included in Berny’s reading list.

  • Mike’s reading list is run through by calling its read method.

  • At the end of each read method call, the read list is cleared.

  • In this way, Mike’s reading list empties when Berny reads it.

  • As you notice, the program already contains a lot of references.

  • It’s a good idea to draw out the state of the program step-by-step on paper and outline how the read method call of the bernysList object proceeds!

Class diagram

  • In class diagrams, interfaces are written <<interface>> NameOfTheInterface.
    • Methods are described just like they are for a class.
  • Implementing an interface is shown as a dashed arrow with a triangle arrowhead.
  • Below we describe an interface Readable and its implementations

Exercise 2 - Interface In A Box

  • Moving houses requires packing all your belongings into boxes.
  • Let’s imitate that with a program.
  • The program will have boxes, and items to pack into those boxes.
  • All items must implement the following Interface:
public interface Packable {
    double weight();
}
  • Add the Interface Packable to your program.
  • Create classes Book and CD, which implement the Interface.
    • Book has a constructor which is given the author (String), name of the book (String), and the weight of the book (double) as parameters.
    • CD has a constructor which is given the artist (String), name of the CD (String), and the publication year (int).
  • The weight of all CDs is 0.1 kg.
  • Remember to implement the Interface Packable in both of the classes.
  • The classes must work as in the following tab
public static void main(String[] args) {
    Book book1 = new Book("Fyodor Dostoevsky", "Crime and Punishment", 2);
    Book book2 = new Book("Robert Martin", "Clean Code", 1);
    Book book3 = new Book("Kent Beck", "Test Driven Development", 0.5);

    CD cd1 = new CD("Pink Floyd", "Dark Side of the Moon", 1973);
    CD cd2 = new CD("IU", "The Winning", 2024);
    CD cd3 = new CD("Daft Punk", "Random Access Memories", 2013);

    System.out.println(book1);
    System.out.println(book2);
    System.out.println(book3);
    System.out.println(cd1);
    System.out.println(cd2);
    System.out.println(cd3);
}

Output

Fyodor Dostoevsky: Crime and Punishment
Robert Martin: Clean Code
Kent Beck: Test Driven Development
Pink Floyd: Dark Side of the Moon (1973)
IU: The Winning (2024)
Daft Punk: Random Access Memories (2013)
  • Note: The weight is not printed
  • Make a class called Box. Items implementing the Packable interface can be packed into a box.
  • The Box constructor takes the maximum capacity of the box in kilograms as a parameter.
  • The combined weight of all items in a box cannot be more than the maximum capacity of the box.
  • Below is an example of using a box:
public static void main(String[] args) {
    Box box = new Box(10);

    box.add(new Book("Fyodor Dostoevsky", "Crime and Punishment", 2)) ;
    box.add(new Book("Robert Martin", "Clean Code", 1));
    box.add(new Book("Kent Beck", "Test Driven Development", 0.7));

    box.add(new CD("Pink Floyd", "Dark Side of the Moon", 1973));
    box.add(new CD("IU", "The Winning", 2024));
    box.add(new CD("Daft Punk", "Random Access Memories", 2013));

    System.out.println(box);
}

Sample Output

Box: 6 items, total weight 4.0 kg
  • Note: As the weights are saved as a double, the calculations might have some small rounding errors. You don’t need to worry about them.
  • If you made a class variable double weight in the Box class, replace it with a method which calculates the weight of the box:
public class Box {
    //...

    public double weight() {
        double weight = 0;
        // calculate the total weight of the items in the box
        return weight;
    }
}
  • When you need the weight of the box, for example when adding a new item to the box, you can just call the weight method.
  • The method could also return the value of an object variable.
  • However here we are practicing a situation, where we do not have to maintain an object variable explicitly, but can calculate its value as needed.
  • After the next exercise storing the weight as an object variable would not necessary work anyway.
  • After completing the exercise have a moment to think why that is.
  • Implementing the Packable Interface requires a class to have the method double weight().
  • We just added this method to the Box class.
  • This means we can make the Box packable as well!
  • Boxes are objects, which can contain objects implementing the packable Interface.
  • Boxes implement this Interface as well.
  • So a box can contain other boxes!
  • Try this out.
  • Make some boxes containing some items, and add some smaller boxes to a bigger box.
  • Try what happens, when you put a box in itself.
  • Why does this happen?

Interface as a return type of a method

  • Interfaces can be used as return types in methods – just like regular variable types.
  • In the next example we have a class Factory that can be asked to construct different objects that implement the Packable interface.
import java.util.Random;

public class Factory {

    public Factory() {
        // Note that there is no need to write an empy constructor without
        // parameters if the class doesn't have other constructors.
        // In these cases Java automatically creates a default constructor for
        // the class which is an empty constructor without parameters.
    }

    public Packable produceNew() {
        // The Random-object used here can be used to draw random numbers.
        Random ticket = new Random();
        // Draws a number from the range [0, 4). The number will be 0, 1, 2, or 3.
        int number = ticket.nextInt(4);

        if (number == 0) {
            return new CD("Pink Floyd", "Dark Side of the Moon", 1973);
        } else if (number == 1) {
            return new CD("IU", "The Winning", 2024);
        } else if (number == 2) {
            return new Book("Robert Martin", "Clean Code", 1);
        } else {
            return new Book("Kent Beck", "Test Driven Development", 0.7);
        }
    }
}

Creating packable objects

  • The Factory can be used without exactly knowing what different kind of Packable classes exist.
  • In the next example there is a class Packer that gives a box of things.
  • A packer defines a factory which is used to create the things:
public class Packer {
    private Factory factory;

    public Packer() {
        this.factory = new Factory();
    }

    public Box giveABoxOfThings() {
         Box box = new Box(100);

         int i = 0;
         while (i < 10) {
             Packable newThing = factory.produceNew();
             box.add(newThing);

             i = i + 1;
         }

         return box;
    }
}
  • Because the packer does not know the classes that implement the interface Packable, one can add new classes that implement the interface without changing the packer.

Packing chocolate bars

  • The next example creates a new class that implements the Packable interface ChocolateBar.
  • The factory has been changed so that it creates chocolate bars in addition to books and CDs.
  • The class Packer works without changes with the updated version of the factory.
public class ChocolateBar implements Packable {
    // Because Java's automatically generated default constructor is enough,
    // we don't need a constructor

    public double weight() {
        return 0.2;
    }
}

Factory class modified

import java.util.Random;

public class Factory {
    // Because Java's automatically generated default constructor is enough,
    // we don't need a constructor

    public Packable produceNew() {

        Random ticket = new Random();
        int number = ticket.nextInt(5);

        if (number == 0) {
            return new CD("Pink Floyd", "Dark Side of the Moon", 1973);
        } else if (number == 1) {
            return new CD("Daft Punk", "Random Access Memories", 2013);
        } else if (number == 2) {
            return new Book("Robert Martin", "Clean Code", 1 );
        } else if (number == 3) {
            return new Book("Kent Beck", "Test Driven Development", 0.7);
        } else {
            return new ChocolateBar();
        }
    }
}

Reducing dependencies between classes

  • Using interfaces in programming enables reducing dependencies between classes.
  • In the previous example the Packer does not depend on the classes that implement the Packable interface.
  • Instead, it just depends on the interface.
  • This makes possible to add new classes that implement the interface without changing the Packer class.
  • What is more, adding new Packable classes doesn’t affect the classes that use the Packer class.

Built-in Interfaces

  • Java offers a considerable amount of built-in interfaces.
  • Here we’ll briefly mention three commonly used interfaces:

The Collection Interface

  • The Collection interface describes functionality related to collections.
  • Among other things, lists and sets are categorized as collections in Java – both the List and Set interfaces implement the Collection interface.
  • The Collection interface provides, for instance, methods for checking the existence of an item (the method contains) and determining the size of a collection (the method size).
  • The Collection interface also determines how the collection is iterated over.
  • Any class that implements the Collection interface, either directly or indirectly, inherits the functionality required for a for-each loop.

The List Interface

  • The List interface defines the basic functionality related to lists.
  • Because the ArrayList class implements the List interface, one can also use it through the List interface.
List<String> strings = new ArrayList<>();
strings.add("string objects inside an arraylist object!");
  • As we can see fom the Java API of List, there are many classes that implement the List interface.
  • One list that is familiar to computer scientists is a linked list.
  • A linked list can be used through the List interface exactly the same way as an object created from ArrayList.
List<String> strings = new LinkedList<>();
strings.add("string objects inside a linkedlist object!");

ArrayLists and LinkedLists

  • From the perspective of the user, both implementations of the List interface work the same way.
  • The interface abstracts their inner functionality.
  • The internal structures of ArrayList and LinkedList differ quite a bit.
    • ArrayList saves objects to an array where fetching an object with a specific index is very fast.
    • On the other hand LinkedList constructs a list where each element contains a reference to the next element in the list.

The Set Interface

  • The Set interface describes functionality related to sets.
  • In Java, sets always contain either 0 or 1 amounts of any given object.
  • As an example, the set interface is implemented by HashSet.
  • Here’s how to go through the elements of a set.
Set<String> set = new HashSet<>();
set.add("one");
set.add("one");
set.add("two");

for (String element: set) {
    System.out.println(element);
}
  • Sample Output
one
two
  • Note that HashSet in no way assumes the order of a set of elements.
  • If objects created from custom classes are added to the HashSet object, they must have both the equals and hashCode methods defined.

Checking our learning objectives

  • You’re familiar with the concept of an interface, can define your own interfaces, and implement an interface in a class.
  • You know how to use interfaces as variable types, method parameters and method return values.
  • You’re aware of some of the interfaces that come with Java.

Computer Language (ComLang) course wrap-up (I)

  • Computer programming as a tool
  • Variables and Primitive types (int, double, boolean)
  • Reference types (String, arrays, objects, ArrayList)
  • Input and Output (Print and Scanner)
  • Basic Operators (arithmetic, assignment, compound assignment, increment and decrement)
  • Control Statements (selection and iteration)
  • Counter-controlled and sentinel-controlled iteration
  • Methods
  • ArrayList, arrays and Strings

Computer Language (ComLang) course wrap-up (II)

  • Object Oriented Programming
  • Classes and Objects
  • Instantiation and Constructors
  • Object Methods and object variables
  • Encapsulation and Information Hiding
  • Inheritance
  • Polymorphism
  • Interfaces

Do you want to learn more?

  • We covered almost every part of Java Programming I of The Java Programming MOOC from the University of Helsinki,
  • We covered some parts of Java Programming II, specifically those related to object-oriented programming
  • Do you want more?
    • Hash Maps (Part 8-1)
    • Graphical user interfaces (Part 13)
    • Data visualization (Part 14-1)
    • Maven (Part14-4 or…. OSS)

Final words

  • Programming is hard, but it is one of the greatest tool for ITM students
  • Practice, practice and then practice again
public class Life {
    public static void main(String[] args) {
        
        // Variable to control if we are learning
        boolean learning = true;        
        
        // While loop to represent the continuous learning process
        while (learning) {
            System.out.println("Experimenting with new concepts and ideas...");
            System.out.println("Making mistakes and learning from them...");
            System.out.println("Learning from experiences...");            
        }
    }
}

Acknowledgements


Back to title slide Back to lecture slides index