6.1 Generic methods
Generic method: a method definition having a special type parameter that may be used in place of types in the methods
Type parameter: specified inside angle brakets (<>) before the method’s return type, represents a type that can be used in the method for any method paramters, local variables, or return type
public static <T> int findIndex(T[] arr, T target) {
for (int i = 0; i < array.length; i++) {
if (array[i].equals(target)) {
return i;
}
}
return -1;
}
public static void main(String[] args) {
String[] words = {"apple", "banana", "orange"};
Integer[] nums = {10, 20, 30};
findIndex(words, "banana");
findIndex(nums, 30);
}NOTE: Java does not implicitly convert a primitive array to an array of wrapper objects
A programmer may optionally call a generic method with type arguments to explicitly indicate the types to use in place of a method type parameter
NOTE: type parameters cannot represent primitive types
public static <T, U> void printArrays(T[] arr1, U[] arr2) {
if (arr1.length != arr2.length) return;
for (int i = 0; i < array1.length; i++) {
System.out.println(arr1[i] + ", " + arr2[i]);
}
}
public static void main(String[] args) {
String[] items = {"bag", "cane", "book"};
Integer[] prices = {100, 300, 50};
printArrays(items, prices);
}6.2 Generic methods and type bounds
Type erasure: the compiler’s replacement of type parameters with a common base type
NOTE: if T does not explicitly specify a base type, its defaults to Object
NOTE: every array in Java has a final member named length
Common Object class methods:
.equals(): returns true if the other object equals
.toString(): returns a string representation
.hashCode(): returns an integer hash code value
NOTE: if a class does not override .equals(), .equals() has the same effect as ==. (Ex., String and Integer override .equals() to compare values instead of references)
Type bound: restricts the types that can be used as type arguments for a single type parameter
Bounded type parameter: a type parameter with a type bound
Use extends keyword and type bound to declare bounded type parameter (Ex., <T extends Number>)
public static <T extends Number> double calcDistance(T x1, T x2, T y1, T y2) {
return Math.sqrt(
Math.pow(x2.doubleValue() - x1.doubleValue(), 2.0) +
Math.pow(y2.doubleValue() - y1.doubleValue(), 2.0)
);
}
public static void main(String[] args) {
System.out.println(calcDistance(0, 3, 0, 4));
System.out.println(calcDistance(1.5, 4.5, 2.0, 6.0));
}NOTE: Java allows primitive widening, boxing, boxing followed by reference widening, and unboxing followed by primitive widening. However, Java does NOT allow primitive widening followed by boxing
Common Number class methods:
.doubleValue(): returns the number’s value as a double
.floatValue(): returns the number’s value as a float
.intValue(): returns the number’s value as an int
6.3 Generic classes
Generic class: a class with one or more type parameters that can be used to define class member types
public class Pair<T> {
private T first;
private T second;
public Pair(T first, T second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
}Pair<String> name = new Pair<String>("James", "Gosling");NOTE: omitting the type argument from a declared variable’s type results in a compiler error (Ex., Pair<> name = new Pair<String>("James", "Gosling"))
public class Pair<T, U> {
private T first;
private U second;
public Pair(T first, U second) {
this.first = first;
this.second = second;
}
public T getFirst() {
return first;
}
public U getSecond() {
return second;
}
}Pair<String, Integer> p = new Pair<>("Alice", 20);NOTE: type arguments must be class types
6.4 Generic classes with type bounds
NOTE: runtime polymorphism ensures that the overridden method of the actual object’s class is called, rather than the method of the reference type
public class Point<T extends Number> {
private T x;
private T y;
public Point(T x, T y) {
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public T getY() {
return y;
}
public double calcDistance(Point<T> p) {
return Math.sqrt(
Math.pow(x.doubleValue() - p.getX().doubleValue(), 2.0) +
Math.pow(y.doubleValue() - p.getY().doubleValue(), 2.0)
);
}
}NOTE: <T extends Number> guarantees T is a Number, but not a specific subclass like Double. Therefore, T cannot be passed to a method that requires Double
NOTE: using the same generic type T requires the types to match
6.5 Java example: Map values using a generic method (optional)
6.6 Abstract data types
Abstract data type (ADT): a data type described by predefined user operations without indicating how each operation is implemented
| ADT | Description | Common underlying data structures |
|---|---|---|
| List | ADT for holding ordered data | Array, linked list |
| Dynamic array | ADT for holding ordered data and allowing indexed acccess | Array |
| Stack | ADT in which items are only inserted on or removed from the top of a stack | Linked list, array |
| Queue | ADT in which items are inserted at the end of the queue and removed from the front of the queue | Linked list, array |
| Deque (short for double-ended queue) | ADT in which items can be inserted and removed at both the front and back | Linked list, array |
| Bag | ADT for storing items in which the order does not matter and duplicate items are allowed | Array, linked list |
| Set | ADT for a collection of distinct items | Binary search tree, hash table |
| Priority queue | A queue where each item has a priority, and items with higher priority are closer to the front of the queue than items with lower priority | Heap |
| Dictionary (Map) | ADT that associates (or maps) keys with values | Hash table, binary search tree |
6.7 Applications of ADTs
Abstraction: to have a user interact with an item at a high-level, with lower-level details hidden from the user
Most programming languages provide standard libraries that implement common abstract data types
6.8 Interfaces
Java provides interfaces as another mechanism for programmers to state that a class adheres to rules define
Interface: specifiy a set of abstract methods that an implementing class must override and define (provides method declarations consist of return type, name, and parameters)
Use the interface keyword to create an interface
public interface Animal {
void eat();
void sleep();
}Any class that implements an interface must list the interface names and override and implement the interface’s abstract methods
NOTE: all fields in an interface are automatically decorated with public static final
NOTE: implementing interfaces with the same method signature but incompatible return types causes a compile-time error. Return types are compatible if one is a subtype of the other (Ex., Integer and Number)
<<interface>> above the interface name denote interfaces in UML diagrams
Classes that implement the interface have a dashed line with an unfilled arrow pointing at the interface
6.9 Comparable interfaces: Sorting an ArrayList
Collections.sort() sorts an ArrayList of primitive wrapper classes
Use Collections.sort(list, Collections.reverseOrder()) to sort in reverse order
class Employee implements Comparable<Employee> {
String name;
int salary;
public Employee(String name, int salary) {
this.name = name;
this.salary = salary;
}
@Override
public int compareTo(Employee other) {
return Integer.compare(this.salary, other.salary);
}
}NOTE: a subclass inherits the parent’s comparison type cannot implement Comparable<T> again with a different type argument
A class implementing Comparable<T> does not have to compare objects of its own type. The type T specifies the type of object accepted by compareTo()
NOTE: Java chooses the most specific applicable overloaded method; exact matches are preferred over widening, and automatic narrowing is not allowed
NOTE: In Java compareTo(), a negative value means the current object comes before the other object, a positive value means it comes after, and 0 means they are equal in sorting order.
NOTE: the class must implement all required methods declared by the interface; otherwise, the class must be declared abstract
NOTE: an implementing class may only declare the same or narrower checked exceptions, or unchecked exceptions
NOTE: interfaces are not classes
NOTE: <T extends Animal> means T must be Animal or its subclass. Ex.,
class Animal {
void eat() {}
}
class Dog extends Animal {}
class Box<T extends Animal> {
T item;
void feed() {
item.eat(); // valid
}
}
Box<Dog> b = new Box<>(); // valid
// Box<String> b = new Box<>(); // errorInterfaces define a set of methods that different classes must implement, enabling polymorphism and flexibility (implement some if abstract class)
Define interface: interface keyword
Implement interface: implements keyword
Interfaces are not classes
Comparison: implements Comparable<SomeType>
compareTo(other): negative: this before other, 0: equal order, positive: this after other
Declare generics before return type
Unbounded: object (<T>)
Bounded: specified class or interface or its subtypes (<T extends SomeType>)
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}Collections.sort() uses bounded generics to require its arguments implement Comparable, checked at compile time
Cannot construct generic objects
Cannot use a generic as operand for instanceof
Since Java erases generic during compilations