自我约束泛型中的子类化

时间:2012-08-28 08:43:34

标签: java generics

我遇到了一个自定义泛型类型的问题,该类型具有自定义泛型子类型。

我正在尝试实现某种构建器模式,并且我希望在主方法中或多或少地使用我的语句。

任何人都可以帮助我找到一个更好的原因来声明泛型,所以我不再需要演员,我不会在语句中得到编译错误。或者任何人都可以用明文解释为什么这不起作用?

import java.util.Date;

public class SelfBoundingGenericTypeTest {
    public static void main(String[] args) {
        ConcreteType type = new ConcreteType().pageSize(1).id(12);

        SubType type2 = (SubType) new SubType().id(10).pageSize(0); // Why do i need the cast?

        SubType type3 = new SubType().pageSize(0).id(10); // Compile error
    }
}

abstract class SuperType<E extends SuperType<E>> {
    private int _pageSize = Integer.MIN_VALUE;
    private int _startIndex = Integer.MIN_VALUE;

    @SuppressWarnings("unchecked")
    public E pageSize(int value) {
        this._pageSize = value;
        return (E) this;
    }

    @SuppressWarnings("unchecked")
    public E startIndex(int value) {
        this._startIndex = value;
        return (E) this;
    }

    public int getPageSize() {
        return _pageSize;
    }

    public int getStartIndex() {
        return _startIndex;
    }
}

class SubType<E extends SubType<E>> extends SuperType<E> {
    private long _id = Long.MIN_VALUE;

    @SuppressWarnings("unchecked")
    public E id(long value) {
        this._id = value;
        return (E) this;
    }

    public long getId() {
        return _id;
    }
}

class ConcreteType extends SubType<ConcreteType> {
    private Date _startDate;

    public Date getStartDate() {
        return _startDate;
    }

    public ConcreteType startDate(Date value) {
        this._startDate = value;
        return this;
    }
}

2 个答案:

答案 0 :(得分:1)

您需要演员,因为SubType是原始类型。因此,其所有成员都是原始成员,包括从SuperType继承的成员。 SuperType.pageSize的原始签名是其擦除SuperType pageSize(int)。所以“修复”不使用原始类型。这对于ConcreteType来说都是神奇的。

修改:不要使用原始类型。永远。您应该使用ConcreteType,但在使用重新声明每种方法的愚蠢,愚蠢,愚蠢的“解决方案”之前,请改用((SubType<?>) new SubType())

答案 1 :(得分:0)

我不确定失败的原因,但这是我的理解:     抽象类SuperType&gt; {         public E pageSize(int value){...}     }

对于方法pageSize,因为你声明为extends SuperType<E>,在类型擦除之后,方法签名实际上是SuperType pageSize(int),这导致了new SubType().pageSize(0).id(10)中的问题,因为pageSize正在返回超级类型。

虽然它看起来并不像你期望的那样神奇,但是使用协变返回类型你可以简单地“重载”继承类中的那些方法:

import java.util.Date;

public class SelfBoundingGenericTypeTest {
    public static void main(String[] args) {
        ConcreteType type = new ConcreteType().pageSize(1).id(12);

        SubType type2 = new SubType().id(10).pageSize(0); // works fine now

        SubType type3 = new SubType().pageSize(0).id(10); // works fine too
    }
}

abstract class SuperType {
    private int _pageSize = Integer.MIN_VALUE;
    private int _startIndex = Integer.MIN_VALUE;

    public SuperType pageSize(int value) {
        this._pageSize = value;
        return this;
    }

    public SuperType startIndex(int value) {
        this._startIndex = value;
        return this;
    }

    public int getPageSize() {
        return _pageSize;
    }

    public int getStartIndex() {
        return _startIndex;
    }
}

class SubType extends SuperType {
    private long _id = Long.MIN_VALUE;

    public SubType id(long value) {
        this._id = value;
        return this;
    }

    public SubType pageSize(int value) {
        return (SubType) super.pageSize(value);
    }

    public SuperType startIndex(int value) {
        return (SubType) super.pageSize(value);
    }

    public long getId() {
        return _id;
    }
}

class ConcreteType extends SubType {
    private Date _startDate;

    public Date getStartDate() {
        return _startDate;
    }

    public ConcreteType startDate(Date value) {
        this._startDate = value;
        return this;
    }

    public ConcreteType id(long value) {
        return (ConcreteType) super.id(value);
    }

    public ConcreteType pageSize(int value) {
        return (ConcreteType) super.pageSize(value);
    }

    public ConcreteType startIndex(int value) {
        return (ConcreteType) super.pageSize(value);
    }

}