gpt4 book ai didi

Java 方法无界类型或类返回

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:46:42 24 4
gpt4 key购买 nike

我正在阅读 this文章,关于构建器类的子类。我理解这篇文章,但有一点让我感到困扰。有这个方法,

public static Builder<?> builder() {
return new Builder2();
}

当我改变Builder<?>Builder ,原始类型,编译器不会编译代码。错误是,

Rectangle.java:33: error: cannot find symbol
System.out.println(Rectangle.builder().opacity(0.5).height(250);

使用附加 <?> 传递给编译器的附加信息是什么? ?我怀疑是编译器在编译期间无法确定正确的实例。如果我删除 (A) 中的注释标记,代码编译并运行良好。它一直指的是 Rectangle 实例。所以,我猜是编译器失败了。

如果有人可以向我指出一篇解释此内容或引导我找到更多信息的文章,那就太好了。谢谢。

我把代码贴在这里:

public class Shape {

private final double opacity;

public static class Builder<T extends Builder<T>> {
private double opacity;

public T opacity(double opacity) {
this.opacity = opacity;
return self();
}

/* Remove comment markers to make compilation works (A)
public T height(double height) {
System.out.println("height not set");
return self();
}
*/
protected T self() {
System.out.println("shape.self -> " + this);
return (T) this;
}

public Shape build() {
return new Shape(this);
}
}

public static Builder<?> builder() {
return new Builder();
}

protected Shape(Builder builder) {
this.opacity = builder.opacity;
}
}

public class Rectangle extends Shape {
private final double height;

public static class Builder<T extends Builder<T>> extends Shape.Builder<T> {
private double height;

public T height(double height) {
System.out.println("height is set");
this.height = height;
return self();
}

public Rectangle build() {
return new Rectangle(this);
}
}

public static Builder<?> builder() {
return new Builder();
}

protected Rectangle(Builder builder) {
super(builder);
this.height = builder.height;
}

public static void main(String[] args) {
Rectangle r = Rectangle.builder().opacity(0.5).height(250).build();
}
}

最佳答案

What was the additional information passed to the compiler using the additional <?>?

使用通配符的附加信息<?>是,返回的 Rectangle.Builder<?>是所有可能的generic 的父类(super class) Rectangle.Builder<T>类(参见 Wildcards )。自 Rectangle.Builder<T>保证有一个类型参数 T,它本身是 Rectangle.Builder 的子类, 只要它的通用类型不被忽略, Rectangle.Builder<?>也保证至少是 Rectangle.Builder<? extends Rectangle.Builder<?>> 类型.如果您通过删除通配符完全忽略泛型,则此信息将丢失并且代码将被编译为普通的 Java5.0 之前的代码(其中不存在泛型)。这是向后兼容所必需的。

要查看差异,请考虑忽略通用类型的 Rectangle.Builder 的子类:

public static class BadBuilder extends Rectangle.Builder {
private double height;

public BadBuilder height(double height) {
System.out.println("height is set");
this.height = height;
return (BadBuilder) self();
}

@Override
public Shape.Builder opacity(double opacity) {
return new Shape.Builder();
}

public Rectangle build() {
return new Rectangle(this);
}
}

请注意,此类会覆盖 Shape.Builder#opacity 返回其自身的子类。编译器不会为此类生成错误(但它可能会警告您,该类会忽略通用类型)。因此,如果没有通用信息,返回类型 Shape.Builder合法的从不透明度方法。一旦您向 BadBuilder 添加类型参数,此代码将不再编译:

public static class BadBuilder extends Rectangle.Builder<BadBuilder> // -> compile time error

所以你得到编译器错误的原因cannot find symbol是的,因为类 Shape.Builder本身不声明方法/符号 T Shape.Builder#heigth() , 和声明的方法 T Shape.Builder#opacity()只保证返回的对象是 Shape.Builder 类型,如 class Shape.Builder<T extends Shape.Builder<T>> 的类型参数中声明的那样.因此调用方法链 Rectangle.builder().opacity(0.5).height(250)只有在 Rectangle.builder() 时才有效实际上保证返回一个 Builder,它是用 Rectangle.Builder 的子类键入的。如果不忽略通用类型(如 BadBuilder 示例中所示),则只能提供此保证。

添加方法时 Shape.Builder#heigth , 通过删除代码中的注释,这个错误显然消失了,因为 Shape.Builder Shape.Builder#opacity 返回的对象也会有相应的方法。您还可以通过重新声明 Shape.Builder#opacity 来消除此错误。在 Rectangle.Builder 中像这样:

@Override
public T opacity(double opacity) {
return super.opacity(opacity);
}

如果您这样做,则可以保证 T Rectangle.Builder#opacity() 的返回对象类型为 Rectangle.Builder ,如 class Rectangle.Builder<T extends Rectangle.Builder<T>> extends Shape.Builder<T> 的类型参数中声明的那样.

希望这对您有所帮助。

关于Java 方法无界类型或类返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22525088/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com