使用接口作为类型参数并使用生成器模式的Java泛型

使用接口作为类型参数并使用生成器模式的Java泛型,java,generics,interface,builder-pattern,Java,Generics,Interface,Builder Pattern,我有一个接口Foo和一个实现Foo的枚举栏。然后我使用一个简单的生成器模式类结果。请参阅下面的代码 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) { retur

我有一个接口Foo和一个实现Foo的枚举栏。然后我使用一个简单的生成器模式类结果。请参阅下面的代码

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;
    }
}
公共接口Foo{}
公共枚举栏实现Foo{Bar}
公开课成绩{
公共结果(T结果){}
公共静态结果(T结果){
返回新结果(Result);
}
公共结果集(){
归还这个;
}
}
尝试生成Bar.Bar类型的结果并将其分配给结果变量时,此操作正常:

Result<Foo> r1 = Result.of(Bar.BAR);
Result r1=Result.of(Bar.Bar);
但下面给出了一个编译错误:

Result<Foo> r2 = Result.of(Bar.BAR).set();
Result r2=Result.of(Bar.Bar.set();
不兼容的类型。必需:结果,找到:结果

谁能解释一下原因吗

谁能解释一下原因吗

因为泛型很难,编译器很难猜出你的意思

在Java8中它变得更好了。您的第一次尝试将无法在Java7及以下版本上编译

of
是一种通用方法。Java上的类型推断查看周围的上下文(本例中为赋值变量的类型),以确定目标类型参数。在您的示例中,它可以推断出
Foo
,因为
Bar.Bar
Foo
的一个子类型

Result<Foo> r1 = Result.of(Bar.BAR).set();
Result<Foo> r2 = Result.<Foo>of(Bar.BAR).set();
在第二个示例中,链接方法使问题变得更加困难。而且
set
不是通用方法。因此,它取决于调用它的表达式的类型。由于方法链接,编译器不能依赖于调用的
的上下文。它采用它所看到的类型,即
Bar
Bar.Bar
。然后调用变为(澄清类型)

((结果)Bar.Bar).set();
其中
set
的返回类型为
Bar

因为

结果
不是
结果
,因此一个表达式不能分配给另一个表达式

谁能解释一下原因吗

因为泛型很难,编译器很难猜出你的意思

在Java8中它变得更好了。您的第一次尝试将无法在Java7及以下版本上编译

of
是一种通用方法。Java上的类型推断查看周围的上下文(本例中为赋值变量的类型),以确定目标类型参数。在您的示例中,它可以推断出
Foo
,因为
Bar.Bar
Foo
的一个子类型

Result<Foo> r1 = Result.of(Bar.BAR).set();
Result<Foo> r2 = Result.<Foo>of(Bar.BAR).set();
在第二个示例中,链接方法使问题变得更加困难。而且
set
不是通用方法。因此,它取决于调用它的表达式的类型。由于方法链接,编译器不能依赖于调用
的上下文。它采用它所看到的类型,即
Bar
Bar.Bar
。然后调用变为(澄清类型)

((结果)Bar.Bar).set();
其中
set
的返回类型为
Bar

因为


Result
不是
Result
,因此一个表达式不能分配给另一个表达式。

第一个示例编译,因为根据Java8的目标类型推断,
T
被推断为
Foo
,而不是
Bar

Result<Foo> r1 = Result.of(Bar.BAR);
在赋值操作符将结果赋值给
r1
之前,调用
set()
方法。这里,
Result.of(Bar.Bar).set()
必须单独考虑,而不考虑
r1
的类型,因此
T
被推断为
Bar

而且,Java的泛型是不变的,因此即使
Foo
结果也不是
结果。但是您可以使用通配符来解决这种情况

Result<? extends Foo> r1 = Result.of(Bar.BAR).set();
而且,这不是,;您的
of
方法只是一个工厂方法。构建器模式使用单独的类,其全部目的是构建目标类的实例

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;
    }
}
公共类结果{
//防止除生成器类之外的任何人实例化
//通过将构造函数设为私有来初始化该类。
私有结果(T结果){}
公共静态类生成器
{
私人T结果;
公共无效设置结果(T结果)
{
this.result=结果;
}
公共结果生成()
{
返回新结果(Result);
}
}
公共结果集(){
归还这个;
}
}

第一个示例之所以编译,是因为根据Java8的目标类型推断,
T
被推断为
Foo
,而不是
Bar

Result<Foo> r1 = Result.of(Bar.BAR);
在赋值操作符将结果赋值给
r1
之前,调用
set()
方法。这里,
Result.of(Bar.Bar).set()
必须单独考虑,而不考虑
r1
的类型,因此
T
被推断为
Bar

而且,Java的泛型是不变的,因此即使
Foo
结果也不是
结果。但是您可以使用通配符来解决这种情况

Result<? extends Foo> r1 = Result.of(Bar.BAR).set();
而且,这不是,;您的
of
方法只是一个工厂方法。构建器模式使用单独的类,其全部目的是构建目标类的实例

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;
    }
}
公共类结果{
//防止除生成器类之外的任何人实例化
//通过将构造函数设为私有来初始化该类。
私有结果(T结果){}
公共静态类生成器
{
私人T结果;
公共无效设置结果(T结果)
{
this.result=结果;
}
公共结果生成()
{
返回新结果(Result);
}
}
公共结果集(){
归还这个;
}
}