Как поймать ClassCastException?

Я пытаюсь поймать ClassCastException при десериализации объекта из xml.

So,

try {
    restoredItem = (T) decoder.readObject();
} catch (ClassCastException e){
    //don't need to crash at this point,
   //just let the user know that a wrong file has been passed.
}

И все же этого не будет, поскольку исключение не будет поймано. Что ты предлагаешь?


person yanchenko    schedule 09.10.2008    source источник
comment
Теги изменены для использования более распространенных тегов, связанных с исключениями.   -  person James Schek    schedule 09.10.2008


Ответы (4)


Код в вопросе должен дать вам предупреждение о непроверенном приведении. Слушайте -Xlint.

Все, что компилятор знает о T, — это его границы, которых у него, вероятно, нет (кроме явного расширения Object и super нулевого типа). Таким образом, эффективное приведение во время выполнения (Object) - не очень полезно.

Что вы можете сделать, так это передать экземпляр класса параметризованного типа (при условии, что он не является универсальным).

class MyReader<T> {
    private final Class<T> clazz;
    MyReader(Class<T> clazz) {
        if (clazz == null) {
            throw new NullPointerException();
        }
        this.clazz = clazz;
    }
    public T restore(String from) {
        ...
        try {
            restoredItem = clazz.cast(decoder.readObject());
            ...
            return restoredItem;
        } catch (ClassCastException exc) {
            ...
        }
    }
}

Или как общий метод:

    public <T> T restore(Class<T> clazz, String from) {
        ...
        try {
            restoredItem = clazz.cast(decoder.readObject());
            ...
person Tom Hawtin - tackline    schedule 09.10.2008

Не будет никакого ClassCastException, за исключением случаев, когда у вашего T есть какая-то база:

public class GenericsTest
{
    public static void main(String[] args)
    {
        System.out.println(cast(Integer.valueOf(0)));
        System.out.println(GenericsTest.<Long> cast(Integer.valueOf(0)));
        System.out.println(GenericsTest.<Long> cast("Hallo"));

        System.out.println(castBaseNumber(Integer.valueOf(0)));
        System.out.println(GenericsTest.<Long> castBaseNumber(Integer.valueOf(0)));
        System.out.println(GenericsTest.<Long> castBaseNumber("Hallo"));
    }

    private static <T extends Number> T castBaseNumber(Object o)
    {
        T t = (T)o;
        return t;
    }

    private static <T> T cast(Object o)
    {
        T t = (T)o;
        return t;
    }
}

В приведенном выше примере не будет ClassCastException в первых 5 вызовах cast и castBaseNumber. Только 6-й вызов генерирует исключение ClassCastException, потому что компилятор эффективно переводит cast() в return (Object) o и castBaseNumber() в return (Number)o;. Вэнн ты пишешь

String s = GenericsTest.<Long> cast("Hallo");

Вы получите ClassCastException, но не в методе приведения, а при назначении s.

Поэтому я думаю, что ваше «Т» — это не просто «Т», а «Т расширяет Что-то». Итак, вы можете проверить:

Object o = decoder.readObject();
if (o instanceof Something)
    restoredItem = (T) o;
else 
    // Error handling

Но это все равно приведет к ошибке позже, когда вы используете свой класс.

public Reader<T extends Number>{...}

Long l = new Reader<Long>("file.xml").getValue(); // there might be the ClassCastException

В этом случае может помочь только совет Тома.

person Tobias Schulte    schedule 09.10.2008

Ну, я не могу использовать оператор instanceof, так как метод параметризованный:

public T restore(String from){
...
restoredItem = (T) decoder.readObject();
...
}

И дженерики в Java только во время компиляции.

person yanchenko    schedule 09.10.2008
comment
Разве это не предполагает, что приведение к T на самом деле выполняется вызывающей стороной, а не самим методом? - person Chris Jester-Young; 09.10.2008
comment
Не уверен, что я вполне понимаю вашу точку зрения. В качестве быстрого взлома я возвращаю объект из restore(..) и выполняю проверку instanceof на более высоком уровне, без участия дженериков (поскольку они все равно не помогают). Все равно это некрасиво. - person yanchenko; 09.10.2008

Если вы не можете использовать instaceof, вы можете использовать метод isAssignableFrom в классе

person John Nilsson    schedule 09.10.2008