How does Java solve this untyped generic Method?

casting, generics, java, weak-linking

Solution

I don't quite understand your question, but perhaps I can clarify some points:

Singnature such as `<A extends Animal> A getAnimalByName(String name)` involves a technique called type inference - i.e. actual type of `A` in particular invocation of `getAnimalByName()` is inferred from the left side of assignment.

Note that it's a purely compile-time feature - code such as

<A extends Animal> A getAnimalByName(String name) { ... }
...
Dog dog = getAnimalByName("foo");

turns into the following code when compiled (due to type erasure):

Animal getAnimalByName(String name) { ... }
...
Dog dog = (Dog) getAnimalByName("foo");

As you can see, your code breaks type safety guarantees - it happens when you do a cast in `return (A) a`, and compiler emits a warning about it. It's a basic guarentee of generics - if your code compiles without warnings, it doesn't break type safety.

Problem

Today I come across a Function that makes me really wondering. So lets assume this simple structure for clearification. ``` public class Animal{ public String getName(){ return null; } } public class Dog extends Animal{ @Override public String getName(){ //I'm aware that not any Dog's name is 'Pluto', but its just a Sample ;) return "Pluto" } } public class Cat extends Animal{ protected final String mName; public Cat(String name){ mName = name; } @Override public String getName(){ //cats have different names, because the internet loves cats return mName; } public void miao(){ //just a dummy } } ``` Now it is absolut valid to assign a `Dog` to an `Animal` Pointer, but invalid to Assign an `Animal` to a `Dog` Pointer like this: ``` Animal animal = new Dog(); //valid, any Dog is at least an Animal Dog dog = new Animal(); // invalid, of course not any Animal is a Dog! ``` Lets Assume an AnimalCage class, where the "Magic" happens: ``` public class AnimalCage{ private ArrayList<Animal> mCage = new ArrayList<Animal>(); public addAnimal(Animal animal){ mCage.add(animal); } // HERE is where the "Magic" happens: public <A extends Animal> A getAnimalByName(String name){ //try catch block not mandatory try{ for (Animal a: mCage){ if (name.equals(a.getName()) return (A)a; } } catch(ClassCastException cce){} return null; } } ``` With the use of the `AnimalCage` it is possible to do this: ``` //all valid AnimalCage cage = new AnimalCage(); Dog dog = new Dog(); Cat cat = new Cat("Mauzi"); Cat cat2 = new Cat("Garfield"); cage.add(dog); cage.add(cat); cage.add(cat2); // and later get it back //will return dog Dog pluto = cage.getAnimalByName("Pluto"); //will find nothing and return null Dog snoopy = cage.getAnimalByName("Snoopy); //will raise ClassCastException and return null snoopy = cage.getAnimalByName("Mauzi"); //will return Mauzi Animal mauzi = cage.getAnimalByName("Mauzi"); ``` so I can Do anything of this WITHOUT casting explicit. This leads me to the assumption, that `Erasures` aren't erased at Runtime, although I know better. Before I thought I have to give at least an Indicator on what to Cast like this Function: ``` public <A extends Animal> A getAnimalByName(String name, Class<A> animalClass){ try{ for (Animal a: mCage){ if (name.equals(a.getName()) return (A)a; } } catch(ClassCastException cce){} return null; } //use Dog dog = cage.getAnimalByName("Pluto", Dog.class); ``` I'm really wondering on how Java lets me assign Animals on Cats/Dogs, and on what specialization of Animal it has to Cast

Original source