在不重新编译实现类的情况下更改接口

时间:2013-02-06 16:45:34

标签: java exception undefined-behavior throws

我有以下课程

public abstract interface X 
{
    public abstract void f() throws java.io.IOException;
}


public class Y implements X 
{
    public void f() throws java.io.IOException 
    {
        throw new java.ioIOException("Hello");
    }

    public static void main(String [] args)
    {
        X x = new Y();
        try
        {
            x.f();
        }
        catch (IOException e)
        {
            System.out.println("Caught");
        }
    }

}

现在我编译两个并获得X.classY.class

现在我更改X以删除投掷

public abstract interface X 
{
    public abstract void f();
}

显然,如果我重新编译X& Y,Y&#39的编译将失败

Y.java:4: f() in Y cannot implement f() in X; overridden method does not throw j
ava.io.IOException

然而,我只是重新编译X.java&保留我用旧的X.java编译的Y.class。

在这种情况下会发生什么 - 它是否定义明确?

或者它属于未定义的类别 - 即任何事情都可能发生?

是否有任何保证 - 例如,如果我在Windows下的Java 1.6.32下运行它,我可以依靠没有发生任何不良事件吗?

更新:更新了它,因为有些答案说我会在运行时获得IncompatibleClassChangeError。但我不是。

步骤

1)如上所述编译X.java和Y.java。跑Y。

输出:抓住

2)更改X.java以注释掉抛出。重新编译X.java。 不要重新编译Y.java。

运行Y

输出:抓住

我在Windows 7上运行java

编译器

javac 1.6.0_35

运行

java version "1.6.0_35"
Java(TM) SE Runtime Environment (build 1.6.0_35-b10)
Java HotSpot(TM) Client VM (build 20.10-b01, mixed mode, sharing)

1 个答案:

答案 0 :(得分:3)

现在这是Java的一个限制。创建一个扩展当前界面的子接口,如果确实需要,可以覆盖该方法而不会出现异常。一般来说,这被称为“二进制更改”,并且在代码运行时导致链接断开,并且在JLS中有明确定义(关于它的整个章节,JLS 13,您特别想要JLS 13.5 })。

编辑:经过进一步调查后发现我错了。来自JLS 13.4.21

  

对方法或构造函数的throws子句的更改不会破坏与预先存在的二进制文件的兼容性;这些子句仅在编译时检查。

但是,我仍然建议不要这样做,因为这意味着在运行时基本上可以取消选中已检查的异常。