18

Getting into a little bit of confusion here when to use generics. I've looked at Java Generics? but still have a few questions.

Say I have:

public class Honda implements ICar(){
}

public class Opel implements ICar(){
}

Should I use:

public class Person{
    ICar car;
    .
    .
    public Person (ICar c){
        car = c;
    }
}

or

public class Person<T extends ICar>{
    T car;
    .
    .
    public Person(T c){
        car = c;
    }
}

or does it depend on the tasks performed?

Are generics only for aggregation relationships (containers etc); that is, are they just used for collections?

Makoto
  • 104,088
  • 27
  • 192
  • 230
intrigued_66
  • 16,082
  • 51
  • 118
  • 189
  • Generics is not just for use with collections, although it is most certainly playing it's most important role there. It's for anywhere where you want to have an object instance or method etc. work for a more specific type than what you design it for, and check during compile time (only, in case of Java) if you use the object with the correct type. However, your use case does not seem to imply that kind of relationship. – Maarten Bodewes Jul 11 '12 at 16:59
  • they can be used with any class, a "not-so-good" example is a DAO framework in which all DAO concrete classes extend a `GenericDAO` interface/abstract class. In that model every DAO is linked to an entity and primary key types and the concrete implementations may behave differently depending of the actual values of those parameters. – Alonso Dominguez Jul 11 '12 at 17:02
  • @user997112 I don't think so, if you look at the Collection classes, they have been designed to work internally with generic types, and you use them with more specific types when you use them. – Maarten Bodewes Jul 11 '12 at 17:13

6 Answers6

16

A person is generally not parameterized with a type of car. Only very annoying persons are defined by their car. Persons change cars too (in time). So I would not parameterize the class, if only for the semantics.

Think about what you try to mimic from the real world, before going into such programming details.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
12

The distinction isn't always clearcut but here are a few clues:

  1. Try to think of them as "type parameters" (Which they are.) They are associated with the class but they're not necessarily related to it. (Look at the collections framework for example.)
  2. Type parameters can only be used if they don't change throughout an object's lifetime. This sounds quite obvious, but it's a very handy rule to decide when NOT to use generics. (Example is a person who can change cars.)
  3. On the other hand, if not many instances will use the type parameter, if it's too optional, that's not a good idea either. (A lot of people might not have cars at all.)

And finally, a general thought that I found really useful: if you're unsure, don't be afraid to prototype it. Write the code both ways and check which one looks simpler and easier to comprehend. Show it to someone else without any explanations or maybe wait a day or two and then re-read the code yourself. Then throw the other one away. Throwing away code is good.

biziclop
  • 48,926
  • 12
  • 77
  • 104
  • Regarding rule 2, so you're saying for a particular instance T can be a subtype of ICar but if it changes from Honda to Opel- shouldnt use generics? – intrigued_66 Jul 11 '12 at 16:31
  • At least not this form. `T extends ICar` essentially means "any subclass of ICar, determined at object creation". – biziclop Jul 11 '12 at 16:34
  • Thanks for replying biziclop. Would your answer change if you knew that the object type would always be implementing ICar? Im not sure if you're trying to suggest that the car type could change and no longer implement ICar? I thought the generic parameter type enforced this? – intrigued_66 Jul 11 '12 at 16:36
  • No, I mean if the car changed from `Honda` to `Opel`. Your first code example can handle it. Your second one couldn't. Just try it out. – biziclop Jul 11 '12 at 16:43
8

You need the generics version if you have any methods that take or return anything involving a T, or if it's possible for other people to access your car field. (Since you didn't show any methods, we can't really tell.)

For example, with the generics version you can have a method like T someMethod();, then when someone has a Person<Honda>, they know they can get a Honda back when they call someMethod, rather than some unknown type of car if you didn't have generics.

Similarly, with the generics version you can have a method like void anotherMethod(T anotherCar);, then when someone has a Person<Honda>, this forces them to pass a Honda to this method, instead of any car.

So basically, having a generic class allows you to place constraints on uses of the object later on (method calls etc.). If the constructor is the only place that you use T, and you don't need to use T in any methods or fields, then yes, there is no point for it.

newacct
  • 119,665
  • 29
  • 163
  • 224
4

This has to do with using Inheritance versus Composition.

Without knowing any other semantics, Composition seems more relevant. A person may change cars, without becoming a different person.

http://www.artima.com/objectsandjava/webuscript/CompoInherit1.html http://en.wikipedia.org/wiki/Composition_over_inheritance

VSOverFlow
  • 1,025
  • 8
  • 11
  • Why does the inheritance matter? I thought it would be a case of whether you only use generics for aggregation as opposed to composition? – intrigued_66 Jul 11 '12 at 16:21
  • You need to separate out the design style from implementation style. The first question to ask is what is the design style (pattern) you want to use. Then figure out the language constructs to implement them. While the design pattern and implementation tend to become tightly coupled when we think, it is better to keep them separate as far as possible. In your case first figure out whether you want to use inheritance or composition; then figure out the implementation style (which may vary from language to language). – VSOverFlow Jul 11 '12 at 16:52
1

I'd tend to favor composition (what you're calling dynamic binding), especially in the case you use. A person is not a type of ICar, so using the generics here is kind of weird (to me anyway). I'd use generics as a way of saying "A container for ICar", as in Garage although in that case I might just use a collection type as a variable, or extend the collection type if really needed.

Robert
  • 2,441
  • 21
  • 12
0

I'd suggest to focus on semantics first:

Providing that you may have a Bmw and a Toyota classes implementing the ICar interface, then make this question: can a Person change his car or would it be a different person if he does so?

The generics approach will force you to create a new Person instance if for some reason you need to change the value of the car attribute from Toyota to Bmw in an existent person instance and thus, this new person will be different from the previous one. Of course, you could create the first Person instance as Person<ICar> instead of hooking it to a specific car class but, why use generics then?

Alonso Dominguez
  • 7,750
  • 1
  • 27
  • 37
  • That is exactly my confusion- why use generics if you can insert the interface name as the generic parameter.... – intrigued_66 Jul 11 '12 at 16:38
  • it's exactly the same that biziclop and owlstead had already stated but with different words: When using generics your class at compile time will be linked to the parameter type. They are very useful with collections as it helps you to know which type is contained inside the collection (an `ArrayList`it's not the same as an `ArrayList` and, if for some reason, you need to mutate the former to the latter you transform the list ending up with two complete different objects). With your model I think `Person` should be "the same" when changing from one car to another... – Alonso Dominguez Jul 11 '12 at 16:42
  • another example of the opposite: if for some reason you need an heterogeneous list, then you need to declare it as a `ArrayList`, which is the same as a `ArrayList` with no type – Alonso Dominguez Jul 11 '12 at 16:46