0

このコードは、両方向のフローを 1 つのフローと見なすことになっています。例えば:

srcAddr,dstAddr,srcPort,dstPort
192.168.1.65, 217.174.16.1, 123456,80

と同じでなければなりません

217.174.16.1, 192.168.1.65,80,123456

もう一つの例:

192.168.1.65, 217.174.16.1, 12345, 80, TCP
217.174.16.1, 192.168.1.65, 80, 12345, TCP
192.168.1.65, 217.174.16.1, 12345, 80, TCP
217.174.16.1, 192.168.1.65, 80, 12345, TCP

私はそれを次のように保ちたい:

Flow 1: key---> value (keeps statistics about each packet, like length and timeArrival)

[192.168.1.65, 217.174.16.1, 12345, 80] ----> [(outgoing, 1,2)(incoming,3,4)()()...]

192.168.1.65, 69.100.70.80, 98521, 80 69.100.70.80, 192.168.1.65, 80, 98521 192.168.1.65, 69.100.70.80, 98521, 80 69.100.70.80, 192.168.1.65, 80, 98521 192.168.1.65, 69.100.70.80, 98521, 80 69.100.70.80, 192.168.1.65, 80, 98521

Flow 2: [192.168.1.65, 69.100.70.80, 98521, 80] --> [(outgoing, 1,2)(incoming,3,4)()()...]

結果を得るためにどのように変更すればよいですか?[hashMap を使用しており、このフローのクラスが私のキーです]

 package myclassifier;
 public class Flows implements Comparable<Flows> {

String srcAddr = "", dstAddr = "", protocol = "";
int srcPort = 0, dstPort = 0;

public Flows(String sIP, String dIP, int sPort, int dPort){
    this.srcAddr = sIP;
    this.dstAddr = dIP;
    this.srcPort = sPort;
    this.dstPort = dPort;
    //this.protocol = protocol;

}
public Flows(){

}

public int compareTo(Flows other) {
    int res = 1;
    if(this.equals(other)){
        return res=0;
    }else
        return 1;
}



 @Override
public int hashCode() {

    final int prime = 31;
    int result = 1;
    result = prime * result + ((dstAddr == null) ? 0 : dstAddr.hashCode());
    result = prime * result + dstPort;
    result = prime * result + ((srcAddr == null) ? 0 : srcAddr.hashCode());
    result = prime * result + srcPort;
    return result;

}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;

    if (getClass() != obj.getClass())
        return false;

    Flows other = (Flows) obj;

    if (dstAddr == null) {
        if (other.dstAddr != null)
            return false;
    } else if (!dstAddr.equals(other.dstAddr))
        return false;
    if (dstPort != other.dstPort)
        return false;
    if (srcAddr == null) {
        if (other.srcAddr != null)
            return false;
    } else if (!srcAddr.equals(other.srcAddr))
        return false;
    if (srcPort != other.srcPort)
        return false;
    return true;

}

 @Override
public String toString() {
return String.format("[%s, %s, %s, %s, %s]", srcAddr, dstAddr, srcPort, dstPort, protocol);
}


}
4

3 に答える 3

2

おそらくこれを行う最もクリーンな方法は、これらのメソッドを定義することです:

  • Flows reverse()指定されたの逆方向を返しFlowsますFlows
  • Flows canon()の正規化された形式を返しますFlows
    • Flowsたとえば、次の場合に a はカノンであると定義できますsrcAddr.compareTo(dstAddr) <= 0
    • そうでなければ、それreverse()は定義上正典です

次に、方向性のない比較のために、2 つのフローの正規形を単純に比較できます。これらのメソッドを使用すると、残りのロジックが非常にクリーンで読みやすくなります (以下のコードを参照)。


Comparator、 、および との一貫Comparable性についてequals

上記のreverse()概念を使用すると、f.equals(f.reverse())常に必要な場合は、そもそも方向性の概念がないはずです。この場合、正規化が最善の方法です。

iffは一般にではありませんが、必要に応じて 0と比較しequals(f.reverse())たい場合は、使用しないでください。これを行うと、equals と一致しない自然な順序付けが課せられるためです。ff.reverse()Comparable

