z
Interface (computing): In computing, an interface is a shared boundary across which two or more separate components of a computer system exchange information. The exchange can be between software, computer hardware, peripheral devices, humans, and combinations of these.
Interface (object-oriented programming)
In object-oriented programming, an interface is a data type that acts as an abstraction of a class. It describes a set of method signatures, the implementations of which may be provided by multiple classes that are otherwise not necessarily related to each other. A class which provides the methods listed in a protocol is said to implement the interface.[1]
If objects are fully encapsulated then the interface is the only way in which they may be accessed by other objects. For example, in Java, the Comparable interface specifies a
method compareTo() which implementing classes must implement. This means that a sorting method, for example, can sort a collection of any objects of types which implement
the Comparable interface, without having to know anything about the inner nature of the class (except that two of these objects can be compared by means of compareTo()).
An interface in the Java programming language is an abstract type that is used to declare a behavior that classes must implement. Interfaces are declared using the interface keyword, and may only contain method signature and constant declarations (variable declarations that are declared to be both static and final). All methods of an Interface do not contain implementation (method bodies) as of all versions below Java 8.
Interfaces cannot be instantiated, but rather are implemented. A class that implements an interface must implement all of the methods described in the interface, (or be an abstract class). Object references in Java may be specified to be of an interface type; in each case, they must either be null, or be bound to an object that implements the interface.
(One benefit of using interfaces is that they simulate multiple inheritance. All classes in Java must have exactly one base class, the only exception being java.lang.Object (the root class of the Java type system); multiple inheritance of classes is not allowed. However, an interface may inherit multiple interfaces and a class may implement multiple interfaces.)
class SSNum {
…
public int getArea() {…}
public int getGroup() {…}
public int getSerial() {…}
public String toString() {…}
…
}
String, complete with the separating '-'s.
toString.
class SSNum {
SSNum(String ssnum) {this.ssnum = ssnum;}
public int getArea() {return Integer.parseInt(ssnum.substring(0, 3));}
public int getGroup() {return Integer.parseInt(ssnum.substring(4, 6));}
public int getSerial() {return Integer.parseInt(ssnum.substring(7));}
public String toString() {return ssnum;}
private String ssnum;
}
Integer.valueOf is an acceptable alternative to parseInt
Integer, the latter an int, but with autoboxing, the
result is basically the same (at least here)
class SSNumApp {
public static void main(String [] args) {
SSNum sSNum = new SSNum("123-45-6789");
System.out.println(sSNum);
System.out.println(sSNum.getArea());
System.out.println(sSNum.getGroup());
System.out.println(sSNum.getSerial());
}
}
int
(e.g., it takes up less space than the 11-byte string).
class SSNum {
SSNum(String ssnum) {
this.ssnum = Integer.parseInt(ssnum.substring(0, 3)) * 1000000 + Integer.parseInt(ssnum.substring(4, 6)) * 10000 + Integer.parseInt(ssnum.substring(7));}
public int getArea() {return ssnum / 1000000;}
public int getGroup() {return (ssnum / 10000) % 100;}
public int getSerial() {return ssnum % 10000;}
public String toString() {return String.format("%03d-%02d-%04d", getArea(), getGroup(), getSerial());}
private int ssnum;
}
toString
toString has to transform the internal representation into a String
toString which takes the internal representation and transforms it into
a string suitable for human viewing.
StringSSNum. When we shift to an int-based
implementation, that name would no longer be appropriate.
StringSSNum, the app would read:
StringSSNum sSNum = new StringSSNum("123-45-6789");
would have to be changed to:
IntSSNum sSNum = new IntSSNum("123-45-6789");
(note that I've left the variable name the same 'vanilla' name (ssNum); changing it from stringSSNum
to intSSNum just introduces even more name changing.)
asInt method in our StringSSNum
implementation:
int asInt() {…}
StringSSNum may have thought it a good idea to have such a method; and
furthermore, made heavy use of this method
IntSSNum) — which justifiably would not have
such a method, the application code would break wherever that method was called.
IntSSNum) but that then involves making changes
to our tested class.
Container classe: tatic fixed-sized, dynamic fixes-sized and growableo, and methods
to return their capacities: the growable really does not need any such method (the capacity changes as needed), the first will always return the same value;
it's only the dynamic fixed that truly calls for a getCapacity method.
Java's interface construct allows us to specify a set of behavior in the form of method specifications.
The interface forms a data type, i.e., a specification of a set of values and the valid operations
on those values. Any class that implements the interface is said to belong to the data type of the interface,
i.e., we say an object of the implementation class is-a object of the interface type as well, and can appear in any context
a reference variable of the interface type may appear.
Here is an interface for our social security number:
interface SSNum {
int getArea();
int getGroup();
int getSerial();
}
class StringSSNum implements SSNum {
StringSSNum(String ssnum) {this.ssnum = ssnum;}
public int getArea() {return Integer.parseInt(ssnum.substring(0, 3));}
public int getGroup() {return Integer.parseInt(ssnum.substring(4, 6));}
public int getSerial() {return Integer.parseInt(ssnum.substring(7));}
public String toString() {return ssnum;}
private String ssnum;
}
class IntSSNum implements SSNum {
IntSSNum(String ssnum) {this.ssnum = Integer.parseInt(ssnum.substring(0, 3)) * 1000000 +
Integer.parseInt(ssnum.substring(4, 6)) * 10000 + Integer.parseInt(ssnum.substring(7));}
public int getArea() {return ssnum / 1000000;}
public int getGroup() {return (ssnum / 10000) % 100;}
public int getSerial() {return ssnum % 10000;}
public String toString() {return String.format("%03d-%02d-%04d", getArea(), getGroup(), getSerial());}
private int ssnum;
}
The above two classes are each said to be an implementing class or simply implementation of the interface
class StringSSNumApp {
public static void main(String [] args) {
StringSSNum stringSSNum = new StringSSNum("123-45-6789");
System.out.println(stringSSNum);
System.out.println(stringSSNum.getArea());
System.out.println(stringSSNum.getGroup());
System.out.println(stringSSNum.getSerial());
}
}
class IntSSNumApp {
public static void main(String [] args) {
IntSSNum intSSNum = new IntSSNum("123-45-6789");
System.out.println(intSSNum);
System.out.println(intSSNum.getArea());
System.out.println(intSSNum.getGroup());
System.out.println(intSSNum.getSerial());
}
}
StringSSNum vs IntSSNum). This is used in
IntSSNum intSSNum).
new StringSSNum(…);).
stringSSNum vs intSSNum)
ssNum
in both apps.
ssNum.
IntSSNum one must write new IntSSNum,
(clearly one wouldn't write new StringSSNum and you can't create an SSNum (it's an interface, not a concrete class).
newIntSSNum or new String SSNum), we pass the object in as a parameter,
allowing the caller to be responsible for which to use.
SSNum by virtue of their
having implemented the SSNum interface.
SSNum app, we are also making sure we are only using those methods
of the interface, i.e., we are indeed 'programming to the interface'.
class SSNumApp {
public static void demo(SSNum sSNum) {
System.out.println(sSNum);
System.out.println(sSNum.getArea());
System.out.println(sSNum.getGroup());
System.out.println(sSNum.getSerial());
}
}
class StringSSNumApp {
public static void main(String [] args) {
SSNumApp.demo(new StringSSNum("123-45-6789"));
}
}
class IntSSNumApp {
public static void main(String [] args) {
SSNumApp.demo(new IntSSNum("123-45-6789"));
}
}
interface Counter {
void up();
void down();
int getVal();
}
public class UnboundedCounter implements Counter {
UnboundedCounter() {val = 0;}
public void up() {val++;}
public void down() {val--;}
public int getVal() {return val;}
public String toString() {return "A counter with value " + val;}
private int val = 0;
}
public class UpperBoundedCounter implements Counter {
UpperBoundedCounter(int limit) {
val = 0;
this.limit = limit;
}
public void up() {if (val < limit) val++;}
public void down() {val--;}
public int getVal() {return val;}
int getLimit() {return limit;}
public String toString() {return "A upper-bounded counter with value " + val + " and limit " + limit;}
private int val = 0;
private int limit;
}
public class App {
public static void main(String [] args) {
doIt(new UnboundedCounter());
doIt(new UpperBoundedCounter(10));
}
static void doIt(Counter c) {
System.out.println(c.getClass().getName());
System.out.println("Initially: " + c);
for (int i = 1; i <= 20; i++)
c.up();
System.out.println("After 20 up's: " + c);
for (int i = 1; i <= 3; i++)
c.down();
System.out.println("After 3 down's: " + c);
System.out.println(); //---------
}
}
UnboundedCounter as well as the UpperBoundedCounter
can be sent as arguments to the Counter parameter of doIt
because they both implement the Counter interface and the thus considered
Counter objects
UnboundedCounter is-a Counter
(same for UpperBoundedCounter).
UpperBoundCounter's getLimit method in doIt as it is not a method of the interface.
Counter reference back to a UpperBoundedCounter. This would then permit
getLimit to be called.
static void doIt(Counter c) {
…
UpperBoundedCounter ubc = (UpperBoundedCounter)c;
System.out.println(ubc.getLimit();
…
}
UpperBoundedCounter argument, it would cause a ClassCastException
when doIt was invoked with the UnboundedCounter argument.
UpperBoundedCounter
objects were sent to doIt; however it requires an explicit cast to force the programmer to pay attention to the fact
that this may fail.
Counter
/ \
UnboundedCounter UpperBoundedCounter
then we have to following:
UnboundedCounter and UpperBoundedCounter can always be upcast to Counter and this requires
no explicit cast:
UnboundedCounter uc = new UnboundedCounter(); Counter c = uc; // no cast, will always work
UpperBoundedCounter ubc = new UpperBoundedCounter(10); Counter c = ubc; // no cast, will always work
UnboundedCounter and UpperBoundedCounter can never be cast to each other
UnboundedCounter uc = new UnboundedCounter(); UpperBoundedCounter ubc = uc; // compiler error
UpperBoundedCounter ubc = new UpperBoundedCounter(10); UnboundedCounter uc = new ubc; // compiler error
Counter can be downcast to both UnboundedCounter and UpperBoundedCounter; however an explicit cast is required as
a ClassCastException may occur (if the reference is not to an object of the type being cast to).
Counter c = new UnboundedCounter(); // this is an upcast! UnboundedCounter uc = (UnboundedCounter)c; // ok &helip;creferenced anUnboundedCounterobject
Counter c = new UnboundedCounter(); // this is an upcast! UpperBoundedCounter ubc = (UpperBoundedCounter)c; //ClassCastException; attempting to cast a reference to anUnboundedCounterobject to aUpperBounderCounterreference
interface Sortable {
int compareTo(Sortable other);
}
class SortableInt implements Sortable {
SortableInt(int i) {this.i = i;}
public int compareTo(Sortable other) {
return Integer.compare(i, ((SortableInt)other).i);
}
public String toString() {return "SortableInt " + i;}
private int i;
}
class SortableString implements Sortable {
SortableString(String s) {this.s = s;}
public int compareTo(Sortable other) {
return (s).compareTo(((SortableString)other).s);
}
public String toString() {return "SortableString " + s;}
private String s;
}
import java.util.*;
class Sorter {
public static void main(String [] args) {
Random r = new Random(12345);
SortableInt [] sortableInts = new SortableInt[10];
for (int i = 0; i < sortableInts.length; i++)
sortableInts[i] = new SortableInt(r.nextInt(1000));
System.out.println( "sortableInts (before sort): " + toString(sortableInts));
sort(sortableInts);
System.out.println( "sortableInts (after sort): " + toString(sortableInts));
System.out.println();
SortableString [] sortableStrings = new SortableString[8];
for (int i = 0; i < sortableStrings.length; i++)
sortableStrings[i] = new SortableString("Str" + r.nextInt(1000));
System.out.println( "sortableStrings (before sort): " + toString(sortableStrings));
sort(sortableStrings);
System.out.println( "sortableStrings (after sort): " + toString(sortableStrings));
}
static String toString(Sortable [] arr) {
String result = "{";
for (int i = 0; i < arr.length; i++)
result += arr[i] + (i < arr.length-1 ? ", " : "");
return result + "}";
}
static void sort(Sortable [] arr) {
for (int last = arr.length-1; last >= 0; last--)
for (int i = 0; i < last; i++)
if (arr[i].compareTo(arr[i+1]) > 0) {
Sortable temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
The output:
sortableInts (before sort): {SortableInt 251, SortableInt 80, SortableInt 241, SortableInt 828, SortableInt 55, SortableInt 84, SortableInt 375, SortableInt 802, SortableInt 501, SortableInt 389}
sortableInts (after sort): {SortableInt 55, SortableInt 80, SortableInt 84, SortableInt 241, SortableInt 251, SortableInt 375, SortableInt 389, SortableInt 501, SortableInt 802, SortableInt 828}
sortableStrings (before sort): {SortableString Str517, SortableString Str942, SortableString Str390, SortableString Str806, SortableString Str12, SortableString Str384, SortableString Str787, SortableString Str303}
sortableStrings (after sort): {SortableString Str12, SortableString Str303, SortableString Str384, SortableString Str390, SortableString Str517, SortableString Str787, SortableString Str806, SortableString Str942}
SortableInt objects are Sortable objects as well, but not all
Sortable objects are SortableInt objects (some of them could be SortableStrings)
doIt
compareTo uses arr[i] as the receiver and arr[i+1] as the argument (sent to parameter other).
The parameter is clearly declared in the compareTo method as Sortable; the question is which compareTo method is called?
new.
Sorter:
import java.util.*;
class Sorter2 {
public static void main(String [] args) {
Random r = new Random(12345);
Sortable [] sortables = new Sortable[10];
for (int i = 0; i < sortables.length; i++)
sortables[i] = new SortableInt(r.nextInt(1000));
System.out.println( "sortables (before sort): " + toString(sortables));
sort(sortables);
System.out.println( "sortables (after sort): " + toString(sortables));
System.out.println();
}
static String toString(Sortable [] arr) {
String result = "{";
for (int i = 0; i < arr.length; i++)
result += arr[i] + (i < arr.length-1 ? ", " : "");
return result + "}";
}
static void sort(Sortable [] arr) {
for (int last = arr.length-1; last >= 0; last--)
for (int i = 0; i < last; i++)
if (arr[i].compareTo(arr[i+1]) > 0) {
Sortable temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
}
One final note: the Sortable interface exists in Java as the Comparable interface and is the basis for allowing
sorting of classes regardless of their behavior — as long as they implement Comparable
Collection Interface
interface Collection {
boolean add(int value);
boolean remove(int value);
int size();
boolean isEmpty();
}
class Set implements Collection {
public boolean add(int value) {
if (find(value) != -1) return false;
values[size] = value;
size++;
return true;
}
public boolean remove(int value) {
int pos = find(value);
if (pos == -1) return false;
shiftLeft(pos);
size--;
return true;
}
public int size() {return size;}
public boolean isEmpty() {return size() == 0;}
public String toString() {
String result = "{";
for (int i = 0; i < size; i++)
result += values[i] + (i < size-1 ? ", " : "");
return result + "}";
}
private int find(int value) {
for (int i = 0; i < size; i++)
if (values[i] == value) return i;
return -1;
}
private void shiftLeft(int pos) {
for (int i = pos; i < size-1; i++)
values[i] = values[i+1];
}
private static final int CAPACITY = 100;
private int [] values = new int[CAPACITY];
private int size = 0;
}
class Vector implements Collection {
public boolean add(int value) {
values[size] = value;
size++;
return true;
}
public boolean add(int pos, int value) {
shiftRight(pos);
values[pos] = value;
size++;
return true;
}
public boolean remove(int value) {
int pos = find(value);
if (pos == -1) return false;
shiftLeft(pos);
size--;
return true;
}
public int removeAt(int pos) {
int hold = values[pos];
shiftLeft(pos);
size--;
return hold;
}
public int get(int pos) {
return values[pos];
}
public void set(int pos, int value) {
values[pos] = value;
}
public int size() {return size;}
public boolean isEmpty() {return size() == 0;}
public String toString() {
String result = "{";
for (int i = 0; i < size; i++)
result += values[i] + (i < size-1 ? ", " : "");
return result + "}";
}
private int find(int value) {
for (int i = 0; i < size; i++)
if (values[i] == value) return i;
return -1;
}
private void shiftLeft(int pos) {
for (int i = pos; i < size-1; i++)
values[i] = values[i+1];
}
private void shiftRight(int pos) {
for (int i = size; i > pos; i--)
values[i] = values[i-1];
}
private static final int CAPACITY = 100;
private int [] values = new int[CAPACITY];
private int size = 0;
}
import java.util.*;
class CollectionApp {
public static void main(String [] args) {
doIt(new Set());
System.out.println();
System.out.println();
doIt(new Vector());
}
static void doIt(Collection c) {
System.out.println("===== " + c.getClass().getName());
Random r = new Random(12345);
System.out.println("--- Adding");
for (int i = 0; i < 20; i++) {
int num = r.nextInt(10);
System.out.println(num + " -> " + c.add(num) + " " + c);
}
System.out.println();
System.out.println("--- Removing");
while (!c.isEmpty()) {
int num = r.nextInt(10);
System.out.println(num + " -> " + c.remove(num) + " " + c);
}
}
}
===== Set
--- Adding
1 -> true {1}
0 -> true {1, 0}
1 -> false {1, 0}
8 -> true {1, 0, 8}
5 -> true {1, 0, 8, 5}
4 -> true {1, 0, 8, 5, 4}
5 -> false {1, 0, 8, 5, 4}
…
3 -> true {1, 0, 8, 5, 4, 2, 9, 7, 6, 3}
2 -> false {1, 0, 8, 5, 4, 2, 9, 7, 6, 3}
5 -> false {1, 0, 8, 5, 4, 2, 9, 7, 6, 3}
--- Removing
1 -> true {0, 8, 5, 4, 2, 9, 7, 6, 3}
1 -> false {0, 8, 5, 4, 2, 9, 7, 6, 3}
2 -> true {0, 8, 5, 4, 9, 7, 6, 3}
6 -> true {0, 8, 5, 4, 9, 7, 3}
8 -> true {0, 5, 4, 9, 7, 3}
1 -> false {0, 5, 4, 9, 7, 3}
5 -> true {0, 4, 9, 7, 3}
hellip;
2 -> false {0, 4}
1 -> false {0, 4}
0 -> true {4}
8 -> false {4}
6 -> false {4}
2 -> false {4}
9 -> false {4}
8 -> false {4}
8 -> false {4}
0 -> false {4}
2 -> false {4}
1 -> false {4}
0 -> false {4}
8 -> false {4}
4 -> true {}
===== Vector
--- Adding
1 -> true {1}
0 -> true {1, 0}
1 -> true {1, 0, 1}
8 -> true {1, 0, 1, 8}
5 -> true {1, 0, 1, 8, 5}
4 -> true {1, 0, 1, 8, 5, 4}
5 -> true {1, 0, 1, 8, 5, 4, 5}
…
4 -> true {1, 0, 1, 8, 5, 4, 5, 2, 1, 9, 7, 2, 0, 6, 2, 4}
7 -> true {1, 0, 1, 8, 5, 4, 5, 2, 1, 9, 7, 2, 0, 6, 2, 4, 7}
3 -> true {1, 0, 1, 8, 5, 4, 5, 2, 1, 9, 7, 2, 0, 6, 2, 4, 7, 3}
2 -> true {1, 0, 1, 8, 5, 4, 5, 2, 1, 9, 7, 2, 0, 6, 2, 4, 7, 3, 2}
5 -> true {1, 0, 1, 8, 5, 4, 5, 2, 1, 9, 7, 2, 0, 6, 2, 4, 7, 3, 2, 5}
--- Removing
1 -> true {0, 1, 8, 5, 4, 5, 2, 1, 9, 7, 2, 0, 6, 2, 4, 7, 3, 2, 5}
1 -> true {0, 8, 5, 4, 5, 2, 1, 9, 7, 2, 0, 6, 2, 4, 7, 3, 2, 5}
2 -> true {0, 8, 5, 4, 5, 1, 9, 7, 2, 0, 6, 2, 4, 7, 3, 2, 5}
6 -> true {0, 8, 5, 4, 5, 1, 9, 7, 2, 0, 2, 4, 7, 3, 2, 5}
8 -> true {0, 5, 4, 5, 1, 9, 7, 2, 0, 2, 4, 7, 3, 2, 5}
1 -> true {0, 5, 4, 5, 9, 7, 2, 0, 2, 4, 7, 3, 2, 5}
5 -> true {0, 4, 5, 9, 7, 2, 0, 2, 4, 7, 3, 2, 5}
3 -> true {0, 4, 5, 9, 7, 2, 0, 2, 4, 7, 2, 5}
1 -> false {0, 4, 5, 9, 7, 2, 0, 2, 4, 7, 2, 5}
9 -> true {0, 4, 5, 7, 2, 0, 2, 4, 7, 2, 5}
9 -> false {0, 4, 5, 7, 2, 0, 2, 4, 7, 2, 5}
7 -> true {0, 4, 5, 2, 0, 2, 4, 7, 2, 5}
…
8 -> false {4, 4, 7}
4 -> true {4, 7}
4 -> true {7}
4 -> false {7}
8 -> false {7}
0 -> false {7}
9 -> false {7}
8 -> false {7}
5 -> false {7}
4 -> false {7}
7 -> true {}
List Interface
interface List extends Collection {
int get(int index);
void set(int index, int value);
boolean add(int index, int value);
int removeAt(int index);
}
class Vector implements List {
…
}
import java.util.*;
class ListApp {
public static void main(String [] args) {
doIt(new Vector());
}
static void doIt(List l) {
System.out.println("===== " + l.getClass().getName());
System.out.println();
System.out.println("Calling CollectionApp.doIt");
CollectionApp.doIt(l);
System.out.println();
System.out.println();
System.out.println("Perfoming ListApp.doIt");
Random r = new Random(12345);
System.out.println("--- Indexed Adding");
for (int i = 0; i < 20; i++) {
int pos = r.nextInt(l.size()+1);
int num = r.nextInt(10);
System.out.println(num + " @" + pos + " -> " + l.add(pos, num) + " " + l);
}
System.out.println();
System.out.println("--- Getting");
for (int i = 0; i < l.size(); i++)
System.out.println("@" + i + " -> " + l.get(i));
System.out.println();
System.out.println("--- Setting");
for (int i = 0; i < l.size(); i++) {
int num = r.nextInt(10);
l.set(i, num);
System.out.println(num + " @" + i + " -> " + l);
}
System.out.println();
System.out.println("--- Indexed Removing");
while (!l.isEmpty()) {
int pos = r.nextInt(l.size());
System.out.println("@" + pos + " -> " + l.removeAt(pos) + " " + l);
}
}
}
List inherits from Collection, we can leverage the CollectioApp
logic
Iterable
Runnable