今天遇到一个问题,代码(后面各个版本的代码都是基于此代码进行变更的)如下:
public interface Type1 { void f(); void f1(); void f11(); }
public interface Type2 { void f(); void f2(); void f22(); }
public class IFTest implements Type1, Type2 { @Override public void f2() { } @Override public void f22() { } @Override public void f() { System.out.println("method f"); } @Override public void f1() { } @Override public void f11() { } }
当时有过这样一个疑问:Type1和Type2中都有一个f()方法,那么IFTest中的f()方法到底实现的是Type1中的f()呢,还是Type2中的f()呢?其实,这种疑问是多余的,因为IFTest中的f()既是Type1中的f()也是Type2中的f()。因为既然IFTest这个类没有发生编译错误,那就说明它既实现Type1也实现了Type2,也就是说Type1中的f()与Type2中的f()在IFTest中是相安无事的。可以通过以下的JUnit测试用例来看一下:
public class IFTestTest { /** * Test method for {@link com.rainbow.util.demo.iftest.IFTest#f()}. * * @throws IOException */ @Test public void testF() throws Exception { Type1 ift = new IFTest(); Type2 ift2 = new IFTest(); ift.f(); ift2.f(); } }
它的打印结果中是:
method f method f
-------------------------------------------分隔线-------------------------------------------
上面这个问题的变种:
将Type1中的f()的返回值修改为int,将Type2中的f()的返回值修改为boolean,那么又会是什么结果呢?
public interface Type1 { int f(); void f1(); void f11(); }
public interface Type2 { boolean f(); void f2(); void f22(); }
public class IFTest implements Type1, Type2 { @Override public void f2() { } @Override public void f22() { } @Override public void f() { System.out.println("method f"); } @Override public void f1() { } @Override public void f11() { } }
在我意料之中,此时IFTest这个类在编译时就报错了, 在Eclipse中,将鼠标移至IFTest的f()上,查看一下,出错消息为:
The return type is incompatible with Type2.f()
这也就说明了,如果两个接口有同名的方法,但是它们的返回值不一样,那么,是无法用一个类同时来实现这两个接口的。
-------------------------------------------分隔线-------------------------------------------
上面这个问题的变种:
将Type1中的f()声明为抛出IOException,将Type2中的f()声明为抛出CloneNotSupportedException,那么又会是什么结果呢?
public interface Type1 { void f() throws IOException; void f1(); void f11(); }
public interface Type2 { void f() throws CloneNotSupportedException; void f2(); void f22(); }
public class IFTest implements Type1, Type2 { @Override public void f2() { } @Override public void f22() { } @Override public void f() throws CloneNotSupportedException, IOException { System.out.println("method f"); } @Override public void f1() { } @Override public void f11() { } }
我本来以为上面的IFTest是可以正常通过编译的。但是,结果却是残酷的,在Eclipse中可以查看到出错消息为:
Exception IOException is not compatible with throws clause in Type2.f()
对于这个现象,在《Java 解惑》的迷题37中,有如下的描述:
一个方法可以抛出的受检查异常集合是它所适用的所有类型的声明要抛出的受检查异常集合的交集,而不是合集。
也就是说,在IFTest的f()上声明的异常只能是在Type1和Type2的f()上都声明过的异常。因为此示例中,Type1抛出的是IOException,而Type2抛出的是CloneNotSupportedException,即Type1与Type2的f()所抛出的异常是没有交集的,因此,IFTest的f()是无法声明抛出任何异常的。
如果像下面这样修改一下:
public interface Type1 { void f() throws IOException, CloneNotSupportedException; void f1(); void f11(); }
public interface Type2 { void f() throws CloneNotSupportedException; void f2(); void f22(); }
那么,就可以将IFTest的f()修改为声明抛出 ClonseNotSupportedException了,因为这个时候Type1和Type2的f()都声明了 ClonseNotSupportedException,这个异常就是它们抛出的异常的交集:
public class IFTest implements Type1, Type2 { @Override public void f2() { } @Override public void f22() { } @Override public void f() throws CloneNotSupportedException { System.out.println("method f"); } @Override public void f1() { } @Override public void f11() { } }
当然,对于这一点,一定要注意一下,仅仅是针对 受检查的异常(Checked Exception) 才起作用的,对于非受检查的异常(Unchecked Exception)则不适用。
关于什么是 Checked Exception ,什么是 Unchecked Exception,可以查看http://czj4451.iteye.com/blog/1851825