1. 程式人生 > >考慮實現Comparable介面

考慮實現Comparable介面

我們重寫實現

compareTo  實現自己的需求。

為什麼重寫?

原來的compareTo是空方法體, 很多類已實現該介面,目的就是為了排序,通過什麼排序,這就根據自己的業務邏輯了。

比如: public final class PhoneNumber implements Cloneable, Comparable<PhoneNumber> {...  public static void main(String[] args) {...
 NavigableSet<PhoneNumber> s = new TreeSet<PhoneNumber>();
        for (int i = 0; i < 10; i++)
            s.add(randomPhoneNumber());
        System.out.println(s);
... TreeSet自身就實現了Comparable 介面 s.add就會呼叫TreeSert.java 內部方法  
return m.put(e, PRESENT)==null;

m.put就會呼叫TreeMap.java 內部put方法
/**
     * Associates the specified value with the specified key in this map.
     * If the map previously contained a mapping for the key, the old
     * value is replaced.
     *
     * @param key key with which the specified value is to be associated
     * @param value value to be associated with the specified key
     *
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     * @throws ClassCastException if the specified key cannot be compared
     *         with the keys currently in the map
     * @throws NullPointerException if the specified key is null
     *         and this map uses natural ordering, or its comparator
     *         does not permit null keys
     */
    public V put(K key, V value) {
        Entry<K,V> t = root;
        if (t == null) {
	    // TBD:
	    // 5045147: (coll) Adding null to an empty TreeSet should
	    // throw NullPointerException
	    //
	    // compare(key, key); // type check
            root = new Entry<K,V>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        else {
            if (key == null)
                throw new NullPointerException();
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<K,V>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }

因為
 cmp = k.compareTo(t.key);
我想重寫compareTo方法,實現自己的邏輯,所以我實現Comparable<PhoneNumber>介面,重寫它的方法。
----------------------------------------------------------------------------------------------------------------------------------------------------->api--------------------------------------

這個介面是什麼?

java.lang 
介面 Comparable<T>
型別引數:
T - 可以與此物件進行比較的那些物件的型別
所有已知子介面: 
Delayed, Name, RunnableScheduledFuture<V>, ScheduledFuture<V> 
所有已知實現類: 
Authenticator.RequestorType, BigDecimal, BigInteger, Boolean, Byte, ByteBuffer, Calendar, Character, CharBuffer, Charset, ClientInfoStatus, CollationKey, Component.BaselineResizeBehavior, CompositeName, CompoundName, Date, Date, Desktop.Action, Diagnostic.Kind, Dialog.ModalExclusionType, Dialog.ModalityType, Double, DoubleBuffer, DropMode, ElementKind, ElementType, Enum, File, Float, FloatBuffer, Formatter.BigDecimalLayoutForm, FormSubmitEvent.MethodType, GregorianCalendar, GroupLayout.Alignment, IntBuffer, Integer, JavaFileObject.Kind, JTable.PrintMode, KeyRep.Type, LayoutStyle.ComponentPlacement, LdapName, Long, LongBuffer, MappedByteBuffer, MemoryType, MessageContext.Scope, Modifier, MultipleGradientPaint.ColorSpaceType, MultipleGradientPaint.CycleMethod, NestingKind, Normalizer.Form, ObjectName, ObjectStreamField, Proxy.Type, Rdn, Resource.AuthenticationType, RetentionPolicy, RoundingMode, RowFilter.ComparisonType, RowIdLifetime, RowSorterEvent.Type, Service.Mode, Short, ShortBuffer, SOAPBinding.ParameterStyle, SOAPBinding.Style, SOAPBinding.Use, SortOrder, SourceVersion, SSLEngineResult.HandshakeStatus, SSLEngineResult.Status, StandardLocation, String, SwingWorker.StateValue, Thread.State, Time, Timestamp, TimeUnit, TrayIcon.MessageType, TypeKind, URI, UUID, WebParam.Mode, XmlAccessOrder, XmlAccessType, XmlNsForm 


public interface Comparable<T>
此介面強行對實現它的每個類的物件進行整體排序。這種排序被稱為類的自然排序,類的 compareTo 方法被稱為它的自然比較方法。

實現此介面的物件列表(和陣列)可以通過 Collections.sort(和 Arrays.sort)進行自動排序。實現此介面的物件可以用作有序對映中的鍵或有序集合中的元素,無需指定比較器。

對於類 C 的每一個 e1 和 e2 來說,當且僅當 e1.compareTo(e2) == 0 與 e1.equals(e2) 具有相同的 boolean 值時,類 C 的自然排序才叫做與 equals 一致。注意,null 不是任何類的例項,即使 e.equals(null) 返回 false,e.compareTo(null) 也將丟擲 NullPointerException。

建議(雖然不是必需的)最好使自然排序與 equals 一致。這是因為在使用自然排序與 equals 不一致的元素(或鍵)時,沒有顯式比較器的有序集合(和有序對映表)行為表現“怪異”。尤其是,這樣的有序集合(或有序對映表)違背了根據 equals 方法定義的集合(或對映表)的常規協定。

例如,如果將兩個鍵 a 和 b 新增到沒有使用顯式比較器的有序集合中,使 (!a.equals(b) && a.compareTo(b) == 0),那麼第二個 add 操作將返回 false(有序集合的大小沒有增加),因為從有序集合的角度來看,a 和 b 是相等的。

實際上,所有實現 Comparable 的 Java 核心類都具有與 equals 一致的自然排序。java.math.BigDecimal 是個例外,它的自然排序將值相等但精確度不同的 BigDecimal 物件(比如 4.0 和 4.00)視為相等。

從數學上講,定義給定類 C 上自然排序的關係式 如下:

      {(x, y)|x.compareTo(y) <= 0}。
整體排序的商 是:
      {(x, y)|x.compareTo(y) == 0}。
它直接遵循 compareTo 的協定,商是 C 的等價關係,自然排序是 C 的整體排序。當說到類的自然排序與 equals 一致 時,是指自然排序的商是由類的 equals(Object) 方法定義的等價關係。
    {(x, y)|x.equals(y)}。此介面是 Java Collections Framework 的成員。


方法詳細資訊

compareTo
int compareTo(T o)比較此物件與指定物件的順序。如果該物件小於、等於或大於指定物件,則分別返回負整數、零或正整數。 
實現類必須確保對於所有的 x 和 y 都存在 sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) 的關係。(這意味著如果 y.compareTo(x) 丟擲一個異常,則 x.compareTo(y) 也要丟擲一個異常。) 

實現類還必須確保關係是可傳遞的:(x.compareTo(y)>0 && y.compareTo(z)>0) 意味著 x.compareTo(z)>0。 

最後,實現者必須確保 x.compareTo(y)==0 意味著對於所有的 z,都存在 sgn(x.compareTo(z)) == sgn(y.compareTo(z))。 強烈推薦 (x.compareTo(y)==0) == (x.equals(y)) 這種做法,但並不是 嚴格要求這樣做。一般來說,任何實現 Comparable 介面和違背此條件的類都應該清楚地指出這一事實。推薦如此闡述:“注意:此類具有與 equals 不一致的自然排序。” 

在前面的描述中,符號 sgn(expression) 指定 signum 數學函式,該函式根據 expression 的值是負數、零還是正數,分別返回 -1、0 或 1 中的一個值。 


引數:
o - 要比較的物件。 
返回:
負整數、零或正整數,根據此物件是小於、等於還是大於指定物件。 
丟擲: 
ClassCastException - 如果指定物件的型別不允許它與此物件進行比較。