Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/400.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_Design Patterns_Unbounded Wildcard - Fatal编程技术网

Java方法无界类型或类返回

Java方法无界类型或类返回,java,generics,design-patterns,unbounded-wildcard,Java,Generics,Design Patterns,Unbounded Wildcard,我在读一篇文章,是关于构建器类的子类化。我理解这篇文章,但有一点困扰着我。有这个方法, public static Builder<?> builder() { return new Builder2(); } 使用附加的传递给编译器的附加信息是什么?我怀疑是编译器在编译过程中找不到正确的实例。如果我删除(A)中的注释标记,则代码编译并运行良好。它一直在引用矩形实例。所以,我猜是编译器失败了 如果有人能给我指一篇文章来解释这一点或引导我找到更多的信息,那将是非常棒的

我在读一篇文章,是关于构建器类的子类化。我理解这篇文章,但有一点困扰着我。有这个方法,

public static Builder<?> builder() {
        return new Builder2();
}
使用附加的
传递给编译器的附加信息是什么?我怀疑是编译器在编译过程中找不到正确的实例。如果我删除(A)中的注释标记,则代码编译并运行良好。它一直在引用矩形实例。所以,我猜是编译器失败了

如果有人能给我指一篇文章来解释这一点或引导我找到更多的信息,那将是非常棒的。谢谢

我已将代码粘贴到此处:

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();
     }
}
公共类形状{
私人最终双重不透明;
公共静态类生成器{
私人双重不透明;
公共T不透明度(双不透明度){
this.opacity=不透明度;
返回自我();
}
/*删除注释标记以使编译生效(A)
公共T形高度(双高){
System.out.println(“未设置高度”);
返回自我();
}
*/
受保护的T self(){
System.out.println(“shape.self->”+this);
返回(T)这个;
}
公共形状构建(){
返回新形状(此);
}
}
公共静态生成器(){
返回新的生成器();
}
受保护形状(生成器){
this.opacity=builder.opacity;
}
}
公共类矩形扩展形状{
私人最终双高;
公共静态类生成器扩展了Shape.Builder{
私人双高;
公共T形高度(双高){
System.out.println(“设置高度”);
高度=高度;
返回自我();
}
公共矩形构建(){
返回新矩形(该矩形);
}
}
公共静态生成器(){
返回新的生成器();
}
受保护矩形(生成器){
超级建筑商;
this.height=builder.height;
}
公共静态void main(字符串[]args){
矩形r=矩形.builder().opacity(0.5).高度(250).build();
}
}
使用 附加

使用通配符
的附加信息是,返回的
矩形.Builder
是所有可能的通用
矩形.Builder
类的超类(请参阅)。由于
Rectangle.Builder
保证有一个类型参数T,它本身就是
Rectangle.Builder
的子类,只要它的泛型类型不被忽略,
Rectangle.Builder
也保证至少是
Rectangle.Builder>类型。如果通过删除通配符完全忽略泛型,则此信息将丢失,代码将编译为普通的Java5.0之前的代码(其中不存在泛型)。这是向后兼容性所必需的

查看差异,考虑矩形类的子类。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
如果执行此操作,则可以保证
T Rectangle.Builder#opacity()
的返回对象的类型为
Rectangle.Builder
,正如
类Rectangle.Builder的类型参数中声明的那样


希望这能有所帮助。

这一区别是因为当您在方法中使用原始类型时,它会将您对该类型所做的所有事情转换为泛型

例如,假设
Builder
有一个方法
foo()
,该方法返回一个
列表
。如果对类型为
Builder
的表达式调用
foo()
,它将是类型为
List
。另一方面,如果对原始类型
Builder
的表达式调用
foo()
,则该表达式的类型是
List
,而不是
List
,即使类型
List
T
完全无关。它被视为方法
foo()
的返回类型是对其实际内容的擦除

因此,在您的例子中,假设
Rectangle.builder()
返回类型
Rectangle.builder
。为了方便起见,让我们给这个
命名,比如
X
。因此,您有
Rectangle.Builder
(它继承自
Shape.Builder
),并在其上调用
opacity()
,结果是
X
。我们知道,因为
X
Rectangle.Builder
的类型参数,
X
必须是
Rectangle.Builder
的子类型。因此,我们可以对其调用
height()


但是,如果
Rectangle.builder()
返回原始类型
Rectangle.builder
,并且您对其调用
opacity()
,它将关闭方法
opacity()
上的泛型,因此它将返回其返回类型的擦除,即
Shape.builder
。你不能就此打电话给高度()

我是问类似问题的人。感谢和的回答。我试着用我能记住的外行的话来概括它

  • 没有
    ,编译器只知道返回的类型是
    Rectangle.Builder
    Rectangle.Builder
    Shape.Builder
    的子类,没有任何其他信息。s
    public static class BadBuilder extends Rectangle.Builder<BadBuilder> // -> compile time error
    
    @Override
    public T opacity(double opacity) {
        return super.opacity(opacity);
    }