Почему List <type> поглощает нетипичный элемент во время компиляции и выполнения?

У меня есть это демо, которое мне не нужно для конкретного решения с перерисованной архитектурой, но я просто понимаю, почему ведет себя так, и все, чего мне не хватает, чтобы избежать этого. Мне интересно, почему:

Compiler allows the insertion of an element that its not the type of the list into the list

The ClassCast exception is thrown when we try to get the element instead of when pushing it

import Test.*; //Inner classes
import java.util.List;
import java.util.ArrayList;

public class Test<E extends Object> {

    private List<E> list = new ArrayList<E>();
    public Test() {}

    public static void main(String[] args) {
        Test<String> a = new Test<String>();
        a.addElement(new String());
        a.addElement(new Integer(0)); // No complain in comp/run-time, I dont understand why CastException is not thrown here
        String class1 = a.getElement(0); 
        String class2 = a.getElement(1); //No complain in comp but ClassCastException: Integer cannot be cast to String
        //Integer class3 = a.getElement(1); //Compilation error
    }

    public void addElement (Object node) { list.add((E) node); } //No complain in comp/run-time
    public E getElement(int index)       { return list.get(index); }
}

Какое может быть решение? Обратите внимание на строку addElement, где мне нужно передать суперкласс, а не тип E. Это необходимо для моей архитектуры, это просто демонстрационная демонстрация. Но в любом случае приведение к типу E должно действовать так, как нужно, и выдавать CastExeption во время выполнения, не так ли?

Ответы на вопрос(2)

Ваш ответ на вопрос