Java 泛型 + Builder 模式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3204623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java generics + Builder pattern
提问by Jason S
How do I call start()
below?
start()
下面怎么打电话?
package com.example.test;
class Bar {}
public class Foo<K>
{
final private int count;
final private K key;
Foo(Builder<K> b)
{
this.count = b.count;
this.key = b.key;
}
public static class Builder<K2>
{
int count;
K2 key;
private Builder() {}
static public <K3> Builder<K3> start() { return new Builder<K3>(); }
public Builder<K2> setCount(int count) { this.count = count; return this; }
public Builder<K2> setKey(K2 key) { this.key = key; return this; }
public Foo<K2> build() { return new Foo(this); }
}
public static void main(String[] args)
{
Bar bar = new Bar();
Foo<Bar> foo1 = Foo.Builder.start().setCount(1).setKey(bar).build();
// Type mismatch: cannot convert from Foo<Object> to Foo<Bar>
Foo<Bar> foo2 = Foo.Builder<Bar>.start().setCount(1).setKey(bar).build();
// Multiple markers at this line
// - Bar cannot be resolved
// - Foo.Builder cannot be resolved
// - Syntax error on token ".", delete this token
// - The method start() is undefined for the type Foo<K>
// - Duplicate local variable fooType mismatch: cannot convert from Foo<Object> to Foo<Bar>
Foo<Bar> foo3 = Foo<Bar>.Builder.start().setCount(1).setKey(bar).build();
// Multiple markers at this line
// - Foo cannot be resolved
// - Syntax error on token ".", delete this token
// - Bar cannot be resolved
}
}
采纳答案by Andrei Fierbinteanu
You were close:
你很接近:
Foo.Builder.<Bar> start().setCount(1).setKey(bar).build();
Cheers! :)
干杯! :)
P.S. If the compiler can't infer the type parameter of the method on its own, you can force it by calling obj.<Type> method(...)
.
PS 如果编译器无法自行推断方法的类型参数,可以通过调用obj.<Type> method(...)
.
P.P.S you might want to use:
您可能想要使用的 PPS:
public Foo<K2> build() {
return new Foo<K2>(this);
}
Avoid using raw types.
避免使用原始类型。
回答by sfussenegger
Andrei's method is okay, but most programmers will likely struggle with the rather unknown syntax. It might be easier to use this way:
Andrei 的方法没问题,但大多数程序员可能会为相当陌生的语法而苦恼。使用这种方式可能更容易:
static public <K3> Builder<K3> start(Class<K3> cls) { return new Builder<K3>(); }
Foo<Bar> foo1 = Foo.Builder.start(Bar.class).setCount(1).setKey(bar).build();
The class is only passed to help with the generic type. It's not pretty, but at least the syntax is common knowledge.
该类仅用于帮助泛型类型。它并不漂亮,但至少语法是常识。
Another option would be to start right away with an object of the generic type:
另一种选择是立即开始使用泛型类型的对象:
Foo<Bar> foo1 = Foo.Builder.startWithKey(bar).setCount(1).build();
回答by dobrivoje
here's how I would do :
这是我会怎么做:
package odmor2018.krit.rtti.builderpattern;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
public class Person {
private String firstName;
private String middleName;
private String lastName;
private boolean sex;
public Person(String firstName, String middleName, String lastName, boolean sex) {
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.sex = sex;
}
public Person() {
}
@Override
public String toString() {
return "Person{" + "firstName=" + firstName + ", middleName=" + middleName + ", lastName=" + lastName + ", sex=" + sex + '}';
}
public static class Builder {
private final Field[] fields = Person.class.getDeclaredFields();
private final List<Field> fieldsList = Arrays.asList(fields);
private final List<String> fNames = fieldsList.stream().map(f -> f.getName()).collect(Collectors.toList());
private final Person nP = new Person();
public Builder with(String fName, Object value) {
if (fNames.contains(fName)) {
int fInd = fNames.indexOf(fName);
try {
Field f = fields[fInd];
f.setAccessible(true);
f.set(nP, value);
} catch (Exception ex) {
Logger.getLogger(Person.class.getName()).log(Level.SEVERE, null, ex);
}
}
return this;
}
public Person createPerson2() {
return nP;
}
}
public static void main(String[] args) {
Person p3 = new Person.Builder()
.with("firstName", "doooobri2")
.with("sex", false)
.createPerson2();
System.err.println("p3:" + p3);
}
}