为什么构建器丢失了类型?

huangapple go评论93阅读模式
英文:

Why builder lost type?

问题

以下是翻译好的内容:

当我尝试这样做时

public class Example<T> {
    private T value;

    private Example() {

    }

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }

    public static <T> Builder<T> builder() {
        return new Builder<>();
    }

    public static class Builder<T> {
        public Example<T> build() {
            return new Example<>();
        }
    }

    public static void main(String[] args) {
        Example<String> example = Example.builder().build();
        example.setValue("test");
        System.out.println(example.getValue().toUpperCase());
    }
}

我得到一个错误

Example.java:27: 错误不兼容的类型无法将 Example<Object> 转换为 Example<String>
        Example<String> example = Example.builder().build();

但是当我在 builder 方法的参数中添加类型时一切正常运作

public static <T> Builder<T> builder(T type) {
    return new Builder<>();
}

为什么我如何消除这个虚拟的类型参数

附加问题如何将复杂类型传递给像这样的方法

public static <T> Builder<T> builder(Class<T> type) {
    return new Builder<>();
}

Example<Optional<String>> example = Example.builder(???).build();

**更新** 这只是一个示例实际应用中将会有多个构建器在构建过程的不同阶段相互创建并且当然它们将具有接受泛型类型的方法我希望有一种方法可以帮助编译器推断类型我甚至同意使用反射的技巧如果有的话它们可以帮助我获得一个漂亮的 DSL
英文:

When I try something like this

public class Example&lt;T&gt; {
private T value;
private Example() {
}
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
public static &lt;T&gt; Builder&lt;T&gt; builder() {
return new Builder&lt;&gt;();
}
public static class Builder&lt;T&gt; {
public Example&lt;T&gt; build() {
return new Example&lt;&gt;();
}
}
public static void main(String[] args) {
Example&lt;String&gt; example = Example.builder().build();
example.setValue(&quot;test&quot;);
System.out.println(example.getValue().toUpperCase());
}
}

I get an error

Example.java:27: error: incompatible types: Example&lt;Object&gt; cannot be converted to Example&lt;String&gt;
Example&lt;String&gt; example = Example.builder().build();

But when I add type to arguments of builder method, everything works fine

public static &lt;T&gt; Builder&lt;T&gt; builder(T type) {
return new Builder&lt;&gt;();
}

Why? And how I can rid off this dummy type argument?

Bonus question: How to pass complex type to the method like this?

public static &lt;T&gt; Builder&lt;T&gt; builder(Class&lt;T&gt; type) {
return new Builder&lt;&gt;();
}
Example&lt;Optional&lt;String&gt;&gt; example = Example.builder(???).build();

UPDATE: It's only an example. The real-life application will have several builders creating each other on different stages of the building process and of course, they will have methods accepting generic type. I hope there is a way to help the compiler infer types. I even agree to tricks with reflection, if any exist and they can help me to get a beautiful DSL.

答案1

得分: 2

"Example"是一个原始类,因此隐式地,T被视为Object。您可以在调用方法之前使用尖括号(&lt;&gt;)将泛型类型指定给方法:

Example<String> example = Example.<String>builder().build();
// 这里 --------------------------^
英文:

Example is a raw class, so implicitly T is Object. You can specify the generic type when calling the method by putting it in angle-brackets (&lt;&gt;) before the method call:

Example&lt;String&gt; example = Example.&lt;String&gt;builder().build();
// Here --------------------------^

答案2

得分: 1

编译器可以推断出您要创建的Example是一个Example<String>,但它无法推断出builder()方法返回的Builder应该是一个Builder<String>

您可以通过将语句分为两个语句来帮助编译器:

Builder<String> builder = Example.builder();
Example<String> example = builder.build();

或者通过指定您从builder()方法中期望的Builder类型来帮助编译器:

Example<String> example = Example.<String>builder().build();
英文:

The compiler can infer that the Example you are trying to create is an Example&lt;String&gt;, but it can't infer that the Builder returned by builder() method should be a Builder&lt;String&gt;.

You can help the compiler by breaking the statement into two statements:

Builder&lt;String&gt; builder = Example.builder();
Example&lt;String&gt; example = builder.build();

Or by specifying the type of Builder you expect from the builder() method:

Example&lt;String&gt; example = Example.&lt;String&gt;builder().build();

答案3

得分: 1

只要您不介意未检查的赋值警告,您可以仅进行以下更改:

public static Builder builder() {
    return new Builder<>();
}

编辑开始:

此外,如果您想要省略警告,可以将Builder类更改为:

public static class Builder {
    private <T> Example<T> build() {
        return new Example<>();
    }
}

并将静态的Builder方法更改为:

public static Builder builder() {
    return new Builder();
}

编辑结束。

然后您可以像这样使用它:

Example<String> example = Example.builder().build();
英文:

if you don't mind an Unchecked assignment warning you could add just the following change:

    public static Builder builder() {
return new Builder&lt;&gt;();
}

EDIT Start:

Additionally, if you want to omit the warning you can change the Builder class into:

    public static class Builder {
private &lt;T&gt; Example&lt;T&gt; build() {
return new Example&lt;&gt;();
}
}

and change the static Builder method to:

public static Builder builder() {
return new Builder();
}

EDIT End.

and then you can use it like this:

Example&lt;String&gt; example = Example.builder().build();

huangapple
  • 本文由 发表于 2020年4月5日 19:02:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/61041551.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定