Search code examples
javagenericsinterfacejava-8type-parameter

Use the type parameter of the object in a default interface method


I want to compose two codecs (code below) together, so they must have compatible types to fit together. The code works but I had to use the line Codec<F,T> c = this; for it to work otherwise the compiler didn't seem to understand correctly the type parameters (and restrictions on codec2). I'm glad the code compiles but is there a cleaner way to achieve this?

/**
 * Represents a coder-decoder from a format F to a format T
 */
public interface Codec <F,T> {
    T encode(F obj);
    F decode(T obj);

    /**
     * Compose two codecs with types <F,T> and <T,E> to a codec with type <F,E>.
     * @param codec2 The second codec
     * @return the new codec
     */
    public default <E> Codec<F,E> compose(Codec<T,E> codec2) {
        Codec<F,T> c = this;
        return new Codec<F,E>() {
            public E encode(F obj) { return codec2.encode(c.encode(obj)); }
            public F decode(E obj) { return c.decode(codec2.decode(obj)); }
        };
    }
}

Solution

  • You're declaring an anonymous inner class that implements the Codec interface.

    return new Codec<F,E>() {
        public E encode(F obj) { return codec2.encode(c.encode(obj)); }
        public F decode(E obj) { return c.decode(codec2.decode(obj)); }
    };
    

    Within the body of that anonymous class declaration, this refers to the instance of this anonymous inner class, ie. of type Codec<F, E>.

    Use Codec.this to refer to the instance of the enclosing class (the interface in this case).

    public E encode(F obj) {
        return codec2.encode(Codec.this.encode(obj));
    }
    
    public F decode(E obj) {
        return Codec.this.decode(codec2.decode(obj));
    }