Класс ClassCastException не выбрасывается внутри Java-дженериков

Ниже приведены первые генерируемые Java файлы, которые я когда-либо писал:

public class MyClass {

    public static <T> T castToAnotherType(Object param) {
        T ret = null;
        try {
            ret = (T) param;
        } catch (ClassCastException e) {
            System.out.print("Exception inside castToAnotherType()");
        }
        return ret;
    }

    public static void main(String[] args) {
        try {
            String obj = MyClass.castToAnotherType(new Object());
        } catch (ClassCastException e) {
            System.out.print("Exception outside castToAnotherType()");
        }
    }

}

Результатом является "Исключение вне castToAnotherType()". Почему исключение не встречается внутри общего метода?

Ответы

Ответ 1

T эффективно стирается во время компиляции. См. здесь:

На язык Java были введены обобщения для обеспечения более жесткого типа проверяет время компиляции и поддерживает универсальное программирование. к реализовать generics, компилятор Java применяет стирание типа к:

  • Заменить все параметры типа в родовых типах с их границами или Объект, если параметры типа не ограничены. Произведенный байт-код, поэтому содержит только обычные классы, интерфейсы и методы.
  • Вставьте тип при необходимости, чтобы сохранить безопасность типа. генерировать мостиковые методы для сохранения полиморфизма в расширенных общих типах.
  • Стирание стилей гарантирует, что новые классы не будут созданы для параметризованных типы; следовательно, дженерики не имеют накладных расходов во время выполнения.

Итак, ваш castToAnotherType получает T, стертый в ca. следующее:

public static Object castToAnotherType(Object param) {
    Object ret = null;
    try {
        ret = (Object) param;
    } catch (ClassCastException e) {
        System.out.print("Exception inside castToAnotherType()");
    }
    return ret;
}

Что явно не производит ClassCastException.

main(...) - это другая история, это приводит к следующему:

public static void main(String[] args) {
    try {
        String obj = (String) MyClass.castToAnotherType(new Object());
    } catch (ClassCastException e) {
        System.out.print("Exception outside castToAnotherType()");
    }
}

Что создает ClassCastException при попытке применить Object к String.

Пожалуйста, просмотрите Тип Erasure в учебнике Generics.

Ответ 2

Хорошо, поскольку компилятор стирает параметры типового типа, литье внутри метода по существу эквивалентно:

    Object ret = null;
    try {
        ret = (Object) param;
    } 
    ...

что не является проблемой, независимо от того, что вы передаете вашему методу (поскольку любой объект может быть перенесен в Object).

Однако, когда вы пытаетесь назначить этот объект в String, в вашем основном методе происходит ClassCastException, так как Object нельзя передать в String.

Ответ 3

Все обобщенные типы стираются в скомпилированном коде. Что касается скомпилированного кода, castToAnotherType просто возвращает Object. Тем не менее, ваш метод main пытается назначить его String, и он не является String, поэтому создается ClassCastException.

http://en.wikipedia.org/wiki/Type_erasure

Ответ 4

Это из-за стирания родового типа,

       T ret = null;
       try {
            ret = (T) param;
...

переводится компилятором в

       Object ret = null;
       try {
            ret = (T) param;
...