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

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

и

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.
}

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

4 ответов


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

все, что компилятор знает о T, - это его границы, которых он, вероятно, не имеет (кроме явно расширяющегося объекта и супер типа null). Так что эффективно приведение во время выполнения (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());
            ...

не будет никакого 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 () для возврата (Object) o и castBaseNumber () для возврата (Number) o;. Если вы пишите

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

вы получите ClassCastException, но не whithin cast-метод, но при назначении на 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

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


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

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

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


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