Java中没有Pair<L,R>,有什么好理由吗?与这个c++构造等价的是什么?我宁愿避免重新实现我自己的。
似乎1.6提供了类似的东西(AbstractMap.SimpleEntry<K,V>),但这看起来相当复杂。
Java中没有Pair<L,R>,有什么好理由吗?与这个c++构造等价的是什么?我宁愿避免重新实现我自己的。
似乎1.6提供了类似的东西(AbstractMap.SimpleEntry<K,V>),但这看起来相当复杂。
当前回答
android提供了Pairclass (http://developer.android.com/reference/android/util/Pair.html),这里实现:
public class Pair<F, S> {
public final F first;
public final S second;
public Pair(F first, S second) {
this.first = first;
this.second = second;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Pair)) {
return false;
}
Pair<?, ?> p = (Pair<?, ?>) o;
return Objects.equal(p.first, first) && Objects.equal(p.second, second);
}
@Override
public int hashCode() {
return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
}
public static <A, B> Pair <A, B> create(A a, B b) {
return new Pair<A, B>(a, b);
}
}
其他回答
我注意到所有的Pair实现都散布在这里,属性含义取决于两个值的顺序。当我想到一对时,我想到的是两件物品的组合,这两件物品的顺序不重要。下面是我对一个无序对的实现,使用hashCode和equals重写以确保集合中的期望行为。也可克隆。
/**
* The class <code>Pair</code> models a container for two objects wherein the
* object order is of no consequence for equality and hashing. An example of
* using Pair would be as the return type for a method that needs to return two
* related objects. Another good use is as entries in a Set or keys in a Map
* when only the unordered combination of two objects is of interest.<p>
* The term "object" as being a one of a Pair can be loosely interpreted. A
* Pair may have one or two <code>null</code> entries as values. Both values
* may also be the same object.<p>
* Mind that the order of the type parameters T and U is of no importance. A
* Pair<T, U> can still return <code>true</code> for method <code>equals</code>
* called with a Pair<U, T> argument.<p>
* Instances of this class are immutable, but the provided values might not be.
* This means the consistency of equality checks and the hash code is only as
* strong as that of the value types.<p>
*/
public class Pair<T, U> implements Cloneable {
/**
* One of the two values, for the declared type T.
*/
private final T object1;
/**
* One of the two values, for the declared type U.
*/
private final U object2;
private final boolean object1Null;
private final boolean object2Null;
private final boolean dualNull;
/**
* Constructs a new <code>Pair<T, U></code> with T object1 and U object2 as
* its values. The order of the arguments is of no consequence. One or both of
* the values may be <code>null</code> and both values may be the same object.
*
* @param object1 T to serve as one value.
* @param object2 U to serve as the other value.
*/
public Pair(T object1, U object2) {
this.object1 = object1;
this.object2 = object2;
object1Null = object1 == null;
object2Null = object2 == null;
dualNull = object1Null && object2Null;
}
/**
* Gets the value of this Pair provided as the first argument in the constructor.
*
* @return a value of this Pair.
*/
public T getObject1() {
return object1;
}
/**
* Gets the value of this Pair provided as the second argument in the constructor.
*
* @return a value of this Pair.
*/
public U getObject2() {
return object2;
}
/**
* Returns a shallow copy of this Pair. The returned Pair is a new instance
* created with the same values as this Pair. The values themselves are not
* cloned.
*
* @return a clone of this Pair.
*/
@Override
public Pair<T, U> clone() {
return new Pair<T, U>(object1, object2);
}
/**
* Indicates whether some other object is "equal" to this one.
* This Pair is considered equal to the object if and only if
* <ul>
* <li>the Object argument is not null,
* <li>the Object argument has a runtime type Pair or a subclass,
* </ul>
* AND
* <ul>
* <li>the Object argument refers to this pair
* <li>OR this pair's values are both null and the other pair's values are both null
* <li>OR this pair has one null value and the other pair has one null value and
* the remaining non-null values of both pairs are equal
* <li>OR both pairs have no null values and have value tuples <v1, v2> of
* this pair and <o1, o2> of the other pair so that at least one of the
* following statements is true:
* <ul>
* <li>v1 equals o1 and v2 equals o2
* <li>v1 equals o2 and v2 equals o1
* </ul>
* </ul>
* In any other case (such as when this pair has two null parts but the other
* only one) this method returns false.<p>
* The type parameters that were used for the other pair are of no importance.
* A Pair<T, U> can return <code>true</code> for equality testing with
* a Pair<T, V> even if V is neither a super- nor subtype of U, should
* the the value equality checks be positive or the U and V type values
* are both <code>null</code>. Type erasure for parameter types at compile
* time means that type checks are delegated to calls of the <code>equals</code>
* methods on the values themselves.
*
* @param obj the reference object with which to compare.
* @return true if the object is a Pair equal to this one.
*/
@Override
public boolean equals(Object obj) {
if(obj == null)
return false;
if(this == obj)
return true;
if(!(obj instanceof Pair<?, ?>))
return false;
final Pair<?, ?> otherPair = (Pair<?, ?>)obj;
if(dualNull)
return otherPair.dualNull;
//After this we're sure at least one part in this is not null
if(otherPair.dualNull)
return false;
//After this we're sure at least one part in obj is not null
if(object1Null) {
if(otherPair.object1Null) //Yes: this and other both have non-null part2
return object2.equals(otherPair.object2);
else if(otherPair.object2Null) //Yes: this has non-null part2, other has non-null part1
return object2.equals(otherPair.object1);
else //Remaining case: other has no non-null parts
return false;
} else if(object2Null) {
if(otherPair.object2Null) //Yes: this and other both have non-null part1
return object1.equals(otherPair.object1);
else if(otherPair.object1Null) //Yes: this has non-null part1, other has non-null part2
return object1.equals(otherPair.object2);
else //Remaining case: other has no non-null parts
return false;
} else {
//Transitive and symmetric requirements of equals will make sure
//checking the following cases are sufficient
if(object1.equals(otherPair.object1))
return object2.equals(otherPair.object2);
else if(object1.equals(otherPair.object2))
return object2.equals(otherPair.object1);
else
return false;
}
}
/**
* Returns a hash code value for the pair. This is calculated as the sum
* of the hash codes for the two values, wherein a value that is <code>null</code>
* contributes 0 to the sum. This implementation adheres to the contract for
* <code>hashCode()</code> as specified for <code>Object()</code>. The returned
* value hash code consistently remain the same for multiple invocations
* during an execution of a Java application, unless at least one of the pair
* values has its hash code changed. That would imply information used for
* equals in the changed value(s) has also changed, which would carry that
* change onto this class' <code>equals</code> implementation.
*
* @return a hash code for this Pair.
*/
@Override
public int hashCode() {
int hashCode = object1Null ? 0 : object1.hashCode();
hashCode += (object2Null ? 0 : object2.hashCode());
return hashCode;
}
}
这个实现已经经过了适当的单元测试,并且在Set和Map中的使用已经经过了尝试。
请注意,我并没有要求在公共领域发布这个。这是我为在应用程序中使用而编写的代码,因此如果您打算使用它,请避免直接复制,并在注释和名称上搞得一团糟。明白我的意思吗?
实现Pair with的另一种方法。
Public immutable fields, i.e. simple data structure. Comparable. Simple hash and equals. Simple factory so you don't have to provide the types. e.g. Pair.of("hello", 1); public class Pair<FIRST, SECOND> implements Comparable<Pair<FIRST, SECOND>> { public final FIRST first; public final SECOND second; private Pair(FIRST first, SECOND second) { this.first = first; this.second = second; } public static <FIRST, SECOND> Pair<FIRST, SECOND> of(FIRST first, SECOND second) { return new Pair<FIRST, SECOND>(first, second); } @Override public int compareTo(Pair<FIRST, SECOND> o) { int cmp = compare(first, o.first); return cmp == 0 ? compare(second, o.second) : cmp; } // todo move this to a helper class. private static int compare(Object o1, Object o2) { return o1 == null ? o2 == null ? 0 : -1 : o2 == null ? +1 : ((Comparable) o1).compareTo(o2); } @Override public int hashCode() { return 31 * hashcode(first) + hashcode(second); } // todo move this to a helper class. private static int hashcode(Object o) { return o == null ? 0 : o.hashCode(); } @Override public boolean equals(Object obj) { if (!(obj instanceof Pair)) return false; if (this == obj) return true; return equal(first, ((Pair) obj).first) && equal(second, ((Pair) obj).second); } // todo move this to a helper class. private boolean equal(Object o1, Object o2) { return o1 == null ? o2 == null : (o1 == o2 || o1.equals(o2)); } @Override public String toString() { return "(" + first + ", " + second + ')'; } }
这是Java。您必须使用描述性的类名和字段名创建自己定制的Pair类,不要介意通过编写hashCode()/equals()或一次又一次地实现Comparable来重新发明轮子。
许多人都张贴对代码,可用作地图中的键…如果您试图使用一对作为哈希键(常用习语),请务必查看Guava的Table<R,C,V>: http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table。对于图边,他们给出了下面的用法示例:
Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create();
weightedGraph.put(v1, v2, 4);
weightedGraph.put(v1, v3, 20);
weightedGraph.put(v2, v3, 5);
weightedGraph.row(v1); // returns a Map mapping v2 to 4, v3 to 20
weightedGraph.column(v3); // returns a Map mapping v1 to 20, v2 to 5
Table将两个键映射到一个值,并单独为这两种类型的键提供有效的查找。我已经开始使用这个数据结构,而不是Map<Pair<K1,K2>, V>在我的代码的许多部分。有数组、树和其他用于密集和稀疏使用的实现,可以指定您自己的中间映射类。
JavaFX(与Java 8捆绑在一起)有Pair< A,B >类