Here are some of the key points from this chapter.
q | equals(), hashCode(), and toString() are public. | ||||||||||
q | Override toString() so that System.out.println() or other methods can see something useful, like your object's state. | ||||||||||
q | Use == to determine if two reference variables refer to the same object. | ||||||||||
q | Use equals() to determine if two objects are meaningfully equivalent. | ||||||||||
q | If you don't override equals(), your objects won't be useful hashing keys. | ||||||||||
q | If you don't override equals(), different objects can't be considered equal. | ||||||||||
q | Strings and wrappers override equals() and make good hashing keys. | ||||||||||
q | When overriding equals(), use the instanceof operator to be sure you're evaluating an appropriate class. | ||||||||||
q | When overriding equals(), compare the objects' significant attributes. | ||||||||||
q | Highlights of the equals() contract:
| ||||||||||
q | If x.equals(y) is true, then x.hashCode() == y.hashCode() is true. | ||||||||||
q | If you override equals(), override hashCode(). | ||||||||||
q | HashMap, HashSet, Hashtable, LinkedHashMap, & LinkedHashSet use hashing. | ||||||||||
q | An appropriate hashCode() override sticks to the hashCode() contract. | ||||||||||
q | An efficient hashCode() override distributes keys evenly across its buckets. | ||||||||||
q | An overridden equals() must be at least as precise as its hashCode() mate. | ||||||||||
q | To reiterate: if two objects are equal, their hashcodes must be equal. | ||||||||||
q | It's legal for a hashCode() method to return the same value for all instances (although in practice it's very inefficient). | ||||||||||
q | Highlights of the hashCode() contract:
| ||||||||||
q | transient variables aren't appropriate for equals() and hashCode(). |
q | Common collection activities include adding objects, removing objects, verifying object inclusion, retrieving objects, and iterating. | ||||||||
q | Three meanings for "collection":
| ||||||||
q | Four basic flavors of collections include Lists, Sets, Maps, Queues:
| ||||||||
q | Four basic sub-flavors of collections Sorted, Unsorted, Ordered, Unordered.
| ||||||||
q | Sorting can be alphabetic, numeric, or programmer-defined. |
q | ArrayList: Fast iteration and fast random access. |
q | Vector: It's like a slower ArrayList, but it has synchronized methods. |
q | LinkedList: Good for adding elements to the ends, i.e., stacks and queues. |
q | HashSet: Fast access, assures no duplicates, provides no ordering. |
q | LinkedHashSet: No duplicates; iterates by insertion order. |
q | TreeSet: No duplicates; iterates in sorted order. |
q | HashMap: Fastest updates (key/value pairs); allows one null key, many null values. |
q | Hashtable: Like a slower HashMap (as with Vector, due to its synchronized methods). No null values or null keys allowed. |
q | LinkedHashMap: Faster iterations; iterates by insertion order or last accessed; allows one null key, many null values. |
q | TreeMap: A sorted map, |
q | PriorityQueue: A to-do list ordered by the elements' priority. |
q | Collections hold only Objects, but primitives can be autoboxed. |
q | Iterate with the enhanced for, or with an Iterator via hasNext() & next(). |
q | hasNext() determines if more elements exist; the Iterator does NOT move. |
q | next() returns the next element AND moves the Iterator forward. |
q | To work correctly, a Map's keys must override equals() and hashCode(). |
q | Queues use offer() to add an element, poll() to remove the head of the queue, and peek() to look at the head of a queue. |
q | Sorting can be in natural order, or via a Comparable or many Comparators. |
q | Implement Comparable using compareTo(); provides only one sort order. |
q | Create many Comparators to sort a class many ways; implement compare(). |
q | To be sorted and searched, a List's elements must be comparable. |
q | To be searched, an array or List must first be sorted. |
q | Both of these java.util classes provide
| ||||
q | Arrays.asList() creates a List from an array and links them together. | ||||
q | Collections.reverse() reverses the order of elements in a List. | ||||
q | Collections.reverseOrder() returns a Comparator that sorts in reverse. | ||||
q | Lists and Sets have a toArray() method to create arrays. |
q | Generics let you enforce compile-time type safety on Collections (or other classes and methods declared using generic type parameters). |
q | An ArrayList<Animal> can accept references of type Dog, Cat, or any other subtype of Animal (subclass, or if Animal is an interface, implementation). |
q | When using generic collections, a cast is not needed to get (declared type) elements out of the collection. With non-generic collections, a cast is required:
List<String> gList = new ArrayList<String>(); List list = new ArrayList(); // more code String s = gList.get(0); // no cast needed String s = (String)list.get(0); // cast required |
q | You can pass a generic collection into a method that takes a non-generic collection, but the results may be disastrous. The compiler can't stop the method from inserting the wrong type into the previously type safe collection. |
q | If the compiler can recognize that non-type-safe code is potentially endangering something you originally declared as type-safe, you will get a compiler warning. For instance, if you pass a List<String> into a method declared as
void foo(List aList) { aList.add(an Integer); } the compiler will issue a warning because the add() method is potentially an "unsafe operation." |
q | Remember that "compiles without error" is not the same as "compiles without warnings." On the exam, a compilation warning is not considered a compilation error or failure. |
q | Generic type information does not exist at runtime—it is for compile-time safety only. Mixing generics with legacy code can create compiled code that may throw an exception at runtime. |
q | Polymorphic assignments applies only to the base type, not the generic type parameter. You can say
List<Animal> aList = new ArrayList<Animal>(); // yes You can't say
List<Animal> aList = new ArrayList<Dog>(); // no |
q | The polymorphic assignment rule applies everywhere an assignment can be made. The following are NOT allowed:
void foo(List<Animal> aList) { } // cannot take a List<Dog> List<Animal> bar() { } // cannot return a List<Dog> |
q | Wildcard syntax allows a generic method, accept subtypes (or supertypes) of the declared type of the method argument:
void addD(List<Dog> d) {} // can take only <Dog> void addD(List<? extends Dog>) {} // take a <Dog> or <Beagle> |
q | The wildcard keyword extends is used to mean either "extends" or "implements," So in <? extends Dog>, Dog can be a class or an interface. |
q | When using a wildcard, List<? extends Dog>, the collection can be accessed but not modified. |
q | When using a wildcard, List<?>, any generic type can be assigned to the reference, but for access only, no modifications. |
q | List<Object> refers only to a List<Object>, while List<?> or List<? extends Object> can hold any type of object, but for access only. |
q | Declaration conventions for generics use T for type and E for element:
public interface List<E> // API declaration for List boolean add(E o) // List.add() declaration |
q | The generics type identifier can be used in class, method, and variable declarations:
class Foo<t> { } //a class T anInstance; // an instance variable Foo(T aRef) {} //a constructor argument void bar(T aRef) {} //a method argument T baz() {} //a return type The compiler will substitute the actual type. |
q | You can use more than one parameterized type in a declaration:
public class UseTwo<T, X> { } |
q | You can declare a generic method using a type not defined in the class:
public <T> void makeList(T t) { } is NOT using T as the return type. This method has a void return type, but to use T within the method's argument you must declare the <T>, which happens before the return type. |