What are Static Methods on interface in Java?

In Java SE 8 and later, you can define static methods on interfaces. A static method is a method associated with the class, not the instance. This means you can call a static method without creating an instance of the class.

This feature can be particularly useful when providing utility methods that act on instances of the interface. You would normally keep these in a separate utility class, but by having these on the interface itself can lead to more readable and maintainable code.

Here is a simple example:

interface MyInterface {
    static void myStaticMethod() {
        System.out.println("Static Method on Interface");
    }
}

public class Main {
    public static void main(String[] args) {
        MyInterface.myStaticMethod(); // Call without creating instance
    }
}

In this example, myStaticMethod() is a static method defined on MyInterface. You call it using the interface name (MyInterface.myStaticMethod()), without needing to create an instance of MyInterface.

Keep in mind that static methods in interfaces are not inherited by classes that implement the interface or sub-interfaces, so you always have to use the interface name when calling them.

The Stream interface in Java has several static methods that provide useful functionality for working with sequences of elements, such as collections. Here is an example that uses the Stream.of() static method, which allows you to create a Stream from a set of objects:

import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        Stream.of("Hello", "World", "Interface", "Static", "Methods")
              .map(String::toUpperCase)
              .forEach(System.out::println);
    }
}

In this example, we use Stream.of() to create a Stream from a set of String objects. We then use map() to convert each string in the stream to uppercase, and forEach() to print out each string.

Here is another example, this time using the IntStream.range() static method:

import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        IntStream.range(1, 6)
                 .forEach(System.out::println);
    }
}

In this example, IntStream.range(1, 6) creates a stream of integers from 1 (inclusive) to 6 (exclusive). The forEach() method is then used to print out each integer in the stream.

What is Default Methods in Java?

Default methods are a feature introduced in Java 8, allowing the declaration of methods in interfaces, apart from abstract methods. They are also known as defender methods or virtual extension methods.

With the use of default keyword, these methods are defined within the interface and provide a default implementation. This means they can be directly used by any class implementing this interface without needing to provide an implementation for these methods.

The main advantage of default methods is that they allow the interfaces to be evolved over time without breaking the existing code.

Here’s an example of a default method in an interface:

interface MyInterface {
    void abstractMethod();

    default void defaultMethod() {
        System.out.println("This is a default method in the interface");
    }
}

In the above example, any class implementing MyInterface needs to provide an implementation for abstractMethod(), but not for defaultMethod() unless it needs to override the default implementation.

Before Java 8, we could declare only abstract methods in interfaces. It means that classes which implement the interface were obliged to provide an implementation of all methods declared in an interface. However, this was not flexible for developers, especially when they wanted to add new methods to the interfaces.

For instance, here is an interface used by multiple classes:

interface Animal {
    void eat();
}

Now, if we wanted to add a new method called run(), all classes that implement Animal would need to define this method, which could potentially introduce bugs and is quite cumbersome if we have many classes that implement the interface.

To mitigate such issues, Java 8 introduced default methods in interfaces. With default methods, we can now add new methods in the interface with a default implementation, thereby having the least impact on the classes that implement the interface.

interface Animal {
    void eat();

    default void run() {
        System.out.println("Running");
    }
}

So in the updated Animal interface, the run() method is a default method. Classes implementing Animal can choose to override this method, but they are not obliged to do so. If a class does not provide an implementation for this method, the default implementation from the interface will be used.

Here’s an example implementation of the Animal interface:

class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("Dog is eating");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // Output: Dog is eating
        dog.run();  // Output: Running
    }
}

As you can see, the Dog class didn’t implement the run method, but we’re still able to call dog.run() because of the default implementation in the Animal interface.

Note: In case a class implements multiple interfaces and these interfaces have default methods with identical signatures, the compiler will throw an error. The class must override the method to resolve the conflict.

How do I get direct superclass and interfaces of a class?

