I have the following classes
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");
}
}
}
Now I compile both and get X.class
and Y.class
.
Now I change X to remove the throws
public abstract interface X
{
public abstract void f();
}
Obviously if I recompile both X & Y, Y's compilation will fail
Y.java:4: f() in Y cannot implement f() in X; overridden method does not throw j
ava.io.IOException
However, what I if only recompile X.java & keep my Y.class which was compiled with the older X.java.
What happens in such a case - is it well defined?
Or does it fall under the category of undefined - i.e. anything can happen?
Are there any guarantees at all - i.e. if I am running it always under Java 1.6.32 under Windows, can I rely on nothing bad happening?
Update: Updated it because some answers said I would get a IncompatibleClassChangeError
at runtime. But I don't.
Steps
1) Compile both X.java and Y.java as given above. Run Y.
Output: Caught
2) Change X.java to comment out the throws. Recompile X.java. Do not recompile Y.java.
Run Y
Output: Caught
I am running java on Windows 7
Compiler
javac 1.6.0_35
Runtime
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)
An implemented class can of course have methods NOT declared in its interface . But is bound to implement methods which are declared in the interface unless it is declared abstract .
Press Ctrl+Shift+R and then choose Convert Abstract Class to Interface.
it's super easy to refer to one and figure which APIs are accessible for the clients to call. Lastly, it's better to practice using interfaces as a standard in a project than having to use it on a case by case bases (where you need multiple implementations). This ensures consistency in your project.
The short answer: An abstract class allows you to create functionality that subclasses can implement or override. An interface only allows you to define functionality, not implement it. And whereas a class can extend only one abstract class, it can take advantage of multiple interfaces.
This is a limitation in Java right now. Create a sub-interface that extends your current interface and override the method without the exception if you really need it. Generally speaking, this is called a "binary change" and results in broken linking when the code runs, and is well-defined in the JLS (there's an entire chapter on it, JLS 13, you specifically want JLS 13.5).
Edit: after further investigation, it turns out I was wrong. From JLS 13.4.21:
Changes to the
throws
clause of methods or constructors do not break compatibility with pre-existing binaries; these clauses are checked only at compile time.
However, I'd still recommend not doing this since it means a checked exception can essentially become unchecked at runtime.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With