Java interface that returns objects with its own type

90 Views Asked by At

I was looking at an interface that is built into Java, and noticed that it has methods which return objects of its own type.

Specifically, the IntStream interface has a method range which returns an IntStream object (i.e. some object that implements IntStream). This method can be used by only importing the interface, as follows:

import java.util.stream.IntStream;

class Foo {
    public static void main(String[] args) {
        IntStream s = IntStream.range(0,10);
        System.out.println(s.average());
    }
}

It therefore seems that 'under the hood' the interface is choosing an implementation for me, and allowing me to use it. How exactly is this working?

Crucially, how would I do the same thing? If I wanted to export an interface that can instantiate objects of its own type, so that a user could simply import my interface and it would drag along my implementation, how would I do this? Or is this only a special privilege of interfaces built into Java?

3

There are 3 best solutions below

3
On BEST ANSWER

range is a static method of the IntStream interface that returns an instance of a class that implements IntStream. Take a look in the example below.

public interface MyInterface {

    public static class MyClass implements MyInterface {
        @Override 
        public void doSomething() {
            System.out.println( "i'm an implementing class!" );
        }
    }

    public static MyInterface createMagicInstance() {
        return new MyClass();
    }

    public void doSomething();

}

public class Test {
    public static void main( String[] args ) {
        MyInterface mi = MyInterface.createMagicInstance();
        mi.doSomething();
    }
}

In my example I tried to design something self-contained, but implementations of createMagicInstance may vary. You don't need to implement the returning type as a static inner class. I would recomend you to take a look at the source code of IntStream class of OpenJDK: https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/stream/IntStream.java

0
On

The "interface" is not returning anything.

IntStream.range(int, int) is a static method that returns an IntStream.

It has little to do with the IntStream interface and would work equally well if defined in another class.

0
On

If you check the definition of IntStream.range you would be able to see that range is an static method of IntStream, which means, you don't need to have an instance of IntStream to call it, you can just directly invoke it as you are doing in the piece of code you put as example. How can you do it? Just define an interface with an static method that returns an object of that interface type. You can also check the source code of IntStream and see the implementation

public static IntStream rangeClosed(int startInclusive, int endInclusive) {
    if (startInclusive > endInclusive) {
        return empty();
    } else {
        return StreamSupport.intStream(
                new Streams.RangeIntSpliterator(startInclusive, endInclusive, true), false);
    }
}