In Abstraction Functions & Rep Invariants we looked at CharSet, which represents a set of characters. Let’s implement Set for a particular type E. Generic interface, non-generic implementation. We can either write a non-generic implementation that replaces E with a specific type, or a generic implementation that keeps the placeholder. Suppose we want to implement the generic Set interface above. We still write specs at the level of our abstract model of sets. The story for these mutators is basically the same as for the observers. * e element to remove */ public void remove (E e) * If e is not found in the set, has no effect.
** Modifies this set by removing e, if found. * e element to add */ public void add (E e) example mutator operations /** Modifies this set by adding e to the set. These specs should apply to any valid implementation of the set ADT.
Notice how the specs are in terms of our abstract notion of a set it would be malformed to mention the details of any particular implementation of sets with particular private fields. * true iff this set contains e */ public boolean contains (E e)
* the number of elements in this set */ public int size () It needs its own generic type parameter, separate from the E we’re using in instance method specs.) // example observer operations /** Get size of the set. (We write at the front of this signature because make is a static method. The make operation is implemented as a static factory method.Īnd the compiler will understand that the new Set is a set of String objects. Using an interface instead of a class for the ADT, we can support multiple implementations: /** MyString represents an immutable sequence of characters. If you declare a subtype in Java - implementing an interface is our current focus - then you must ensure that the subtype’s spec is at least as strong as the supertype’s. When we declare a class that implements an interface, the Java compiler enforces part of this requirement automatically: for example, it ensures that every method in A appears in B, with a compatible type signature.Ĭlass B cannot implement interface A without implementing all of the methods declared in A.īut the compiler cannot check that we haven’t weakened the specification in other ways: strengthening the precondition on some inputs to a method, weakening a postcondition, weakening a guarantee that the interface abstract type advertises to clients. That means B is only a subtype of A if B’s specification is at least as strong as A’s specification. In terms of specifications: “every B satisfies the specification for A.” “B is a subtype of A” means “every B is an A.” Instead, those values are all ArrayList objects, or LinkedList objects, or objects of another class that implements List.Ī subtype is simply a subset of the supertype: ArrayList and LinkedList are subtypes of List. If we think about all possible List values, none of them are List objects: we cannot create instances of an interface. The Java List type is defined by an interface.
Java interface code#
Unfortunately, the compiler doesn’t check for us that the code adheres to the specs of those methods that are written in documentation comments. Java’s static type checking allows the compiler to catch many mistakes in implementing an ADT’s contract.įor instance, it is a compile-time error to omit one of the required methods, or to give a method the wrong return type. We explored two different representations for MyString, but we couldn’t have both representations for the ADT in the same program. In the MyString example from Abstract Data Types, MyString was a single class. When an abstract data type is represented just as a single class, without an interface, it’s harder to have multiple representations. The implementation is kept well and truly separated, in a different class altogether.Īnother advantage is that multiple different representations of the abstract data type can co-exist in the same program, as different classes implementing the interface. The client can’t create inadvertent dependencies on the ADT’s rep, because instance variables can’t be put in an interface at all. The interface is all a client programmer needs to read to understand the ADT. One advantage of this approach is that the interface specifies the contract for the client and nothing more. So one way to define an abstract data type in Java is as an interface, with its implementation as a class implementing that interface.
Java’s interface is a useful language mechanism for expressing an abstract data type.Īn interface in Java is a list of method signatures, but no method bodies.Ī class implements an interface if it declares the interface in its implements clause, and provides method bodies for all of the interface’s methods.