有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java类newInstance传播已检查和未检查的异常这是真的吗?

据此:https://docs.oracle.com/javase/tutorial/reflect/member/ctorTrouble.html

Class.newInstance() Throws Unexpected Exception The ConstructorTroubleToo example shows an unresolvable problem in Class.newInstance(). Namely, it propagates any exception — checked or unchecked — thrown by the constructor.

This situation is unique to reflection. Normally, it is impossible to write code which ignores a checked exception because it would not compile. It is possible to wrap any exception thrown by a constructor by using Constructor.newInstance() rather than Class.newInstance().

下面我有一段代码,它没有捕获任何未检查的(RuntimeEcxeption/Error)异常,我对它们进行了注释并编译了它。那么传播在哪里呢?我编写的代码忽略了未检查的异常,这些异常被告知是不可能的。请告诉我上课有什么问题。newInstance()关于上述报价

try {
        Class<?> c = Class.forName("ConstructorTroubleToo");
        // Method propagetes any exception thrown by the constructor
        // (including checked exceptions).

        Object o = c.newInstance();

        // production code should handle these exceptions more gracefully
    } catch (ClassNotFoundException | 
            InstantiationException | 
            IllegalAccessException  x
           /*IllegalArgumentException | 
             SecurityException x*/ ) {
        x.printStackTrace();
    }

共 (2) 个答案

  1. # 1 楼答案

    Class.newInstance()确实会传播它调用的构造函数抛出的任何异常,无论是选中的还是未选中的。通过调用sun.misc.Unsafe.throwException()方法,以一种相当低调的方式进行传播。这个方法只是抛出你给它的异常,它是sun.misc.Unsafe类的一部分,该类包含用于Java中低级“不安全”操作的各种方法This article总结了其中一些方法

    JDK中有一个src.zip文件,其中包含一些标准Java平台类的源代码。特别是,您会在这个zip文件java/lang/Class.java中找到java.lang.Class的源代码。打开这个文件,查看其中的newInstance()方法。你会发现Class.newInstance()实际上使用Constructor.newInstance()来创建对象

    如果构造函数抛出异常,通过Constructor.newInstance()调用构造函数将把“真实”异常包装在InvocationTargetException中并抛出该异常。但是,Class.newInstance()并没有声明抛出InvocationTargetException,因此它会捕获Constructor.newInstance()抛出的InvocationTargetException,并使用Unsafe.throwException()抛出“real”异常

    之所以Class.newInstance()没有声明为抛出InvocationTargetException,是因为这个方法可以追溯到Java 1.0。InvocationTargetException和反射API的其余部分在1.1版中引入Java。在用Java 1.1编译Java 1.0代码时,将throws InvocationTargetException添加到Class.newInstance()会破坏向后兼容性

  2. # 2 楼答案

    传播意味着异常会消失,不像像反射方法一样包装到InvocationTargetException中

    实际上,编写忽略选中异常的代码并不是不可能的。从here

    考虑第一种情况
    public class Test {
        // No throws clause here
        public static void main(String[] args) {
            doThrow(new SQLException());
        }
    
        static void doThrow(Exception e) {
            Test.<RuntimeException> doThrow0(e);
        }
    
        @SuppressWarnings("unchecked")
        static <E extends Exception> 
        void doThrow0(Exception e) throws E {
            throw (E) e;
        }
    }
    

    JVM不区分检查和未检查的异常,有一些方法可以愚弄Java编译器