英文:
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<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());
}
}
I get an error
Example.java:27: error: incompatible types: Example<Object> cannot be converted to Example<String>
Example<String> example = Example.builder().build();
But when I add type to arguments of builder
method, everything works fine
public static <T> Builder<T> builder(T type) {
return new Builder<>();
}
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 <T> Builder<T> builder(Class<T> type) {
return new Builder<>();
}
Example<Optional<String>> 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
。您可以在调用方法之前使用尖括号(<>
)将泛型类型指定给方法:
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 (<>
) before the method call:
Example<String> example = Example.<String>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<String>
, but it can't infer that the Builder
returned by builder()
method should be a Builder<String>
.
You can help the compiler by breaking the statement into two statements:
Builder<String> builder = Example.builder();
Example<String> example = builder.build();
Or by specifying the type of Builder
you expect from the builder()
method:
Example<String> example = Example.<String>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<>();
}
EDIT Start:
Additionally, if you want to omit the warning you can change the Builder
class into:
public static class Builder {
private <T> Example<T> build() {
return new Example<>();
}
}
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<String> example = Example.builder().build();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论