Java 为什么会有";无法从类型变量“中选择”;
我有以下课程:Java 为什么会有";无法从类型变量“中选择”;,java,generics,builder,Java,Generics,Builder,我有以下课程: public abstract class A { public String att; public static abstract class Builder<T extends A> { public T a; public abstract T build(); public T.Builder setAtt(String a) { this.a.att = a;
public abstract class A {
public String att;
public static abstract class Builder<T extends A> {
public T a;
public abstract T build();
public T.Builder setAtt(String a) {
this.a.att = a;
return this;
}
}
}
公共抽象类A{
公共字符串att;
公共静态抽象类生成器{
公共交通管理局;
公共抽象T build();
公共T.建筑商setAtt(字符串a){
此a.att=a;
归还这个;
}
}
}
公共类A1扩展了{
公共静态类生成器扩展了.Builder{
公共建筑商(){
this.a=新的A1();
}
公共建筑{
归还这个;
}
}
}
公共类A2扩展了{
公共字符串子集合;
公共静态类生成器扩展了.Builder{
公共建筑商(){
this.a=新的A2();
}
公共建筑{
归还这个;
}
公共生成器setSubAtt(字符串subAtt){
a、 subAtt=subAtt;
归还这个;
}
}
}
为什么在a.setAtt
上出现“无法从类型变量中选择”错误
类型擦除不适用T
是A1
或A2
,但这在编译时是已知的
那么我应该如何返回子类生成器呢?我的主要目标是能够在setter混合子类和超类之后进行setter。这不可能奏效:
T.Builder
由于T
是一个类型变量,因此没有绑定到任何特定类型,因此不能期望编译器解析未知类型的嵌套类型
T
是A1
或A2
,但这在编译时是已知的
这种假设是错误的:假设您将代码作为JAR提供,另一个开发人员使用它,并引入他自己的a
子类。如果Java代码是在封闭世界的假设下编译的,Maven将是一个非常无用的服务
这个假设也是不相关的:您需要一个非常复杂的类型系统来计算一般类型
T.Builder
符合什么。正如Marko所解释的,您不能简单地使用“T.Builder”并期望编译器确定未知类型的嵌套类
您可以强制Builder
的子类识别自身:
public class A
{
public String att;
public static abstract class Builder<T extends A, U extends Builder<T, U>>
{
public T a;
public abstract T build();
public U setAtt(String a)
{
this.a.att = a;
return getBuilder();
}
public abstract U getBuilder();
}
}
将起作用。您能分享触发错误的代码吗?将代码粘贴到IDE中不会触发编译错误。类型擦除确实适用,因为可以轻松创建另一个从外部扩展的类,然后,你的系统会崩溃。有没有办法这样做?在代码> >代码> Builder < /Cuff>类中添加一个字段“代码> A<代码>:为避免NPEs在设置超类“ATTIRAT”时,还可以考虑通过一个吸收器获得<代码> A<代码>:<代码>公共摘要T GETA()。。
U
上的绑定是不必要的:类生成器
也同样有效当您希望能够使用超类型的方法setAtt
时,U上的绑定是必要的在构建过程的任何阶段,而不仅仅是作为第一次调用。它仍然不会对您给出的示例中的第一次调用起作用,使用new A1.Builder()…
Yes,但在使用getBuilder()
的边界时,您禁止使用未提供Builder
子类的构建器的A
子类。如果没有边界,任何对象
都可能存在,例如字符串
。这会在尝试迭代构建器集合集合时引发问题
T.Builder
public class A
{
public String att;
public static abstract class Builder<T extends A, U extends Builder<T, U>>
{
public T a;
public abstract T build();
public U setAtt(String a)
{
this.a.att = a;
return getBuilder();
}
public abstract U getBuilder();
}
}
public class A1 extends A
{
public static class Builder extends A.Builder<A1, A1.Builder>
{
public Builder()
{
this.a = new A1();
}
@Override
public A1 build()
{
return this.a;
}
@Override
public A1.Builder getBuilder()
{
return this;
}
}
}
A1 build = new A1.Builder().setAtt("x").build();