How do Java generics types ensure only the right type of object is added?

How does a generic class like Arraylist ensure that only the correct type of object is added to it if the type is erased at compile time? I know class cast get added by the compiler but that seems to be for only when retrieving objects from the class. Does the add method have class casts as well?


Let's look how to check this.

Foo.java

public class Foo extends Bar { }

Baz.java

List<Bar> list = new ArrayList<>();
list.add(new Foo());
//list.add("boo"); ***ERROR***

In the above the compiler ensures that only Bar's are added.

After compilation we change Foo.java and compile it separately:

Foo.java

public class Foo { }

When we run with the new Foo.class we may expect a ClassCastException on using an element from the list. Adding probably will not throw an exception, as with type erasure only Object is required.