With abstractions, we add complexity and detail to programs. Interfaces are a way to isolate, and unify, a cross-class
abstraction.
In Java we use the "implements" keyword to specify that a class
adheres to an interface
. The interface
's methods are then required—the class
must implement them.
interface
This program introduces one interface
, called "Site." It implements this interface
in two classes, Ruby and Java. Those override
the display()
method.
display()
method the "override
" implementations are located at runtime and invoked.interface Site { public void display(); } class Ruby implements Site { public void display() { System.out.println("Ruby.display"); } } class Java implements Site { public void display() { System.out.println("Java.display"); } } public class Program { public static void main(String[] args) { // Use implementations through an interface. Site site = new Ruby(); site.display(); Site site2 = new Java(); site2.display(); } }Ruby.display Java.display
Collection
interface
Many interfaces (often the most-used ones) are implemented in the built-in Java libraries. The Collection
interface
, a generic one, is an example.
Collection
, we can act upon many classes, like ArrayList
and Vector
, with unified code.display()
method receives an ArrayList
and a Vector
but provides only one implementation.interface
code to compile.import java.util.ArrayList; import java.util.Collection; import java.util.Vector; public class Program { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); list.add(1); Vector<Integer> vec = new Vector<>(); vec.add(2); vec.add(3); // Treat the collections by their interface. display(list); display(vec); } static void display(Collection<Integer> col) { // Display size of collection. System.out.println(col.size()); } }1 2
A class
can implement multiple interfaces. Here we show a class
(called Unit) that implements two interfaces, Box and Cube.
interface
names with a comma. The "implements" keyword is not repeated.interface Box { public int area(boolean accurate); } interface Cube { public int volume(boolean accurate); } class Unit implements Box, Cube { public int area(boolean accurate) { if (accurate) { return 4; } else { return 1; } } public int volume(boolean accurate) { if (accurate) { return 100; } else { return 10; } } } public class Program { public static void main(String[] args) { // Create class and call methods. Unit unit = new Unit(); System.out.println(unit.area(true)); System.out.println(unit.volume(false)); } }4 10
interface
A variable can be "implicitly" cast to its interface
. But to convert from an interface
reference to a class
, we must use an explicit cast.
ArrayList
as a Collection
. Then we cast the Collection
interface
variable back to an ArrayList
.import java.util.ArrayList; import java.util.Collection; public class Program { public static void main(String[] args) { // Use Collection interface with ArrayList. Collection<String> coll = new ArrayList<>(); coll.add("cat"); // Cast Collection to ArrayList. ArrayList<String> list = (ArrayList<String>) coll; System.out.println(list.size()); } }1
interface
methodWhen a method may throw an exception, it must contain a "throws" declaration. An interface
method too must include "throws."
interface Coffee { public void brew(int size) throws Exception; } class MediumRoast implements Coffee { public void brew(int size) throws Exception { // Throw an exception if size is too big. if (size > 100) { throw new Exception("Too much coffee"); } } } public class Program { public static void main(String[] args) throws Exception { Coffee cup = new MediumRoast(); cup.brew(1000); } }Exception in thread "main" java.lang.Exception: Too much coffee at program.MediumRoast.brew(Program.java:12) at program.Program.main(Program.java:20)
HashMap
, interface
The HashMap
class
is a lookup structure. We can use an interface
as the value of a HashMap
. Then, we can store multiple object types safely within a single table.
CardboardBox
and PlasticBox
classes implement the Box interface
. We add instances of them to the HashMap
in main.get()
and access interface
references. We can use the interface
without determining the actual class
types.import java.util.HashMap; interface Box { public void test(); } class CardboardBox implements Box { public void test() { System.out.println("cardboard"); } } class PlasticBox implements Box { public void test() { System.out.println("plastic"); } } public class Program { public static void main(String[] args) { HashMap<String, Box> map = new HashMap<>(); // ... Put new class instances in HashMap. map.put("ship-100", new CardboardBox()); map.put("pack-200", new PlasticBox()); // ... Get interface reference from the HashMap. // Call test on it. Box b = map.get("ship-100"); if (b != null) { b.test(); } } }cardboard
interface
Consider this program: it tests a method call through an interface
(called Tester) against a direct method call. The direct call is faster.
interface
reference (the interface
is called Tester).class
method directly on the Perl class
. No interface
is used for this version of the code.test()
is about three times faster than an interface
call to the same method.interface Tester { public void test(int value) throws Exception; } class Perl implements Tester { public void test(int value) throws Exception { // Some useless logic. if (value < 0) { throw new Exception(); } } } public class Program { public static void main(String[] args) throws Exception { Tester test = new Perl(); Perl perl = (Perl) test; long t1 = System.currentTimeMillis(); // ... Version 1: call interface method. for (int i = 0; i < 10000000; i++) { test.test(i); } long t2 = System.currentTimeMillis(); // ... Version 2: call class method. for (int i = 0; i < 10000000; i++) { perl.test(i); } long t3 = System.currentTimeMillis(); // ... Times. System.out.println(t2 - t1); System.out.println(t3 - t2); } }27 ms, Interface method call 8 ms, Non-interface method call
In Java, interfaces have tradeoffs. They unify common functionality throughout a program—throughout many programs. But they can reduce performance.