避免使用具有双扩展类的泛型的未经检查的强制转换?

时间:2014-03-19 09:30:47

标签: java generics inheritance unchecked-cast

我有以下代码,我今天刚刚对此进行了重构,因为我理解<T extends Buffer>的真正含义,这是简化版本:

public class Buffer {
    protected final int bufferType;
    protected final int bufferDataType;

    protected int bufferId;
    protected boolean created;

    public Buffer(final int bufferType, final int bufferDataType) {
        this.bufferType = bufferType;
        this.bufferDataType = bufferDataType;
    }

    public <T extends Buffer> T create() {
        assertNotCreated();
        bufferId = GL15.glGenBuffers();

        created = true;
        return (T)this;
    }

    public boolean hasBeenCreated() {
        return created;
    }

    private void assertNotCreated() {
        if (hasBeenCreated()) {
            throw new RuntimeException("Buffer has been created already.");
        }
    }
}

public class ArrayBuffer extends Buffer {
    public ArrayBuffer(final int bufferDataType) {
        super(GL15.GL_ARRAY_BUFFER, bufferDataType);
    }    
}

public class DynamicDrawArrayBuffer extends ArrayBuffer {
    public DynamicDrawArrayBuffer() {
        super(GL15.GL_DYNAMIC_DRAW);
    }
}

警告发生在Buffer.create(),是否可以安全地取消警告?有没有办法让它更安全?

另一个要求是不应该在此API的调用/使用代码中添加任何混乱,具体地说这意味着DynamicDrawArrayBuffer可能无法附加泛型。

2 个答案:

答案 0 :(得分:4)

这显然不是类型安全的。你可以写

ArrayBuffer a = new ArrayBuffer(0);
DynamicDrawArrayBuffer d = a.create();

这将导致ClassCastException。从调用站点推断出create方法的返回类型。此处呼叫网站上唯一可用的信息是返回值必须为DynamicDrawArrayBuffer - 因此ArrayBuffer被粗暴地归为一个。

我认为你可以在这里轻松利用协方差:create方法总能返回类的类型。然后,create方法的返回类型由调用方法时的类型信息确定:

public class BufferTest
{
    public static void main(String[] args)
    {
        ArrayBuffer a = new ArrayBuffer();
        ArrayBuffer aa = a.create(); // Yes
        // DynamicDrawArrayBuffer ad = a.create(); // No

        DynamicDrawArrayBuffer d = new DynamicDrawArrayBuffer();
        ArrayBuffer da = a.create(); // Yes
        DynamicDrawArrayBuffer dd = d.create(); // Yes

        Buffer b = a;
        Buffer bb = b.create(); // Yes
        //ArrayBuffer ba = b.create(); // No
    }
}

class Buffer 
{
    public Buffer create() 
    {
        // create etc...
        return this;
    }

}

class DynamicDrawArrayBuffer extends ArrayBuffer 
{
    @Override
    public DynamicDrawArrayBuffer create()
    {
        super.create();
        return this;
    }
}

class ArrayBuffer extends Buffer 
{
    @Override
    public ArrayBuffer create()
    {
        super.create();
        return this;
    }
}

答案 1 :(得分:2)

更简化的版本:

public class Buffer {
    public <T extends Buffer> T create() {
        return (T)this;
    }

    public static class FooBuffer extends Buffer {}
    public static class BarBuffer extends FooBuffer {}

    public static void main(String... args) {
        BarBuffer b = new FooBuffer().create();
    }
}

main方法在没有警告的情况下编译,在ClassCastException中运行代码结果。 create中的警告指出代码中确实缺乏类型安全。