为什么 "cannot select from a type variable"
Why the "cannot select from a type variable"
我有以下 类:
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;
}
}
}
public class A1 extends A {
public static class Builder extends A.Builder<A1> {
public Builder() {
this.a = new A1();
}
public A1 build() {
return this.a;
}
}
}
public class A2 extends A {
public String subAtt;
public static class Builder extends A.Builder<A2> {
public Builder() {
this.a = new A2();
}
public A2 build() {
return this.a;
}
public Builder setSubAtt(String subAtt) {
a.subAtt = subAtt;
return this;
}
}
}
为什么我在 A.setAtt
上收到“cannot select from a type variable”错误?
类型擦除不适用。 T
是 A1
或 A2
但这在编译时是已知的。
我应该如何 return 子类生成器呢?我的主要 objective 是能够在 setter 混合子类和超类之后执行 setter。
这不可能有效:
T.Builder
由于 T
是一种类型 变量 ,因此未绑定到任何特定类型,因此您不能指望编译器解析未知类型的嵌套类型。
T
is either A1
or A2
but this is known at compile-time.
这个假设是错误的:假设您将代码作为 JAR 提供,而另一个开发人员使用它,引入了他自己的 A
子类。如果Java代码是在封闭世界的假设下编译的,Maven将是最无用的服务。
这个假设也是无关紧要的:你需要一个相当复杂的类型系统来计算出 T.Builder
符合的一般类型。
正如 Marko 所解释的,您不能简单地使用 'T.Builder' 并期望编译器确定未知类型的嵌套 class。
你可以做的是强制 Builder
的子 class 识别自己:
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();
会起作用。
我有以下 类:
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;
}
}
}
public class A1 extends A {
public static class Builder extends A.Builder<A1> {
public Builder() {
this.a = new A1();
}
public A1 build() {
return this.a;
}
}
}
public class A2 extends A {
public String subAtt;
public static class Builder extends A.Builder<A2> {
public Builder() {
this.a = new A2();
}
public A2 build() {
return this.a;
}
public Builder setSubAtt(String subAtt) {
a.subAtt = subAtt;
return this;
}
}
}
为什么我在 A.setAtt
上收到“cannot select from a type variable”错误?
类型擦除不适用。 T
是 A1
或 A2
但这在编译时是已知的。
我应该如何 return 子类生成器呢?我的主要 objective 是能够在 setter 混合子类和超类之后执行 setter。
这不可能有效:
T.Builder
由于 T
是一种类型 变量 ,因此未绑定到任何特定类型,因此您不能指望编译器解析未知类型的嵌套类型。
T
is eitherA1
orA2
but this is known at compile-time.
这个假设是错误的:假设您将代码作为 JAR 提供,而另一个开发人员使用它,引入了他自己的 A
子类。如果Java代码是在封闭世界的假设下编译的,Maven将是最无用的服务。
这个假设也是无关紧要的:你需要一个相当复杂的类型系统来计算出 T.Builder
符合的一般类型。
正如 Marko 所解释的,您不能简单地使用 'T.Builder' 并期望编译器确定未知类型的嵌套 class。
你可以做的是强制 Builder
的子 class 识别自己:
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();
会起作用。