2010-01-27 2 views
1

Пусть я:Дженерики вопрос

public interface Action<S extends Shape> { 
    public void start(S shape); 
} 

Почему я получаю следующее?

public <S extends Shape> void performAction(Action<S> action, Shape shape) { 
    action.start(shape); // error: cannot supply Shape 
} 

Другими словами, в будущем, я мог бы иметь подклассы Shape и Action S, которые работают на них, как:

Action<Rectangle> 
Action<Blob> 

Я хотел бы иметь единый интерфейс, который может применяться Action s к набору различных подклассов Shape.

ответ

5

Я думаю, что нужно что-то вроде этого:

public <S extends Shape> void performAction(Action<S> action, S shape) { 
    action.start(shape); 
} 

Однако в этом случае не ясно, какое значение есть при помощи дженерики, если все, что вы заинтересованы в том, Shape и его подклассы. Код ниже выполнил бы то же самое.

public interface Action { 
    public void start(Shape someShape); 
} 

public void performAction(Action action, Shape someShape) { 
    action.start(someShape); 
} 

Если же Action класс полностью универсален и может быть использован с другими объектами, чем Shape и его подклассов, то вы можете сделать следующее:

public interface Action<S> { 
    public void start(S target); 
} 

public <S> void performAction(Action<S> action, S target) { 
    action.start(target); 
} 
+0

+1. В исходном коде не было никакой гарантии, что 'shape' был любого типа' action'. –

+0

В этом случае, я думаю, что дженерики только что усложняют ситуацию. – jjnguy

+0

@jjnguy, Согласованные дженерики кажутся ненужными в этом простом случае. –

1

Сигнатура start требует S, но вы передаете ему Shape.

1

Потому что действие предназначено для специализации формы, а не любой формы.

3

Я не думаю, что вам обязательно нужны дженерики в этом случае. Вот что я хотел бы сделать:

public interface Action { 
    public void start(Shape someShape); 
} 

public void performAction(Action action, Shape someShape) { 
    action.start(someShape); 
} 

Затем вы можете передать любой тип, который расширяет Shape в метод start().

+0

Но предположим, что Action должен использовать какой-либо метод в подклассе Shape, т. Е. Как метод getWidth() для Rectangle. В этом случае выполнение действия, предназначенного для прямоугольника на объекте Shape, потребует кастинга и больше не является в целом безопасным. Что делать? – Jake

+0

Если бы это было так, дайте Shape метод под названием 'getWidth()' и правильно переопределите его во всех подклассах. – jjnguy

+0

@Jake См. Непосредственно над комментарием. – jjnguy

1

Для базовой потребности, я предлагаю:

public interface Action { 
    public void start(Shape shape); 
} 

Или, если вам нужно ввести их сильнее, вы могли бы изменить другой:

public <S extends Shape> void performAction(Action<S> action, S shape) { 
    action.start(shape); 
}