Generics Flashcards
What property do generics add to collections?
They make them type-safe. We can not add any element other than specified type.
What do we call the type in brackets as above:
List myList = new ArrayList();
The type in angle brackets is referred to as the “parameterized type,” “type parameter,” or, of course, just old-fashioned “type.”
List myList = new ArrayList(); for (String s : myList) { int x = s.length(); } do we need a cast in this statement?
No need for a cast before calling a String method! The compiler already knew “s” was a String coming from myList
Would that compile: void takeListOfStrings(List strings) { strings.add(new Integer(42)); }
No, strings is type-safe.
Can return types be type-safe?
Yes, like below: public List getDogList() { List dogs = new ArrayList(); // more code to insert dogs return dogs; }
Would that code work:
public class TestBadLegacy { public static void main(String[] args) { List myList = new ArrayList(); myList.add(4); myList.add(6); Inserter in = new Inserter(); in.insert(myList); // pass List to legacy code } } class Inserter { // method with a non-generic List argument void insert(List list) { list.add(new String("42")); } }
Yes it both compiles and runs. But compiler gives a warning.
How does generics work in compile vs run time?
Think of generics as strictly a compile-time protection. The compiler uses generic type information (the in the angle brackets) to make sure that your code doesn’t put the wrong things into a collection and that you do not assign what you get from a collection to the wrong reference type. But NONE of this protection exists at runtime. Through a process called “type erasure,” the compiler does all of its verifications on your generic code and then strips the type information out of the class bytecode.
Do you have type protection in Arrays for compile or runtime?
Yes. it gives you both compile and run-time protection. But for collections it does not work that way just to support the legacy code.
Do we need casting below?
List test = new ArrayList();
test.add(43);
int x = test.get(0);
Yes we have to add;
int x = (Integer)test.get(0);
Because unboxing can’t convert a plain old Object to a primitive.
Do we need casting below?
List test2 = new ArrayList();
test2.add(343);
int x2 = test2.get(0);
No. Unboxing can unbox Integer to int since get returns Integer with generics here.
Is this declaration valid? class Parent { } class Child extends Parent { } List myList = new ArrayList();
No, it doesn’t work. There’s a very simple rule here the type of the variable declaration must match the type you pass to the actual object type. If you declare List foo, then whatever you assign to the foo reference MUST be of the generic type . Not a subtype of . Not a supertype of . Just .
Is this declaration valid? class Parent { } class Child extends Parent { } Parent[] myArray = new Child[3];
Yes
Can we assign the individual ArrayList of Animal subtypes (, , ) to an ArrayList of the supertype , which is the declared type of the argument.
No.
Ex;
AnimalDoctorGeneric.java:52: checkAnimals(java.util.ArrayList) in AnimalDoctorGeneric cannot be applied to (java.util.List) doc.checkAnimals(cats);
Is below code piece ok?
List animals = new ArrayList();
animals. add(new Cat());
animals. add(new Dog());
Yes
Is this declaration allowed? If yes what is the problem with that?
public void foo() { Dog[] dogs = {new Dog(), new Dog()}; addAnimal(dogs); } public void addAnimal(Animal[] animals) { animals[0] = new Dog(); }
The problem is when we change the caller, the problem is not realized by the compiler.
public void foo() {
Cat[] cats = {new Cat(), new Cat()};
addAnimal(cats);
}
and the original method stays the same:
public void addAnimal(Animal[] animals) {
animals[0] = new Dog();public void foo() {
Cat[] cats = {new Cat(), new Cat()};
addAnimal(cats); // no problem, send the Cat[] to the method
}
and the original method stays the same:
public void addAnimal(Animal[] animals) {
animals[0] = new Dog();
}