Java 以接口作为类型参数并使用构建器模式的泛型
Java generics with interface as type argument and using builder pattern
我有一个接口 Foo 和一个实现 Foo 的枚举 Bar。然后我使用一个简单的构建器模式 class 结果。请参阅下面的代码。
public interface Foo {}
public enum Bar implements Foo { BAR }
public class Result<T> {
public Result(T result) {}
public static <T> Result<T> of(T result) {
return new Result<>(result);
}
public Result<T> set() {
return this;
}
}
当尝试构建 Bar.BAR 类型的结果并将其分配给 Result 变量时,这工作正常:
Result<Foo> r1 = Result.of(Bar.BAR);
但是编译报错:
Result<Foo> r2 = Result.of(Bar.BAR).set();
不兼容的类型。要求:结果,找到:结果
谁能解释一下为什么?
Could anyone please explain why?
因为泛型很难,编译器很难猜出你的意思。
它在 Java 8 中变得更好。您的第一次尝试将无法在 Java 7 及更低版本上编译。
of
是一种通用方法。 Java 上的类型推断查看周围的上下文,在这种情况下是分配变量的类型,以确定目标类型参数。在您的示例中,它可以推断 Foo
,因为 Bar.BAR
是 Foo
.
的子类型
在您的第二个示例中,链接方法使事情变得更加困难。 set
不是通用方法。因此,它取决于调用它的表达式的类型。由于方法链接,编译器不能依赖于 of
调用的上下文。它采用它所看到的类型,即。 Bar
对于 Bar.BAR
。然后调用变为(澄清类型)
((Result<Bar>) Bar.BAR).set();
其中 set
有一个 return 类型的 Bar
。
并且因为
- Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?
a Result<Bar>
不是 Result<Foo>
所以一个表达式不能分配给另一个。
第一个示例编译是因为 T
被推断为 Foo
,而不是 Bar
,作为 Java 8 的目标类型推断的结果。
Result<Foo> r1 = Result.of(Bar.BAR);
它编译是因为 Bar
是 Foo
,所以它可以作为参数传递给 of
方法。
第二个示例无法编译,因为必须将 T
推断为 Bar
,而不是 Foo
。
Result<Foo> r1 = Result.of(Bar.BAR).set();
在赋值运算符将结果赋值给r1
之前调用set()
方法。这里必须孤立地考虑Result.of(Bar.BAR).set()
,没有考虑r1
的类型,所以T
被推断为Bar
.
此外,Java 的泛型是不变的,所以即使 Bar
是 Foo
,Result<Bar>
也不是 Result<Foo>
。但是您可以使用通配符来解决这种情况。
Result<? extends Foo> r1 = Result.of(Bar.BAR).set();
您的第一个示例当然是另一种解决方法。
另一种解决方法,如 Paul Boddington 的评论中所述,是对泛型方法使用显式类型参数 of
。这明确地将 T
设置为 Foo
.
Result<Foo> r2 = Result.<Foo>of(Bar.BAR).set();
还有,这不是Builder Pattern;您的 of
方法只是一个工厂方法。构建器模式使用单独的 class,其全部目的是构造目标 class.
的实例
public class Result<T> {
// Prevent anyone except the Builder class from instantiating
// this class by making the constructor private.
private Result(T result) {}
public static class Builder<T>
{
private T result;
public void setResult(T result)
{
this.result = result;
}
public Result<T> build()
{
return new Result(result);
}
}
public Result<T> set() {
return this;
}
}
我有一个接口 Foo 和一个实现 Foo 的枚举 Bar。然后我使用一个简单的构建器模式 class 结果。请参阅下面的代码。
public interface Foo {}
public enum Bar implements Foo { BAR }
public class Result<T> {
public Result(T result) {}
public static <T> Result<T> of(T result) {
return new Result<>(result);
}
public Result<T> set() {
return this;
}
}
当尝试构建 Bar.BAR 类型的结果并将其分配给 Result
Result<Foo> r1 = Result.of(Bar.BAR);
但是编译报错:
Result<Foo> r2 = Result.of(Bar.BAR).set();
不兼容的类型。要求:结果
谁能解释一下为什么?
Could anyone please explain why?
因为泛型很难,编译器很难猜出你的意思。
它在 Java 8 中变得更好。您的第一次尝试将无法在 Java 7 及更低版本上编译。
of
是一种通用方法。 Java 上的类型推断查看周围的上下文,在这种情况下是分配变量的类型,以确定目标类型参数。在您的示例中,它可以推断 Foo
,因为 Bar.BAR
是 Foo
.
在您的第二个示例中,链接方法使事情变得更加困难。 set
不是通用方法。因此,它取决于调用它的表达式的类型。由于方法链接,编译器不能依赖于 of
调用的上下文。它采用它所看到的类型,即。 Bar
对于 Bar.BAR
。然后调用变为(澄清类型)
((Result<Bar>) Bar.BAR).set();
其中 set
有一个 return 类型的 Bar
。
并且因为
- Is List<Dog> a subclass of List<Animal>? Why aren't Java's generics implicitly polymorphic?
a Result<Bar>
不是 Result<Foo>
所以一个表达式不能分配给另一个。
第一个示例编译是因为 T
被推断为 Foo
,而不是 Bar
,作为 Java 8 的目标类型推断的结果。
Result<Foo> r1 = Result.of(Bar.BAR);
它编译是因为 Bar
是 Foo
,所以它可以作为参数传递给 of
方法。
第二个示例无法编译,因为必须将 T
推断为 Bar
,而不是 Foo
。
Result<Foo> r1 = Result.of(Bar.BAR).set();
在赋值运算符将结果赋值给r1
之前调用set()
方法。这里必须孤立地考虑Result.of(Bar.BAR).set()
,没有考虑r1
的类型,所以T
被推断为Bar
.
此外,Java 的泛型是不变的,所以即使 Bar
是 Foo
,Result<Bar>
也不是 Result<Foo>
。但是您可以使用通配符来解决这种情况。
Result<? extends Foo> r1 = Result.of(Bar.BAR).set();
您的第一个示例当然是另一种解决方法。
另一种解决方法,如 Paul Boddington 的评论中所述,是对泛型方法使用显式类型参数 of
。这明确地将 T
设置为 Foo
.
Result<Foo> r2 = Result.<Foo>of(Bar.BAR).set();
还有,这不是Builder Pattern;您的 of
方法只是一个工厂方法。构建器模式使用单独的 class,其全部目的是构造目标 class.
public class Result<T> {
// Prevent anyone except the Builder class from instantiating
// this class by making the constructor private.
private Result(T result) {}
public static class Builder<T>
{
private T result;
public void setResult(T result)
{
this.result = result;
}
public Result<T> build()
{
return new Result(result);
}
}
public Result<T> set() {
return this;
}
}