3

With solid C++ in my back some Java concepts are not 100% clear.

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

This is 100% clear needs no explanation - but it has consequences...

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 ){...} 

Is not callable with List<Car>. However I can add Cars to myRides by:

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

Q1: Is this a good idea?

I would really want something like the first function to work. By doing something that corresponds to C++ const& and adding a copy of the incoming carList to myRides I am thinking carList would be protected from illegal access. My hopes of adding final as a function argument were crushed.

Q2: Is there some way to make a fully callable addRides(List<Driveable> rideList) work?

Nor is overloading ( List<Car> List<Bike> etc ) legal.

And yes I can make this work by adding separate functions addBikes() addCars etc or I could do new List<Drivable> at each point of call. But I am hoping for something sleeker.

Q3: Any suggestions?

Thanks a lot! Adam

Adam
  • 637
  • 1
  • 8
  • 21
  • 1
    The PECS (Produces: `extends`; Consumes: `super`) acronym is definitely worth memorizing. It is a rule you should follow whenever making a function that takes generics. http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs – Mark Peters Feb 16 '12 at 17:36

5 Answers5

4

Your addRides method should be like this:

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

When in doubt about generics usage, look for the collection interfaces in java.util, they have lots of examples, what you want to do is the same as what Collection.addAll() does.

Maurício Linhares
  • 39,901
  • 14
  • 121
  • 158
0

A1. For better protection, you can wrap your List with Collections.unmodifiableList().

A2. You need public void addRides( List<? extends Driveable> rideList ){...}, since rideList can contain anything that extends Driveable.

A3. You're welcome!

Alexander Pavlov
  • 31,598
  • 5
  • 67
  • 93
0

Use wildcard types for the generic parameter. The declaration would be

addRides(List<? extends Driveable> list);

This accepts a List of Car, Skateboard, Bike, or any other Driveable, and will compile correctly.

TDJoe
  • 1,388
  • 1
  • 10
  • 15
0

You can accomplish this by parametizing your method as such:

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 ){
        // ...
    } 
}

Which basically declares that your method will accept any List of Objects T, such that T extends from Driveable. I would recommend reading this excellent SO post which describes Java Generics from the point of view of producers and consumers.

Community
  • 1
  • 1
Perception
  • 79,279
  • 19
  • 185
  • 195
0

The question that you did not ask should have been on the very first line of code

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

Why does this not compile?

The reason it does not is the same reason that you need public void addRides( List<? extends Driveable> rideList )

Miserable Variable
  • 28,432
  • 15
  • 72
  • 133
  • The reason that it does not compile is 100% clear which is precisely why I did not ask that question! And that statement was there to establish what I do know, and what is beyond my knowledge of generics. – Adam Feb 17 '12 at 09:43
  • Sorry for my cryptic answer. The reason it does not compile is that a a `List` cannot be assigned to `List`. Similarly `List carList` cannot be bound to `List` parameter of `addRides`. In both cases you need type constraints, e.g. `List extends SomeInterface> list = new ArrayList` – Miserable Variable Feb 17 '12 at 18:38
  • Your answer was not cryptic. It was almost impolite. And I DO know the reason. I knew it all the time. I was asking something else. – Adam Feb 20 '12 at 15:02