2011-07-11 39 views
3

我需要爲InetSocketAddress編寫Comparator,所以我可以在TreeSet中使用這個類。他們需要通過地址和端口進行比較。InetSocketAddress的Java比較器

的代碼會是這個樣子,但問題是我不知道如何通過<(-1)的地址和端口進行比較,>(1)=(0)

TreeSet<InetSocketAddress> _tree = new TreeSet<InetSocketAddress> 
    (new Comparator<InetSocketAddress>() { 

    public int compare(InetSocketAddress o1, InetSocketAddress o2) { 

     ///????? 
     return 0; 
    } 
}); 

編輯...實際的問題。如何比較InetSocketAddress。

+2

*「問題是..」*您忘了提問? (不,'/// ?????'是*不是問題)。 –

+0

爲了與['InetSocketAddress.equals(Object)'](http://docs.oracle.com/javase/7/docs/api/java/net/InetSocketAddress.html#equals%28java.lang .Object%29)方法,我建議你看一看'InetSocketAddress.equals(Object)'方法是如何在[OpenJDK 7]中實現的(http://grepcode.com/file/repository.grepcode.com/java /root/jdk/openjdk/7u40-b43/java/net/InetSocketAddress.java#InetSocketAddress.equals%28java.lang.Object%29)。如果他們堅持'equals - compareTo'約定,一定要檢查這篇文章的每個答案。 – mucaho

回答

4

代碼與的InetSocketAddress #getHostName比較不正確,因爲當解析主機名時,它可能爲空。看看構造函數:

public InetSocketAddress(String hostname, int port) { 
if (port < 0 || port > 0xFFFF) { 
    throw new IllegalArgumentException("port out of range:" + port); 
} 
if (hostname == null) { 
    throw new IllegalArgumentException("hostname can't be null"); 
} 
try { 
    addr = InetAddress.getByName(hostname); 
} catch(UnknownHostException e) { 
    this.hostname = hostname; 
    addr = null; 
} 
this.port = port; 
} 

僅使用IP的代碼也不正確 - 主機名可能無法解析。這應該是相當有效的:

Integer getIp(InetSocketAddress addr) { 
    byte[] a = addr.getAddress().getAddress(); 
    return ((a[0] & 0xff) << 24) | ((a[1] & 0xff) << 16) | ((a[2] & 0xff) << 8) | (a[3] & 0xff); 
} 

public int compare(InetSocketAddress o1, InetSocketAddress o2) { 
    //TODO deal with nulls 
    if (o1 == o2) { 
     return 0; 
    } else if(o1.isUnresolved() || o2.isUnresolved()){ 
     return o1.toString().compareTo(o2.toString()); 
    } else { 
     int compare = getIp(o1).compareTo(getIp(o2)); 
     if (compare == 0) { 
      compare = Integer.valueOf(o1.getPort()).compareTo(o2.getPort()); 
     } 
     return compare; 
    } 
} 
+1

上面有兩種可能性:數字的比較順序與字符串的比較順序不匹配。或者它確實如此。在第一種情況下(由於ascii表佈局,這不是真的),如果考慮a1,a2和a3(其中只有a2未解析),以上可能會被破壞。在第二種情況下,它們是等價的,在這種情況下,增加的複雜性並不真正爲您帶來任何實質性的成本(超過.toString的成本)。 – alphazero

+0

主機名在構造函數中解析。地址解析後,主機名保持爲空。具有解析主機的InetSocketAddress不等於具有相同未解析主機的InetSocketAddress。所以矛盾的情況永遠不會發生。 – zacheusz

1

<(-1),>(1)=需要進行排序 (0)我想你可以假設訂購 - 例如:

public int compare(InetSocketAddress o1, InetSocketAddress o2) { 
    //TODO deal with nulls 
    if(o1 == o2){ 
     return 0; 
    } else { 
     return o1.toString().compareTo(o2.toString()); 
    } 
} 

這是不是很有效,但它ilustrates的理念。比較IP(何時可用,已解決)可以更快。

+1

compareTo,not compareWith,methinks –

+0

@Ed:thx,fixed – zacheusz

1

取決於你是否需要一個特定的順序,或某種分辨率,這可能是正確的:

class ISC implements Comparator<InetSocketAddress> 
{ 

@Override 
    public int compare(InetSocketAddress o1, InetSocketAddress o2) 
    { 
     return o1.toString().compareTo(o2.toString()); 
    } 
} 
1

嘗試使用CompareToBuilder,並通過在getAddress().getHostAddress()getPort()

+1

您不能僅使用getAddress() - 如果主機名未解決,則返回null – zacheusz

1

你只需要選擇一個約定。

例如

  1. 爲IP地址選擇任意排序方案 。它只是需要一致應用。

    很顯然,點 表示法提供了一種自然的方式 這樣做,因此您可以分解例如127.0.0.1到{127,0,0,1}和 與另一個例如{84,23,10,2}要清楚。

    另一種選擇是將地址部分轉換爲長數字,然後比較這些數字。這是基本的哈希。

  2. 爲端口號選擇任意排序方案 。對於 來說似乎是合理的,只是使用數字語義和 例如治療口55小於端口 999(雖然只要涉及IP協議 ,這樣的語義視圖是 毫無意義。)

僞代碼:

compare (addr1, addr2) 
    if addr1.host > addr2.host return 1; 
    else if addr1.host < addr2.host return -1; 

    if addr1.port > addr2.port return 1; 
    else if addr1.port < addr2.port return -1; 

    return 0; 
+1

Up投票無意義且無法解釋的投票。 – EJP

+0

僞代碼是完美的。 廣告點1:恕我直言,您不能僅使用IP地址排序方案 - 主機名可能無法解析。 – zacheusz

+1

@zacheusz:我同意重新解決。因此「另一種選擇是將地址部分轉換爲長數字,然後比較這些數字,這是基本的哈希。」例如,採用SHA_1的前8個字節(「www.the-host-name.com」,並使用它來比較地址。 – alphazero