Collection system three core conventions

FIG Collection general class:

Note: Map not realize interface Collection

Collection System

To be well aware of the following categories:

/**
 * @see     Set
 * @see     List
 * @see     Map
 * @see     SortedSet
 * @see     SortedMap
 * @see     HashSet
 * @see     TreeSet
 * @see     ArrayList
 * @see     LinkedList
 * @see     Vector
 * @see     Collections
 * @see     Arrays
 * @see     AbstractCollection
 */

Understand the meaning of each method Collection: default method includes Java8 after

public interface Collection<E> extends Iterable<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    Iterator<E> iterator();
    Object[] toArray();
    <T> T[] toArray(T[] a);
    boolean add(E e);
    boolean remove(Object o);
    boolean containsAll(Collection<?> c);
    boolean addAll(Collection<? extends E> c);
    boolean removeAll(Collection<?> c);
    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
    boolean retainAll(Collection<?> c);
    void clear();
    boolean equals(Object o);
    int hashCode();
    @Override
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
}

Arrays / Collections utility methods

In general, if X is a class that is associated with the tool Xs Method:

  • Array -> Arrays
  • Collection -> Collections
  • List -> Lists (guava)
  • Set -> Sets (guava)

Collections of some of the ways:

Collections.emptyList():
- 返回一个final的空List,这个List是一个内部类EmptyList的实例

Collections.synchronizedList(list):
- 装饰器模式,返回一个SynchronizedList的实例,这个类将list的每个方法都用synchronized包装起来了

Collections.unmodifiableList():
- 返回一个UnmodifiableList的实例,对这个实例的修改操作,都会抛出UnsupportedOperationException

Collections.sort(List<T> list):
Collections.sort(List<T> list, Comparator<? super T> c):
- 排序,实际上就是调用了list自己的sort,直接修改原list,没有返回值

还有一些checkXX和singletonXX等之类的方法

Some Collections inner class:

Such internal class used in the above method is substantially

AbstractCollection

AbstractCollection skeleton is implemented to provide an interface Collection, using模板方法模式

such as:

Collection定义了size()和isEmpty()这两个方法

在AbstractCollection中,isEmpty()的实现是:return size() == 0;
这样子,大部分AbstractCollection的子类就不需要自己再实现一遍isEmpty()方法了,
当然,子类也可以选择覆盖isEmpty()方法,以提供自己的实现。

as well as:

contains(Object o) 方法,判断一个元素是否在这个集合中,调用了 iterator 来获取子类的迭代器,然后迭代集合内的元素进行比较。
toArray、remove、removeAll、retainAll、clear、toString等方法也调用了iterator

也存在模板方法相互调用的情况:containsAll -> contains

In addition to the template method pattern, AbstractCollection itself provide some default implementation:

add()方法的现实是:throw new UnsupportedOperationException();

AbstractList, AbstractSet similar

Q: look at the source code we note that some of the methods defined in the Collection interface, AbstractCollection will be declared as once again abstract, and this is why?

In order to reflect these methods are abstract? In order to prevent or interfaces to implement these methods provide default?

A: TODO

other:

接口与接口、类与类之间用extends
类与接口用implements


如果接口有default方法a()
抽象类又将a()声明成抽象的
那么实现类还是需要覆盖a()

The core convention Collection System

equals:

  • Reflexive: reflexive, x.equals (x) == true
  • Symmetry: symmetric, x.equals (y) == y.equals (x)
  • Transitive: transitive, if x.equals (y) == true, y.equals (z) == true, then x.equals (z) == true
  • Consistency: consistent, no matter how many times x.equals (y) calls it the return value is not changed, the premise is not the equals method used to modify the information
  • For any non null object x, x.equals (null) == false

Object.equals():

  • It is reflexive: for any non-null reference value x, x.equals(x) should return true.
  • It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
  • It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
  • It is consistent: for any non-null reference values x and y, multiple invocations of x.equals(y) consistently return true or consistently return false, provided no information used in equals comparisons on the objects is modified.
  • For any non-null reference value x, x.equals(null) should return false.

hashCode:

  • In the same period a JVM, regardless of how many times a call to hashCode the same object, returns an int should be the same, provided that the equals method does not modify the information used to.
  • 若 x.equals(y) == true,则 x.hashCode() == y.hashCode()
  • If x.equals (y) == false, then x.hashCode () and y.hashCode () is not mandatory unequal.
    • But the programmer should be appreciated that, for the two objects unequals, the hashCode return different values ​​can improve performance hash table

Object.hashCode():

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

