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