0

Hi all i am learning Generics in Java. in which i have created this hierarchy.enter image description here

Now i have created a LivingThing class

public class LivingThing<T extends LivingThingTypes> implements Iterable<LivingThingTypes>{
public ArrayList<T> create(Class<T> type) {
        ArrayList arrayList = new ArrayList<>();
        for (T item : list) {
            if (item.getClass().equals(type)) {
                arrayList.add(item);
            }
        }
        return arrayList;
    }
}

So when i try to access create() method like this code of section it doesn't works.

livingList.create(Human.class).size();
livingList.create(Cat.class).size();
livingList.create(Hen.class).size();

But if i change method into this it works perfectly

public class LivingThing<T extends LivingThingTypes> implements Iterable<LivingThingTypes>{
        public <V extends LivingThingTypes>ArrayList<V> create(Class<V> type) {
            ArrayList arrayList = new ArrayList<>();
            for (T item : list) {
                if (item.getClass().equals(type)) {
                    arrayList.add(item);
                }
            }
            return arrayList;
        }
    }
Tushar Pandey
  • 4,557
  • 4
  • 33
  • 50
  • how it is off topic, it is programming question. – Tushar Pandey Dec 15 '18 at 07:05
  • 1
    I think your problem actually might have to do with shadowing of T, although I'm not sure. In the first can you try renaming the T from your function declaration to a V, so you don't have two Ts in scope (T extends LivingThingTypes and the T of the arraylist) – htuy42 Dec 15 '18 at 07:14

2 Answers2

1

The important thing about generics is that they are invariant. This means in your case that even though Human class extends LivingThingTypes but List<Human> doesn't extend List<LivingThingTypes>. So basically you can't do the following assignment:

List<Human> list1;

List<LivingThingTypes> list2 = list1; //compile error

That's how Generics are designed. The reason is imaging you have a Animal parent class and Dog and Cat as child classes. Now you created a List<Dog> and assigned it to List<Animal>. Now Since Animal is parent class of Cat also you can add cats to List<Animal>. Wile iterating it may give ClassCastException. Now the basic pros of using Generics is they provide Type safety but getting ClassCastException means that is not the case and thus the Generics are invariant.

But when you use extends along with Type parameter then it allows the assignment but then you have to remember PECS(Producer Extends and Consumer Super).

In your first case you have Type Parameter declared at class level. Now when you create instance of LivingThing class you have to mention the type parameter like LivingThing<LivingThingTypes> livingList = new LivingThing();. And that becomes the value of T. Now the compiler will expect you to send the same Type inside create method also because of the reason I mentioned in the earlier para.

In your second case you are creating a new Type parameter which is bound to the method only and here you are telling it that V extends LivingThingType and thus now Class<V> type argument of create method can accept Human.class/Hen.class/Cat.class. You can use the same Type parameter T also in place of V but to avoid confusion you should name them differently as you have done.

Yug Singh
  • 3,112
  • 5
  • 27
  • 52
0

That was not working because of this concept defined in Java-Oracle-Docs.

enter image description here

(As Java Doc Says) Given two concrete types A and B (for example, Number and Integer), MyClass has no relationship to MyClass, regardless of whether or not A and B are related. The common parent of MyClass and MyClass is Object.

Tushar Pandey
  • 4,557
  • 4
  • 33
  • 50