Избегать непроверенных приведений с дженериками с двойными расширяющимися классами?
У меня есть следующий код, который я только что рефакторинг на это сегодня, так как я понимаю, что <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 ответа
Это явно не типобезопасно. Ты можешь написать
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;
}
}
Еще более упрощенная версия:
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
указывает на реальное отсутствие типов безопасности в коде.