简体   繁体   中英

Generic method to return function returning generic self-type without the need to cast

Honestly, I'm not even sure whether that title makes sense. Hopefully the code following will explain the issue at hand.

package what.ever.you.like;

import java.util.function.UnaryOperator;

class SelfTypeTemplates {

    public static <SELF extends AbstractSelfType> UnaryOperator<SELF> simpleBound() {
        return self -> self;
    }

    public static <SELF extends AbstractSelfType<SELF>> UnaryOperator<SELF> boundWithGenericType() {
        return self -> self;
    }
}

class ConcreteSelfType extends AbstractSelfType<ConcreteSelfType> {

    public ConcreteSelfType() {
        super(ConcreteSelfType.class);
    }

    public ConcreteSelfType applySimpleBound() {
        // How to get rid of the type cast?
        return (ConcreteSelfType) SelfTypeTemplates.simpleBound().apply(this);
    }

    public ConcreteSelfType applyBoundWithGenericType() {
        // Compile error because `this` is ConcreteSelfType, but required is SELF
        return SelfTypeTemplates.boundWithGenericType().apply(this);
    }
}

class AbstractSelfType<SELF extends AbstractSelfType<SELF>> {
    protected final SELF myself;

    protected AbstractSelfType(final Class<?> type) {
        this.myself = (SELF) type.cast(this);
    }
}

My issue is with the two methods applySimpleBound() and applyBoundWithGenericType() . The former is compiling fine, but needs explicit casting, which is what I'd like to get rid of. The later does not compile, because .apply(this) requires a type SELF but provided is ConcreteSelfType .

So my question is, how do I specify the signature of a method in SelfTypeTemplates to return an UnaryOperator<SELF> so that invoking the returned function ( .apply(this) ), does not need casting in the client code (ie ContreteSelfType )?

Tried to play with different bounds in the generic and return type. Haven't found a working version without type casting.

Sometimes the compiler cannot infer the correct type for what ever reason. To work around this issue you can specify it like this:

class ConcreteSelfType extends AbstractSelfType<ConcreteSelfType> {

    public ConcreteSelfType() {
        super(ConcreteSelfType.class);
    }

    public ConcreteSelfType applySimpleBound() {
        // How to get rid of the type cast?
        return SelfTypeTemplates.<ConcreteSelfType>simpleBound().apply(this);
    }

    public ConcreteSelfType applyBoundWithGenericType() {
        // Compile error because `this` is ConcreteSelfType, but required is SELF
        return SelfTypeTemplates.<ConcreteSelfType>boundWithGenericType().apply(this);
    }
}

Both options compile this way and you don't need a cast.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM