OCP Review 2.1 - Interfaces
Interfaces
- Can declare any number of methods
- Can be a marker interface (empty)
-
Can extend another interface
- The methods of an interface are implicitly abstract and public.
- The vairables of an interface are implicitly public, static, and final.
- Because the methods in an interface are implicitly public, if you try to assign a weaker access to the implemented method in a class, it won’t compile.
interface Marker {
}
interface A extends Marker {
}
Can’t
- a class can’t extend from an Interface
- can’t create an instance of an interface
- can’t contain instance / static blocks of code
Instance of
Marker m = new Marker() { // this is an anonymous class implementing Marker
};
System.out.println(m instanceof Marker);
We’re instantiating an Object
What does this print?
interface Marker {
}
interface A extends Marker {
}
// ...
A a = new A() {
};
System.out.println(a instanceof Marker);
System.out.println(a instanceof A);
true and true
Always public abstract
- we can use any form: the compiler treats them as always
public abstract
- in the interface definition we can omit
public abstract
. In the class implementation: NO
public interface Decompress {
public abstract void decompress();
abstract void decompress();
public void decompress();
void decompress();
}
Interface default implementations
interface Compress {
void compress();
}
interface CompressExtension extends Compress {
@Override
default void compress() {
System.out.println("I'm compressing");
}
}
class ZipCompressor implements CompressExtension {
}
Static members in an interface
interface I1 {
static void sm() {
System.out.println("Static method");
}
default void m1() {
System.out.println("I1::m1");
}
}
interface I2 extends I1 {
default void m1() {
I1.sm(); // we need to use the Interface I1 as sm is defined there
System.out.println("I2::m1");
}
}
class A implements I2, I1 {
@Override
public void m1() {
I1.sm();
}
}
Default implementations useful?
- to move common code from subclasses to small, focused interfaces instead of a big-ass abstract parent class
- f.i. interface
FilePersistable
: we can persist compressed files, or music, photos, etc. - the ability to be saved on file is a trait of many different classes
Problem 1
- two different (unrelated) interfaces provide the same default
class ZipCompressor implements CompressExtension, AnotherCompressExtension { // Error
}
interface CompressExtension extends Compress {
@Override
default void compress() {
System.out.println("I'm compressing in CompressExtension");
}
}
interface AnotherCompressExtension extends Compress {
@Override
default void compress() {
System.out.println("I'm compressing in AnotherCompressExtension");
}
}
Problem 1, simplified
interface I1 {
default void m1() {
System.out.println("I1::m1");
}
}
interface I2 {
default void m1() {
System.out.println("I2::m1");
}
}
class A implements I1, I2 { // COMPILATION ERROR
}
Problem 1, solved
interface I1 {
default void m1() {
System.out.println("I1::m1");
}
}
interface I2 extends I1 {
default void m1() {
System.out.println("I2::m1"); // this is used
}
}
class A implements I1, I2 {
}
Problem 2
- one interface provides a default impl
- another interface extends from it and provides a different default impl
class ZipCompressor implements AnotherCompressExtension {
}
interface CompressExtension extends Compress {
@Override
default void compress() {
System.out.println("I'm compressing in CompressExtension");
}
}
interface AnotherCompressExtension extends CompressExtension {
@Override
default void compress() {
System.out.println("I'm compressing in AnotherCompressExtension");
}
}
ZipCompressor zc = new ZipCompressor();
zc.compress(); // I'm compressing in AnotherCompressExtension
((CompressExtension)zc).compress(); // I'm compressing in AnotherCompressExtension
Uses of interfaces & default impl
- To quickly create mocks
- To let you compile and print warning while running