The first example compiles because T
is inferred to be Foo
, not Bar
, as a result of Java 8's target type inference.
Result<Foo> r1 = Result.of(Bar.BAR);
It compiles because a Bar
is a Foo
, so it can be passed as an argument to the of
method.
The second example doesn't compile because T
must be inferred to be Bar
, not Foo
.
Result<Foo> r1 = Result.of(Bar.BAR).set();
The set()
method is called before the assignment operator assigns the result to r1
. Here, Result.of(Bar.BAR).set()
must be considered in isolation, without considering the type of r1
, so T
is inferred to be Bar
.
Also, Java's generics are invariant, so even if a Bar
is a Foo
, a Result<Bar>
is not a Result<Foo>
. But you can use a wildcard to work around this situation.
Result<? extends Foo> r1 = Result.of(Bar.BAR).set();
Your first example is of course another workaround.
Another workaround, as mentioned in comments by Paul Boddington, is to use an explicit type argument to the generic method of
. This explicitly sets T
to Foo
.
Result<Foo> r2 = Result.<Foo>of(Bar.BAR).set();
Also, this is not the Builder Pattern; your of
method is just a factory method. A Builder Pattern uses a separate class whose entire purpose is to construct instances of the target 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;
}
}