2014-03-19 25 views
0

我有下面的代碼,我只是重構到今天這個,因爲我明白<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

我認爲這是對泛型的濫用。你的創建方法應該是'abstract'並且返回一個'Buffer'。由於返回類型協方差,覆蓋方法可以返回它們自己的類型。 –

+0

@BoristheSpider我曾經這樣做過,但它確實看起來很醜,而且在我看來很煩人。 – skiwi

+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; 
    } 
} 
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的警告指出實際上缺乏類型安全。

相關問題