proxy和UndeclaredThrowableException

时间:2018-04-25 10:30:17

标签: java

import java.io.EOFException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public class ProxyDemo {
    private final ClassLoader loader = getClass().getClassLoader();
    private final InvocationHandler throwHandler = new InvocationHandler() {
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            throw (Throwable) args[0];
        }
    };
    public interface ThrowsIOException {
        Object run(Throwable toThrow) throws IOException;
    }

    public interface ThrowsEOFException {
        Object run(Throwable toThrow) throws EOFException;
    }

    public void testDeclaredExceptionIntersectionIsSubtype() throws Exception {
        ThrowsIOException instance = (ThrowsIOException) Proxy.newProxyInstance(loader,
                new Class[] {ThrowsIOException.class, ThrowsEOFException.class}, throwHandler);
        try {
            instance.run(new EOFException());
        } catch (EOFException expected) {
        }
        try {
            instance.run(new IOException());
        } catch (UndeclaredThrowableException expected) {
        }
        try {
            instance.run(new Exception());
        } catch (UndeclaredThrowableException expected) {
        }
    }

    public static void main(String[] args) throws Throwable {
        ProxyDemo cl = new ProxyDemo();
        cl.testDeclaredExceptionIntersectionIsSubtype();
    }
}

我想问的是为什么当代码运行指令instance.run(new IOException())时,它会抛出UndeclaredThrowableException?

根据oracle的doc,在InvocationHandler的invoke方法中,如果此方法抛出了一个被检查的异常,该异常不能分配给接口方法的throws子句中声明的任何异常类型然后,代理实例上的方法调用将抛出包含此方法引发的异常的UndeclaredThrowableException。

在这种情况下,IOException对IOException是可以的,那么为什么它会抛出UndeclaredThrowableException而不是IOException?

1 个答案:

答案 0 :(得分:0)

因为当您从具有类似方法签名的两个接口创建代理时,这些方法签名将合并到一个签名,以满足两个接口的要求。

由于EOFException继承自IOException,因此方法签名将为

public Object run(Throwable toThrow) throws EOFException

您可以通过创建虚拟类来自行测试:

public class Test implements ThrowsIOException, ThrowsEOFException {
    @Override
    public Object run(Throwable toThrow) throws IOException // compiler error
    {
        return null;
    }
}

public class Test implements ThrowsIOException, ThrowsEOFException {
    @Override
    public Object run(Throwable toThrow) throws EOFException // valid
    {
        return null;
    }
}

这是因为您可以缩小抛出的异常(覆盖throws IOExceptionthrows EOFException很好),但是你无法扩大它(用throws EOFException覆盖throws IOException是非法的)。

因此,当您调用该方法并抛出EOFException时,它适合代理生成的方法签名(它被声明),一切都很好。但是当你抛出IOException时它不符合签名(它没有被声明),你得到UndeclaredThrowableException