Подтвердить что ты не робот

Java - передача ArrayList типа интерфейса

У меня есть интерфейс Damageable следующим образом

public interface Damageable {
    public void handleCollision(float impulse);
}

класс, реализующий этот интерфейс, BaseObject

public class BaseObject implements Damageable

Теперь в третьем классе у меня есть ArrayList типа BaseObject

public class ObjectManager {    
    public ArrayList<BaseObject> bodies;

То, что я пытаюсь сделать, - передать тела ArrayList методу другого класса, который принимает ArrayList

public CollisionManager( ArrayList<Damageable> _bodies) {
        bodies = _bodies;
}

Java не позволяет мне создавать новые CollisionManager (тела), где тела имеют тип ArrayList и BaseObject реализует Damageable

Я попробовал кастинг. Говорит, что нельзя ArrayList<BaseObject> в ArrayList Также попытался использовать Class<? extends Damageable>, но тогда я не могу вызывать методы, объявленные в интерфейсе Damageable. Как передать ArrayList?

4b9b3361

Ответ 1

Вы должны быть явным с вашими дженериками. Поэтому вам необходимо сообщить компилятору, что ваш общий тип не должен быть Damagable как таковой, а может расширять Damagable:

public CollisionManager(ArrayList<? extends Damagable> bodies) {

Кстати, обратите внимание, что я изменил вашу переменную на bodies, а не на _bodies. Подчеркивания не являются частью стандартных соглашений о кодировании Java.


Редактировать в ответ на комментарии OP

Скажем, что вместо интерфейса у вас был конкретный класс под названием Damagable. При написании компилятора <? extends Damagable> говорится, что он не должен быть экземпляром Damagable. Хорошо, что тип расширяется Damagable. В противном случае компилятор предполагает, что у вас есть Damagable точно.

Это не имеет особого смысла, если вы думаете о Damagable как интерфейсе, поскольку нет случая, когда у вас будет экземпляр Damagable. Но они работают по-разному.

Вы должны помнить, что работаете с типами Java, а не с классами. Синтаксис и структура Java-типа менее надежны, чем структура класса. Нет понятия о implements, когда дело касается типов.


Последний раунд изменений

Наконец, я должен отметить, что обычно лучше использовать интерфейс для параметров метода/конструктора и типов возвращаемых методов. Это позволяет вам и тем, кто использует ваши методы, использовать любую вашу реализацию, и позволяет вам изменять свою реализацию по своему усмотрению.

Итак, с этими изменениями вы бы:

public CollisionManager(List<? extends Damagable> bodies) {

Ответ 2

Попробуйте ArrayList<? extends Damageable > _bodies.

Это говорит о том, что вы хотите, чтобы ArrayList состоял из Class, который расширяет (хорошо реализует) Damageable

Ответ 3

Другие, без сомнения, укажут технические решения с точки зрения синтаксиса Java.

Я просто расскажу о нескольких проблемах дизайна, которые вы, возможно, должны учитывать:

  • Ваш BaseObject реализует Damageable. Это означает, что все объекты BaseObject являются повреждаемыми. Почему бы просто не сделать CollisionManager(ArrayList<BaseObject>)? Если вы не собираетесь использовать Damageable в другом месте (т.е. Есть вещи, которые могут быть повреждены, но не являются базовыми объектами), то это кажется ненужной абстракцией.
  • Обычно для обнаружения столкновений в игре/симуляции вы хотели бы использовать структуру пространственных данных для обнаружения конфликтов (например, Octree, Quadtree или AABB tree), а не ArrayList. Поиск коллизий в ArrayList является алгоритмом O (n ^ 2). Это станет большой проблемой, если у вас много живых объектов.
  • Повреждение кажется плохим именем, поскольку функциональность относится к обнаружению столкновений, а не к повреждению - не будет ли Collidable лучше?