ドキュメントから:

クラスの自然な順序付けは、クラスのすべてのおよびクラスと同じブール値を持つ場合にのみ、一貫性Cがあると言われます。 equalse1.compareTo(e2) == 0e1.equals(e2)e1e2C

自然な順序付けが と一致することを強くお勧めします (必須ではありません) equals

つまり、 にComparable矛盾する自然な順序付けを課す代わりに、代わりにequals無指向性を提供する必要がありますComparator

類推として、この状況を と比較Stringしてください。Comparator<String> CASE_INSENSITIVE_ORDERequals

したがって、ここでは、方向を区別しないことによって 0 と比較されないComparator<Flows>2 を許可するa を記述します。Flowsequals

こちらもご覧ください

関連する質問


実装例

これは、無指向性も提供すると一致する指向性の自然順序付けを持つandEdgeを持つクラスの実装例です。fromtoequalsComparator

次に、次の 3 種類でテストされSetます。

  • A 、HashSetテストするequalshashCode
  • A TreeSet、自然順序付けをテストする
  • 非方向性をテストするTreeSetためのカスタムの AComparator

実装は簡潔かつ明確であり、有益なものでなければなりません。

import java.util.*;

class Edge implements Comparable<Edge> {
    final String from, to;
        
    public Edge(String from, String to) {
        this.from = from;
        this.to = to;
    }
    @Override public String toString() {
        return String.format("%s->%s", from, to);
    }
    public Edge reverse() {
        return new Edge(to, from);
    }
    public Edge canon() {
        return (from.compareTo(to) <= 0) ? this : this.reverse();
    }
    @Override public int hashCode() {
        return Arrays.hashCode(new Object[] {
            from, to
        });
    }   
    @Override public boolean equals(Object o) {
        return (o instanceof Edge) && (this.compareTo((Edge) o) == 0);
    }
    @Override public int compareTo(Edge other) {
        int v;

        v = from.compareTo(other.from);
        if (v != 0) return v;

        v = to.compareTo(other.to);
        if (v != 0) return v;

        return 0;
    }
    public static Comparator<Edge> NON_DIRECTIONAL =
        new Comparator<Edge>() {
            @Override public int compare(Edge e1, Edge e2) {
                return e1.canon().compareTo(e2.canon());
            }
        };
}

public class Main {
    public static void main(String[] args) {
        testWith(new HashSet<Edge>());
        testWith(new TreeSet<Edge>());
        testWith(new TreeSet<Edge>(Edge.NON_DIRECTIONAL));
    }
    public static void testWith(Set<Edge> set) {
        set.clear();
        set.add(new Edge("A", "B"));
        set.add(new Edge("C", "D"));
        System.out.println(set.contains(new Edge("A", "B")));
        System.out.println(set.contains(new Edge("B", "A")));
        System.out.println(set.contains(new Edge("X", "Y")));
        System.out.println(set);
        set.add(new Edge("B", "A"));
        set.add(new Edge("Z", "A"));
        System.out.println(set);
        System.out.println();
    }
}

出力は ( ideone.com で見られるように) 以下に注釈が付けられています:

// HashSet
// add(A->B), add(C->D)
true    // has A->B?
false   // has B->A?
false   // has X->Y?
[C->D, A->B]
// add(B->A), add(Z->A)
[B->A, C->D, Z->A, A->B]

// TreeSet, natural ordering (directional)    
// add(A->B), add(C->D)
true    // has A->B?
false   // has B->A?
false   // has X->Y
[A->B, C->D]
// add(B->A), add(Z->A)
[A->B, B->A, C->D, Z->A]

// TreeSet, custom comparator (non-directional)
// add(A->B), add(C->D)
true    // has A->B?
true    // has B->A?
false   // has X->Y?
[A->B, C->D]
// add(B->A), add(Z->A)
[A->B, Z->A, C->D]

無指向性TreeSetの では、Z->Aが に正規化されていることに注意してください。これが、この順序でA->Z前に表示される理由です。C->D同様に、B->Aは に正規化されてA->Bおり、これはすでにセットに含まれています。これは、そこに 3 つしかない理由を説明していEdgeます。

