为另一个构造函数提供类型变量值

时间:2017-02-24 16:40:34

标签: java generics

我有这堂课:

public class Test<T> {
    public Test() {
        this(() -> true); // error here
    }

    public Test(Supplier<T> c) {
    }
}

编译因以下错误而失败:

Error:(23, 24) java: incompatible types: bad return type in lambda expression
    boolean cannot be converted to T

我发现的唯一解决方法是使用静态工厂方法:

public static Test<Boolean> makeDefault() {
    return new Test<>(() -> true);
}

对于不包含某些类型变量的构造函数,是否有任何方法可以调用另一个?为什么会出现这种限制?

修改 我的用例:我有一个带有可选keyExtractor的类。键类型是类型参数之一。如果用户没有提供keyExtractor,我只使用一个返回任何常量非空值。

2 个答案:

答案 0 :(得分:3)

假设您要写:

Test<String> t = new Test<>();

这会导致调用其他构造函数;有效:

Test<String> t = new Test<String>(() -> true);

但这不是类型正确:() -> true不提供String,它提供Boolean(或SerializableObject

如果你想提供这样的默认构造函数, 你需要返回一个可以强制转换为任何值的值:唯一的值是null

this(() -> null);

或者,删除默认构造函数,并提供no-arg工厂方法:

static Test<Boolean> createInstance() {
  return new Test<>(() -> true);
}

答案 1 :(得分:1)

使其编译,您可以执行转换为原始类型:

public class Test<T> {
    public Test() {
        this((Supplier) () -> true);
    }

    public Test(Supplier<T> c) {
        this.c = c;
    }
}

这有一个缺点,即如果用户在调用构造函数时提供了错误的类型参数,他可能会出现意外ClassCastException

Test<Integer> t = new Test<>();
System.out.println(t.supplier().get()); // prints "true"

更好的方法是使用静态工厂方法,它会向用户明确说明Supplier类型:

public class Test<T> {
    public static Test<Boolean> newWithConstantSupplier() {
        return new Test<>(() -> true);
    }

    public Test(Supplier<T> c) {
        this.c = c;
    }
}

在我的情况下,我最终删除了T参数,并取消Supplier<?>,因为我在公共API中没有公开API的方法,因此有T类型,因此有&#39}。用户无需首先使用它:

public class Test {
    public Test() {
        this((Supplier) () -> true);
    }

    public Test(Supplier<?> c) {
        this.c = c;
    }
}