一個類所實現的兩個不同的介面中,有同名的方法,怎麼知道實現的是哪個介面中的方法
今天遇到一個問題,程式碼(後面各個版本的程式碼都是基於此程式碼進行變更的)如下:
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)則不適用。