Comparable/Comparator:

  • Each implementation of the Comparableclass interface, are mandatory to achieve the overall sorting. This ordering is called natural ordering class, compareTo method of the class referred to as its natural comparison method.
    • (Ie, compareTo method uses the class is sort of natural order, or not, such as the use of additional comparator)
  • Implements Comparablethe interface of the object list or array, can be Collections.sort(and Arrays.sort) sorted automatically. To achieve this object interfaces may be used to SortedMapkey or SortedSetelement, without the need to specify the comparator.
  • For any object class C e1, e2, and only if there e1.compareTo (e2) == 0 and e1.equals (e2) returns the same value, C can be called the natural order and consistent equals.
    • Note: null is not an instance of any class, e.compareTo (null) should throw NullPointerException, even if e.equals (null) returns false.
  • It is strongly recommended to let natural ordering is consistent with equals. This is because those elements (or key) using the natural ordering is inconsistent with equals, and not specified extra Comparator's SortedSet(and SortedMap) behavior became "weird." In particular, this SortedSet(or SortedMap) violated Set (or Map) conventional convention defined in terms of the equals method.
  • For example: ... (behind example)
  • In fact, all the realization of ComparableJava core classes have the natural ordering is consistent with equals. java.math.BigDecimalHe is an exception, its natural ordering the values are equal, but the accuracy of the various BigDecimalobjects (such as 4.0 and 4.00) are considered equal.

Comparable:

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.

Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort). Objects that implement this interface can be used as keys in a sorted map or as elements in a sorted set, without the need to specify a comparator.

The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.

It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.

For example, if one adds two keys a and b such that (!a.equals(b) && a.compareTo(b) == 0) to a sorted set that does not use an explicit comparator, the second add operation returns false (and the size of the sorted set does not increase) because a and b are equivalent from the sorted set's perspective.

Virtually all Java core classes that implement Comparable have natural orderings that are consistent with equals. One exception is java.math.BigDecimal, whose natural ordering equates BigDecimal objects with equal values and different precisions (such as 4.0 and 4.00).

For the mathematically inclined, the relation that defines the natural ordering on a given class C is:
         {(x, y) such that x.compareTo(y) <= 0}.
   
The quotient for this total order is:
         {(x, y) such that x.compareTo(y) == 0}.
   
It follows immediately from the contract for compareTo that the quotient is an equivalence relation on C, and that the natural ordering is a total order on C. When we say that a class's natural ordering is consistent with equals, we mean that the quotient for the natural ordering is the equivalence relation defined by the class's equals(Object) method:
       {(x, y) such that x.equals(y)}. 

Comparable correct usage:

// 实现Comparable接口,重写compareTo方法。这里只比较age
public class User implements Comparable<User> {
    int id;
    int age;
    @Override
    public int compareTo(User that) {
        // 小于就返回-1,大于就返回1,等于就返回0
        if (age < that.age) {
            return -1;
        } else if (age > that.age) {
            return 1;
        } else {
            return 0;
        }
        // 每种基本类型都会有现成的比较器,一般不需要自己写
        // return Integer.compare(age, that.age);
    }
}

Tricky question:

// compareTo只需要返回正数、负数或0,并不一定要返回1、-1,所以有的人就会使用相减来实现
@Override
public int compareTo(User that) {
    return age - that.age;
}
// 这会有什么问题呢?
// 整数溢出问题,如果 age = Integer.MIN_VALUE,that.age = Integer.MAX_VALUE,
// 那么 age - that.age = 1

// 以及不要使用非/取反操作
// age = Integer.MIN_VALUE
// -age = -2147483648

So: Do not use addition, subtraction, negation to achieve the compareTo, as it may lead to numerical overflow .

And examples of natural ordering is inconsistent with equals:

public class User implements Comparable<User> {
    int id;
    int age;
    public User(int id, int age) {
        this.id = id;
        this.age = age;
    }
    @Override
    public int hashCode() {
        return Objects.hash(id, age);
    }
    
    // equals比较了id和age
    @Override
    public boolean equals(Object that) {
        if (this == that) {
            return true;
        }
        if (that == null || getClass() != that.getClass()) {
            return false;
        }
        User user = (User) that;
        return id == user.id &&
                age == user.age;
    }
    // compareTo只比较了age
    @Override
    public int compareTo(User that) {
        return Integer.compare(age, that.age);
    }
    public static void main(String[] args) {
        // 1号user与3号user unequals,即!user1.equals(user3)
        // user1.compareTo(user3) == 0
        // 而 SortedSet(TreeSet) 内部是使用compareTo进行比较的,那么user1与user3是相等的,所以add不进去
        Set<User> set = new TreeSet<>();
        set.add(new User(1, 20));
        set.add(new User(2, 10));
        set.add(new User(3, 20));
        // [User{id=2, age=10}, User{id=1, age=20}]
        System.out.println(set);
    }
}

equals and hashCode in a Collection used where the

ALL

Guess you like

Origin www.cnblogs.com/demojie/p/12596132.html