YAJGCQ Еще одна универсальная версия Java против коллекций Q - PullRequest
3 голосов
/ 16 февраля 2012

С твердым C ++ за моей спиной некоторые концепции Java не ясны на 100%.

List<SomeInterface> list = new ArrayList<SomeImplementation>; 

Это на 100% ясно, не нуждается в объяснении - но это имеет последствия ...

interface Drivable {...}
class Car implements Drivable  {...}
class Bike implements Drivable  {...}
class Skateboard implements Drivable  {...}

class MyGarage{
List<Driveable> myRides;

public void addRides( List<Driveable> rideList ){...} 

Не вызывается с List<Car>. Однако я могу добавить автомобили в myRides:

public void addCars( List<Car> carList ){
myRides.addAll( new List<Driveable>( carList ) );

Q1: Это хорошая идея?

Мне бы очень хотелось, чтобы сработала первая функция. Делая что-то, что соответствует C ++ const& и добавляя копию входящего carList в myRides, я думаю, carList будет защищен от несанкционированного доступа. Мои надежды на добавление final в качестве аргумента функции были разбиты.

Q2: Есть ли способ заставить полностью вызываемую addRides(List<Driveable> rideList) работать?

Перегрузка (List<Car> List<Bike> etc) также недопустима.

И да, я могу сделать эту работу, добавив отдельные функции addBikes() addCars etc или я могу сделать new List<Drivable> в каждой точке вызова. Но я надеюсь на что-то более изящное.

Q3: Есть предложения?

Большое спасибо! Адам

Ответы [ 5 ]

4 голосов
/ 16 февраля 2012

Ваш addRides метод должен быть таким:

public void addRides(Collection<? extends Drivable> c)

Если вы сомневаетесь в использовании шаблонов, поищите интерфейсы коллекций в java.util , у них много примеров, и вы хотите сделать то же, что и Collection. addAll () делает.

0 голосов
/ 16 февраля 2012

Вопрос, который вы не задавали, должен был быть в самой первой строке кода

List<SomeInterface> list = new ArrayList<SomeImplementation>; 

Почему это не компилируется?

Причина этогоне по той же причине, что вам нужно public void addRides( List<? extends Driveable> rideList )

0 голосов
/ 16 февраля 2012

Вы можете сделать это, параметризовав свой метод следующим образом:

public class MyGarage{
    public static void main(String[] args) {
        MyGarage garage = new MyGarage();
        garage.addRides(new ArrayList<Car>(4));
        garage.addRides(new ArrayList<Bike>(4));
    }

    List<Driveable> myRides;

    public <T extends Driveable> void addRides( List<T> rideList ){
        // ...
    } 
}

, который в основном объявляет, что ваш метод будет принимать любой список объектов T, так что T расширяется от Driveable.Я бы порекомендовал прочитать этот превосходный пост SO , в котором описывается Java Generics с точки зрения производителей и потребителей.

0 голосов
/ 16 февраля 2012

Используйте подстановочные знаки для универсального параметра. Декларация будет

addRides(List<? extends Driveable> list);

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

0 голосов
/ 16 февраля 2012

A1. Для лучшей защиты вы можете заключить в свой список Collections.unmodifiableList().

A2. Вам нужно public void addRides( List<? extends Driveable> rideList ){...}, поскольку rideList может содержать все, что расширяет Driveable .

A3. Не за что!

...