简体   繁体   中英

Java- Returning different classes based on generic type

I would like to create a class that will take in different types. It should handle some basic operations like .equals() for all given types, but I'd like to create specific implementations for Strings and Booleans for example.

I'd like to use the same constructor but control what happens based on the type.

public class TestObject<T>{
     private T value;

     public TestObject{

     }

     public setValue(T value){
         this.value=value;
     }

     public return Type??? getSpecificType(){
        if (value instanceof Boolean){
        return new TestObjectBoolean(this);
        }
        if (value  instanceof String){
        return new TestObjectString(this);
        }
     }

}

The desired usage below:

TestObject<String> test = new TestObject<String>();
test.setValue("Test");
boolean result = test.getSpecificType().stringSpecificMethod()

TestObject<Integer> test2 = new TestObject<Boolean>();
test.setValue(true);
boolean result2= test2.getSpecificType().booleanSpecificMethod();

I would like the below example to fail to compile:

TestObject<String> test3 = new TestObject<String>();
test.setValue("Test");
boolean result3= test3.getSpecificType().booleanSpecificMethod();
//should not compile because test2 should return a boolean specific class 
//with the boolean specific methods

It may seem silly but I would like to avoid calling differently named constructors for different types like this:

TestObjectString test4 = new TestObjectString();
test.setValue("Test");
boolean result4= test4.stringSpecificMethod();

I am lost on how to implement this. Any advice or help on searching additional information on this would be appreciated.

Thank you.

I'm not sure I understand what you're asking for, but I think you want to make the constructor private, and add public factory methods:

public class TestObject<T> {

    private T value;

    private final Supplier<? extends TestObject<T>> typeSpecificConstructor;

    private TestObject(T initialValue,
                       Supplier<? extends TestObject<T>> constructor) {
        this.value = initialValue;
        this.typeSpecificConstructor = constructor;
    }

    protected TestObject(Supplier<? extends TestObject<T>> constructor) {
        this.typeSpecificConstructor = constructor;
    }

    public boolean test(T valueToTest) {
        throw new UnsupportedOperationException(
            "Must be implemented by subclasses");
    }

    public static TestObject<Boolean> newInstance(boolean initialValue) {
        return new TestObject<>(initialValue, TestObjectBoolean::new);
    }

    public static TestObject<String> newInstance(String initialValue) {
        return new TestObject<>(initialValue, TestObjectString::new);
    }

    public TestObject<T> getSpecificType() {
        return typeSpecificConstructor.get();
    }

    public T getValue() {
        return value;
    }

    public void setValue(T newValue) {
        this.value = newValue;
    }
}

But methods particular to a subtype still won't be accessible. There is simply no way for a variable whose type is a general superclass to make subclass methods available without casting.

I'm not sure what your intended purpose of getSpecificType() is, but you could probably do away with that method and make things simpler:

public abstract class TestObject<T> {

    private T value;

    public abstract boolean test(T valueToTest);

    public static TestObject<Boolean> newInstance(boolean initialValue) {
        TestObject<Boolean> instance = new TestObjectBoolean();
        instance.setValue(initialValue);
        return instance;
    }

    public static TestObject<String> newInstance(String initialValue) {
        TestObject<String> instance = new TestObjectString();
        instance.setValue(initialValue);
        return instance;
    }

    public T getValue() {
        return value;
    }

    public void setValue(T newValue) {
        this.value = newValue;
    }
}

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