キーポイント

  • Edge不変です
  • Arrays.hashCode(Object[])便宜上使用されます。すべての数式をコーディングする必要はありません
  • 自然順序付けが と一致する場合は、でequals使用できますcompareTo == 0equals
  • 簡潔さと明確さのために多段階returnロジックを使用するcompareTo
  • 無指向性の比較を大幅に簡素化 しreverse()ますcanon()
    • 自然な順序で正規化された形式を単純に比較する

こちらもご覧ください

  • 有効な Java 2nd Edition
    • 項目 8: オーバーライドするときは一般契約に従うequals
    • 項目 9: オーバーライドhashCodeするときは常にオーバーライドするequals
    • 項目 10: 常にオーバーライドするtoString
    • 項目 12: 実装を検討するComparable
    • 項目15: 可変性を最小限に抑える
    • 項目 36:@Overrideアノテーションを一貫して使用する
    • 項目47:図書館を知り、利用する
于 2010-08-17T09:41:52.090 に答える
0

これが役立つかどうかはわかりませんが、あなたが言うように、両方の方向に機能します

import java.util.HashSet;
 public class Flows implements Comparable<Flows> {

String srcAddr = "", dstAddr = "", protocol = "";
int srcPort = 0, dstPort = 0;

public Flows(String sIP, String dIP, int sPort, int dPort){
    this.srcAddr = sIP;
    this.dstAddr = dIP;
    this.srcPort = sPort;
    this.dstPort = dPort;
    //this.protocol = protocol;

}
public Flows(){

}

public int compareTo(Flows other) {

    if(this.equals(other)){
        return 0;
    }else
        return 1;
}



 @Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((dstAddr == null) ? 0 : dstAddr.hashCode())+((srcAddr == null) ? 0 : srcAddr.hashCode());
    result = prime * result + dstPort+srcPort;
    return result;

}

@Override
public boolean equals(Object obj) {
   if (this == obj)
        return true;

   if(obj instanceof Flows)
   {
    Flows c=(Flows)obj;
    if(srcAddr.equals(c.dstAddr) && dstAddr.equals(c.srcAddr) &&srcPort==c.dstPort && dstPort==c.srcPort)
      return true;

    if(srcAddr.equals(c.srcAddr) && dstAddr.equals(c.dstAddr) && srcPort==c.srcPort && dstPort==c.dstPort)
        return true;
   }
    return false;

}

 @Override
public String toString() {
return String.format("[%s, %s, %s, %s, %s]", srcAddr, dstAddr, srcPort, dstPort, protocol);
}

public static void main(String[] args) {
    Flows f1=new Flows("192.168.1.65","217.174.16.1", 123456,80);
    Flows f2=new Flows("217.174.16.1","192.168.1.65",80,123456);

    Flows f3=new Flows("192.168.1.66","217.174.16.1", 123456,80);
    Flows f4=new Flows("217.174.16.1","192.168.1.66",80, 123456);
    System.out.println(f1.hashCode()+ " "+f2.hashCode());
    HashSet<Flows> hh=new HashSet<Flows>();
    hh.add(f1);
    hh.add(f2);
    hh.add(f3);
    hh.add(f4);
    System.out.println(f1.compareTo(f2));
    System.out.println(hh);
}
}

テストにハッシュセットを使用しました。したがって、ハッシュマップでも問題なく動作するはずです。

于 2010-08-17T10:51:11.200 に答える
0

重要なのは、equals メソッドを正しく実装することです。あなたのequalsメソッドでは、宛先アドレスが一致しない瞬間にfalseを返しています。これは、双方向の等価性が必要なため、等価性をチェックする追加のロジックを追加する必要がある場所です。同等性の最初のパスは、送信元、宛先、ポートの同等性をチェックする必要があります。2 番目のパスは、送信元と送信先が逆に等しい必要があります。また、例のように、デフォルト値の portno(80) の除外を true に特別に設定する必要があります。

于 2010-08-17T09:54:27.407 に答える