Java泛型引发异常抛出位置异常,自定义异常未生效问题咨询
你的问题核心是Java泛型的类型擦除机制导致的未检查转换,具体拆解如下:
1. 运行时泛型类型被擦除
Java的泛型是编译期语法糖,运行时所有泛型参数都会被擦除为Object。所以你的getObject方法里的(T) in.readObject(),在运行时实际是(Object) in.readObject()——这个转换不会触发任何类型检查,因为readObject()本身返回的就是Object,转成Object完全合法,自然不会抛出ClassCastException。
2. 真正的类型检查发生在调用方
当decode方法返回getObject的结果时,编译器会根据调用decode时的上下文(比如你把返回值赋值给某个具体类型变量,或者显式指定了泛型参数),在return getObject(...)这一行插入隐式的类型检查指令(checkcast)。只有这时候JVM才会去验证返回的对象是否符合T的实际类型,不匹配就抛出ClassCastException。而这个异常发生在getObject方法之外,自然不会被getObject里的try-catch捕获,你的自定义ObjectEncoderException也就永远触发不了。
验证方式(看字节码)
你可以用javap -c反编译字节码,会看到:
getObject方法里没有checkcast指令,只有简单的类型转换标识decode方法的return语句处会有checkcast指令,这才是抛出异常的地方
解决办法(让异常在内部被捕获)
要让类型检查发生在getObject内部,从而被try-catch捕获,别用泛型强制转换,改用Class.cast()方法做显式检查:
private <T> T getObject(byte[] toObject, Class<T> clazz) { try (ByteArrayInputStream bis = new ByteArrayInputStream(toObject); ObjectInput in = new ObjectInputStream(bis)) { return clazz.cast(in.readObject()); // 这里会做显式类型检查 } catch (Exception e) { throw new ObjectEncoderException(e); } }
这样当类型不匹配时,clazz.cast()会直接抛出ClassCastException,这个异常会被try-catch捕获,然后包装成你的自定义异常抛出。
内容的提问来源于stack exchange,提问作者Serhii

