По правде говоря, JVM не знает, как вернуть их в исходное. Мы должны будем выполнить эту задачу для этого. Рассмотрим это ... (после ваших строк кода)
SomeOtherObject obj = arr.get(2); //trying to access the third element
Вы обязательно получите ошибку во время компиляции. Теперь попробуйте явно передать возвращенный объект.
SomeOtherObject obj = (SomeOtherObject)arr.get(2);
Это работает отлично! Зачем? Потому что объект, возвращаемый методом get(), был совместим с типом, который он выполнял.
Теперь рассмотрим это также (я знаю, что я не могу этого сделать), просто для проверки того, может ли JVM сказать нам, какой именно объект.
SomeOtherObject obj = (SomeOtherObject)arr.get(1); //1 instead of 2
Да, да, я знаю, что второй член этого массива является строкой, и я не могу этого сделать. Но давайте посмотрим, что должен сказать JVM (хотя ошибка компилятора отсутствует). Сообщение, которое мы получаем, состоит в том, что объект не может быть передан указанному типу. (Но мы не получаем точный тип объекта).
Вы поняли? JVM здесь знает только, что объекты, передаваемые этому массиву, являются объектами, совместимыми с Object. Он не имеет понятия, действительно ли мы передали String, int (или, скорее, Integer, потому что примитивы не могут быть сохранены в коллекциях) или SomeOtherObject (любой класс, определенный в Java, является непосредственным подклассом Object).
Теперь, чтобы ответить на ваш вопрос:
(Как я смог получить строку и Integer обратно в нормальное (хотя я все равно придется вводить отливка их)) Причина в том, что строки и классы-оболочки (Integer - это класс-оболочка) переопределили метод toString(), унаследованный от Object. Поэтому печать этих объектов дает фактическое значение.
(Как JVM знает, какой тип их отличает) JVM на самом деле не знает, какой объект должен быть преобразован в какой тип перед возвратом пользователю. Он вернет только экземпляр объекта (это то, что JVM знает об объекте). Мы должны будем явно привести его к соответствующему типу.
Надеюсь, я ответил на ваш вопрос. Дайте мне знать, если это неясно.
Подробное описание о времени выполнения полиморфизм (ваш заголовок вопроса) дается на этом сайте: http://www.javatpoint.com/runtime-polymorphism-in-java
Casting не преобразование, за исключением случая примитивных типов. – EJP