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;
}
}