Стирание типов (type erasure) в Java — это механизм, который используется для обеспечения обратной совместимости с версиями Java до появления дженериков (generics). Оно позволяет компилятору удалять информацию о дженериках (например, параметризованные типы) во время компиляции, сохраняя только информацию о не параметризованных версиях классов. В результате, все дженерики становятся "сырыми" типами (raw types), что соответствует типу `Object`.
### Ошибка в приведённом вами коде
Рассмотрим ваш код:
```java
Pair emp = person;
emp.setFirst(new Person());
Person pers = emp.getFirst(); // ОШИБКА!! Object cannot be converted to Person
```
Здесь `Pair` — это обобщённый класс, который, предположительно, должен работать с дженериками. Однако из-за стирания типов, когда вы используете `Pair` как необобщенный тип (тип `Pair` без параметров), метод `getFirst()` возвращает значение типа `Object`, а не `Person`. Из-за этого прямое присвоение `Person pers = emp.getFirst();` невозможно, так как `Object` не может быть автоматически преобразован в `Person` без явного приведения типа.
В вашем втором примере:
```java
Person pers = (Person)emp.getFirst();
```
Вы явно указываете компилятору, что вы ожидаете объект типа `Person`, и поэтому приводите `Object` к `Person` с помощью явного приведения.
### Почему это работает?
1. **Стирание типов**: Когда вы создаёте объект типа `Pair`, компилятор не знает, что `Pair` должен содержать значение типа `Person`. Он использует концепцию стирания типов, так что без параметризованного типа он рассматривает его как `Pair<Object>`.
2. **Автоматическое приведение**: В случае автоматического присвоения у вас нет информации о том, что `getFirst()` действительно вернёт `Person`. Компилятор видит это как `Object` и не может выполнить автоматическое приведение без явного указания, что вы ожидаете именно `Person`.
3. **Явное приведение**: Когда вы используете явное приведение, вы берёте на себя ответственность за то, что объект, к которому вы обращаетесь, действительно является `Person`. Это приводит к потенциальной ошибке во время выполнения, если данный объект не является экземпляром `Person`.
### Рекомендации
Чтобы избежать подобных ошибок, рекомендуется всегда использовать дженерики при работе с типизированными классами. Например, так:
```java
Pair<Person> emp = person;
emp.setFirst(new Person());
Person pers = emp.getFirst(); // Теперь это работает корректно
```
Таким образом, с использованием дженериков вы избегаете проблем, связанных со стиранием типов и получите типобезопасное окружение.