Java reflection also dealing with inheritance concepts. You can get the direct interfaces and direct super class of a class by using method getInterfaces() and getSuperclass() of java.lang.Class object.

  • getInterfaces() will returns an array of Class objects that represent the direct super interfaces of the target Class object.
  • getSuperclass() will returns the Class object representing the direct super class of the target Class object or null if the target represents Object class, an interface, a primitive type, or void.
package org.kodejava.lang.reflect;

import javax.swing.*;
import java.util.Date;

public class GetSuperClassDemo {
    public static void main(String[] args) {
        GetSuperClassDemo.get(String.class);
        GetSuperClassDemo.get(Date.class);
        GetSuperClassDemo.get(JButton.class);
        GetSuperClassDemo.get(Timer.class);
    }

    public static void get(Class<?> clazz) {
        // Gets array of direct interface of clazz object
        Class<?>[] interfaces = clazz.getInterfaces();

        System.out.format("Direct Interfaces of %s:%n",
                clazz.getName());
        for (Class<?> clz : interfaces) {
            System.out.println(clz.getName());
        }

        // Gets direct superclass of clazz object
        Class<?> superclz = clazz.getSuperclass();
        System.out.format("Direct Superclass of %s: is %s %n",
                clazz.getName(), superclz.getName());
        System.out.println("====================================");
    }
}

Here is the result of the code snippet:

Direct Interfaces of java.lang.String:
java.io.Serializable
java.lang.Comparable
java.lang.CharSequence
Direct Superclass of java.lang.String: is java.lang.Object 
====================================
Direct Interfaces of java.util.Date:
java.io.Serializable
java.lang.Cloneable
java.lang.Comparable
Direct Superclass of java.util.Date: is java.lang.Object 
====================================
Direct Interfaces of javax.swing.JButton:
javax.accessibility.Accessible
Direct Superclass of javax.swing.JButton: is javax.swing.AbstractButton 
====================================
Direct Interfaces of javax.swing.Timer:
java.io.Serializable
Direct Superclass of javax.swing.Timer: is java.lang.Object 
====================================

How do I check if a class represent an interface type?

You can use the isInterface() method call of the java.lang.Class to identify if a class objects represent an interface type.

package org.kodejava.lang.reflect;

import java.io.Serializable;

public class IsInterfaceDemo {
    public static void main(String[] args) {
        IsInterfaceDemo.get(Serializable.class);
        IsInterfaceDemo.get(Long.class);
    }

    private static void get(Class<?> clazz) {
        if (clazz.isInterface()) {
            System.out.println(clazz.getName() +
                    " is an interface type.");
        } else {
            System.out.println(clazz.getName() +
                    " is not an interface type.");
        }
    }
}

Here is the result of the program:

java.io.Serializable is an interface type.
java.lang.Long is not an interface type.

How do I create an interface in Java?

Interface only contains methods declaration and all its methods are abstract methods. In its most common form, an interface is a group of related methods with empty bodies. To create an interface, use interface keyword in class definition. The file name of interface always the same with the interface name in class definition and the extension is .java.

The RemoteControl interface defines four move methods and a getPosition() methods. These methods have no bodies. If a class implements an interface, the class should implement all the contracts / methods defined by the interface.

package org.kodejava.basic;

public interface RemoteController {
    void moveUp(int n);

    void moveRight(int n);

    void moveDown(int n);

    void moveLeft(int n);

    int[] getPosition();
}

The following snippet show you how to create a class that implements the RemoteController interface.

package org.kodejava.basic;

public class DummyRemoteControl implements RemoteController {
    private int x;
    private int y;

    public DummyRemoteControl(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public static void main(String[] args) {
        RemoteController control = new DummyRemoteControl(0, 0);
        control.moveDown(10);
        control.moveLeft(5);
        System.out.println("X = " + control.getPosition()[0]);
        System.out.println("Y = " + control.getPosition()[1]);
    }

    public void moveUp(int n) {
        x = x + n;
    }

    public void moveRight(int n) {
        y = y + n;
    }

    public void moveDown(int n) {
        x = x - n;
    }

    public void moveLeft(int n) {
        y = y - n;
    }

    public int[] getPosition() {
        return new int[]{x, y};
    }
}