Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么会有";无法从类型变量“中选择”;_Java_Generics_Builder - Fatal编程技术网

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();