Java中的C ++ Pair <L,R>等效项是什么?


670

是否有充分的理由说明为什么Pair<L,R>Java中没有?这个C ++结构相当于什么?我宁愿避免重新实现自己的。

似乎1.6提供了类似的内容(AbstractMap.SimpleEntry<K,V>),但这看起来有些令人费解。


7
为什么令人AbstractMap.SimpleEntry费解?
CurtainDog 2012年

27
由于namig,任意命名一个键和一个值。
Enerccio 2014年


2
@sffc JavaFX不在JDK7中的任何默认类路径上,使用它需要手动添加JFX运行时库。
Cord Rehn

3
@Enerccio:所以,您实际上声明“第一”和“第二”不是任意的,而“键”和“值”-是吗?这是在SDK中没有此类的一个很好的理由。关于“正确的”命名将存在永恒的争议。
fdreger

Answers:


400

的线程中comp.lang.java.help,Hunter Gratzner提出了一些反对PairJava中存在构造的参数。主要论点是,一个类Pair没有传达关于两个值之间关系的任何语义(您如何知道“第一”和“第二”的含义?)。

更好的做法是为您将要为该类编写的每个应用程序编写一个非常简单的类,如Mike提出的那样PairMap.Entry是一对在其名称中带有其含义的示例。

总而言之,在我看来,最好有一个类Position(x,y),一个类Range(begin,end)和一个类,Entry(key,value)而不是一个Pair(first,second)不告诉我有关它应该做什么的通用类。


143
格拉茨纳正在分裂头发。我们很高兴将单个值作为原始或内置类返回,而无需将其封装在类中。如果我们要返回一个包含十二个元素的元组,没有人会不同意它应该有自己的类。中间的某个地方是(模糊的)分界线。我认为我们的蜥蜴大脑可以轻松应付配对。
伊恩

25
我同意伊恩。Java让您返回int;它不会强制您每次使用int时都为int创建别名。结对差别不大。
克莱门特

5
如果我们可以直接将一对解压缩到您的局部变量,或者将其转发到带有两个参数的方法,则Pair将是一个有用的类。由于我们无法像这样解压,因此创建一个有意义的类并将这些值保持在一起看起来并不算太糟糕。而且,如果您确实想要一对,尽管有一些限制,总会有Object [2] + casts :-)
marcus

问题是,如果您不同意Gratzner,那么在多个地方都可以使用Pair实现。Apache Commons和Guava都有IIRC。使用那些。但是,将某些内容放入主要的Java库中意味着这是一种高尚的,被认可的做事方式(大写),并且由于人们不同意,所以我们不应该将其放在那儿。原来的库中有足够的存储空间,不要不必要地在其中存储更多内容。
HaakonLøtveit'17

1
@Dragas当我需要一对值时,那不是Java ...严重吗?
idclev 463035818

156

这是Java。您必须使用描述性的类和字段名称来制作自己的量身定制的Pair类,并且不要介意通过编写hashCode()/ equals()或一次又一次地实现Comparable来重新发明轮子。


61
那没有回答“为什么”的问题。(除非您认为“这是Java”是一个答案)
Nikita Rybak

127
+1用于嘲笑Java的详细信息。-1表示未实际回答问题。
Bennett McElwee

19
如果您已经指出了包含对类的Apache Commong Lang,那么Java模拟就可以了。
haylem 2012年

6
或者您也可以使用SimpleImmutableEntry
CurtainDog 2012年

33
第一句回答“为什么?”的问题。这是Java,仅此而已。
masterziv 2012年

103

HashMap兼容的Pair类:

public class Pair<A, B> {
    private A first;
    private B second;

    public Pair(A first, B second) {
        super();
        this.first = first;
        this.second = second;
    }

    public int hashCode() {
        int hashFirst = first != null ? first.hashCode() : 0;
        int hashSecond = second != null ? second.hashCode() : 0;

        return (hashFirst + hashSecond) * hashSecond + hashFirst;
    }

    public boolean equals(Object other) {
        if (other instanceof Pair) {
            Pair otherPair = (Pair) other;
            return 
            ((  this.first == otherPair.first ||
                ( this.first != null && otherPair.first != null &&
                  this.first.equals(otherPair.first))) &&
             (  this.second == otherPair.second ||
                ( this.second != null && otherPair.second != null &&
                  this.second.equals(otherPair.second))) );
        }

        return false;
    }

    public String toString()
    { 
           return "(" + first + ", " + second + ")"; 
    }

    public A getFirst() {
        return first;
    }

    public void setFirst(A first) {
        this.first = first;
    }

    public B getSecond() {
        return second;
    }

    public void setSecond(B second) {
        this.second = second;
    }
}

136
您可能想要删除二传手,并使其成为第一和第二决赛,从而使该对保持不变。(如果有人在将它们用作哈希键之后更改了这些组件,将会发生奇怪的事情)。
Thilo

21
在toString()方法中返回“(” + first.toString()+“,” + second.toString()+“)”可能会引发NullPointerExceptions。更好:返回“(” + first +“,” + second +“)”;
JuhaSyrjälä09年

6
另外,将这对标记为“最终”,或将等于的第一行更改为“ if(other!= null && this.getClass()== other.getClass())”
sargas

8
很抱歉出现随机nooby问题,但是为什么要在构造函数中调用super()?
Ibrahim 2010年

6
@易卜拉欣:在这种情况下,这是多余的-如果取super()出来,其行为是完全相同的。通常,如果它是可选的,我会把它关闭,就像在这里一样。
克里斯·杰斯特·杨

53

使用Lombok,我可以想到的最短的一对是:

@Data
@AllArgsConstructor(staticName = "of")
public class Pair<F, S> {
    private F first;
    private S second;
}

它具有的所有优点的答案从@arturh(可比性除外),它有hashCodeequalstoString和静态的“构造”。


好漂亮!喜欢它!
Ahmet Ipkin '18


31

实现配对的另一种方法。

  • 公共不可变字段,即简单的数据结构。
  • 可比。
  • 简单的哈希和等于。
  • 简单的工厂,因此您不必提供类型。例如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 + ')';
        }
    }

10
我喜欢静态工厂方法of。它使人想起了Google Guava不可变的集合。
JarekPrzygódzki2011年

7
尽管没有迹象表明它将实际实现该接口,但您在某个时候将其转换o1Comparable。如果需要,则FIRST类型参数应为FIRST extends Comparable<?>
2011年

我不是Java的人,所以请原谅我的无知,但是您在TODO注释中想到了哪种帮助程序类?

3
31对于hashCode是错误的常数。例如,如果将由Pair <Integer,Integer>键控的HashMap用于2D地图,则将发生许多碰撞。例如(a * 65497)^ b会更适合。
米哈尔·杰林斯基

1
@MarioCarneiro ^是异或,不是权力
米哈尔杰林斯基

27

如何http://www.javatuples.org/index.html我发现它是非常有用的。

javatuples为您提供了从一到十个元素的元组类:

Unit<A> (1 element)
Pair<A,B> (2 elements)
Triplet<A,B,C> (3 elements)
Quartet<A,B,C,D> (4 elements)
Quintet<A,B,C,D,E> (5 elements)
Sextet<A,B,C,D,E,F> (6 elements)
Septet<A,B,C,D,E,F,G> (7 elements)
Octet<A,B,C,D,E,F,G,H> (8 elements)
Ennead<A,B,C,D,E,F,G,H,I> (9 elements)
Decade<A,B,C,D,E,F,G,H,I,J> (10 elements)

6
很有趣,但是至少有5个类比我想象的要多。
maaartinus 2012年

3
@maaartinus至少比我要使用的多十倍。
Boann 2014年

7
@Boann:好的,我保持纠正。我曾经使用过,Pair并且可以想象Triplet每50年使用一次。现在,我使用Lombok并在每次需要配对时创建一个很小的4行类。因此,“ 10太多”是正确的。
maaartinus 2014年

5
我们需要Bottom (0 element)上课吗?:)
Earth

2
哇,这很丑。我知道他们正在尝试使它明确,但是像C#这样具有重载参数的元组会更好。
arviman

12

这取决于您要使用它的目的。这样做的典型原因是遍历地图,您只需为此进行操作(Java 5+):

Map<String, Object> map = ... ; // just an example
for (Map.Entry<String, Object> entry : map.entrySet()) {
  System.out.printf("%s -> %s\n", entry.getKey(), entry.getValue());
}

1
我不确定自定义类在这种情况下是否会有所帮助:)
Nikita Rybak

31
“这样做的典型原因是遍历地图”。真?
Bennett McElwee

12

android提供Pair类(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);
    }
}

1
Objects.equal(..)需要Guava库。
Markus L'

3
Objects.equals(...)其更改为自2011年以来在Java中使用的版本(1.7)。
AndrewF

9

最大的问题可能是无法确保A和B的不变性(请参阅如何确保类型参数不变),因此hashCode()例如插入集合中,同一对的结果可能不一致(这会产生不确定的行为) ,请参见根据可变字段定义等式)。对于特定(非通用)对类,程序员可以通过仔细选择A和B为不可变来确保不可变。

无论如何,从@PeterLawrey的答案(java 1.7)中清除通用警告:

public class Pair<A extends Comparable<? super A>,
                    B extends Comparable<? super B>>
        implements Comparable<Pair<A, B>> {

    public final A first;
    public final B second;

    private Pair(A first, B second) {
        this.first = first;
        this.second = second;
    }

    public static <A extends Comparable<? super A>,
                    B extends Comparable<? super B>>
            Pair<A, B> of(A first, B second) {
        return new Pair<A, B>(first, second);
    }

    @Override
    public int compareTo(Pair<A, B> o) {
        int cmp = o == null ? 1 : (this.first).compareTo(o.first);
        return cmp == 0 ? (this.second).compareTo(o.second) : cmp;
    }

    @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 == o2 || (o1 != null && o1.equals(o2));
    }

    @Override
    public String toString() {
        return "(" + first + ", " + second + ')';
    }
}

非常欢迎您进行添加/更正:)特别是对于使用,我不太确定Pair<?, ?>

有关为何使用此语法的更多信息,请参见确保对象实现Comparable,并获得详细说明如何max(Comparable a, Comparable b)在Java中实现泛型函数?


由于Java Integers是32位,第一个哈希码乘以31会不会导致溢出?执行“异或”会更好吗?

@ Dan随时编辑,我离开了Java :)
Mr_and_Mrs_D

5

我认为Java中没有对,因为如果您想直接在对上添加额外的功能(例如Comparable),则必须绑定类型。在C ++中,我们根本不在乎,如果组成一对的类型不具有operator <,那么它们pair::operator <也不会编译。

无边界可比的示例:

public class Pair<F, S> implements Comparable<Pair<? extends F, ? extends S>> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair<? extends F, ? extends S> that) {
        int cf = compare(first, that.first);
        return cf == 0 ? compare(second, that.second) : cf;
    }
    //Why null is decided to be less than everything?
    private static int compare(Object l, Object r) {
        if (l == null) {
            return r == null ? 0 : -1;
        } else {
            return r == null ? 1 : ((Comparable) (l)).compareTo(r);
        }
    }
}

/* ... */

Pair<Thread, HashMap<String, Integer>> a = /* ... */;
Pair<Thread, HashMap<String, Integer>> b = /* ... */;
//Runtime error here instead of compile error!
System.out.println(a.compareTo(b));

比较类型与编译时检查类型参数是否可比的示例:

public class Pair<
        F extends Comparable<? super F>, 
        S extends Comparable<? super S>
> implements Comparable<Pair<? extends F, ? extends S>> {
    public final F first;
    public final S second;
    /* ... */
    public int compareTo(Pair<? extends F, ? extends S> that) {
        int cf = compare(first, that.first);
        return cf == 0 ? compare(second, that.second) : cf;
    }
    //Why null is decided to be less than everything?
    private static <
            T extends Comparable<? super T>
    > int compare(T l, T r) {
        if (l == null) {
            return r == null ? 0 : -1;
        } else {
            return r == null ? 1 : l.compareTo(r);
        }
    }
}

/* ... */

//Will not compile because Thread is not Comparable<? super Thread>
Pair<Thread, HashMap<String, Integer>> a = /* ... */;
Pair<Thread, HashMap<String, Integer>> b = /* ... */;
System.out.println(a.compareTo(b));

很好,但是这一次您可能不能在Pair中将不可比较的类型用作类型参数。在某些实用工具类中,可能会为Pair使用很多Comparators,但C ++人士可能无法使用它。另一种方法是在类型层次结构中编写许多类,对类型实参使用不同的界限,但是可能的界限及其组合太多了。


5

JavaFX(与Java 8捆绑在一起)具有Pair <A,B>类


1
javafx.util.Pair中hashCode实现可能导致琐碎的冲突。在HashMap / HashTable中使用它仍然可以正常工作,因为Java除了检查哈希码之外还检查值的相等性,但这是需要注意的。
sffc 2015年

这是一个非常标准且通常推荐的hashCode实现。任何调用的代码都应该发生冲突hashCode()。请注意,Java本身不调用此方法。它用于用户代码,包括库。
AndrewF

5

正如许多其他人已经指出的那样,Pair类是否有用真的取决于用例。

我认为,对于私有帮助器函数,使用Pair类完全合法,如果这可以使您的代码更具可读性,并且不值得花所有的样板代码创建另一个值类。

另一方面,如果您的抽象级别要求您清楚地记录包含两个对象或值的类的语义,则应为其编写一个类。如果数据是业务对象,通常就是这种情况。

与往常一样,它需要熟练的判断。

对于第二个问题,我建议使用Apache Commons库中的Pair类。这些可能被视为Java的扩展标准库:

https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/tuple/Pair.html

您可能还想看看Apache Commons的EqualsBuilderHashCodeBuilderToStringBuilder,它们简化了为业务对象编写值类的过程。


更新的URL为commons.apache.org/lang/api-release/index.html?org/apache/…,因为commons-lang3不在beta版本。这比我自己的龙目岛的解决方案更短,如果你已经使用commons-郎3
迈克尔Piefel


5

好消息JavaFX具有关键价值。

只需将javafx添加为依赖项并导入javafx.util.Pair

并像中一样简单地使用c++

Pair <Key, Value> 

例如

Pair <Integer, Integer> pr = new Pair<Integer, Integer>()

pr.get(key);// will return corresponding value

坏消息是,并非每个人都使用的JavaFX
米哈尔DOBI多布然斯基



3

根据Java语言的性质,我认为人们实际上并不需要Pair,通常是他们需要的接口。这是一个例子:

interface Pair<L, R> {
    public L getL();
    public R getR();
}

因此,当人们想要返回两个值时,他们可以执行以下操作:

... //Calcuate the return value
final Integer v1 = result1;
final String v2 = result2;
return new Pair<Integer, String>(){
    Integer getL(){ return v1; }
    String getR(){ return v2; }
}

这是一个非常轻巧的解决方案,它回答了“ a的语义是Pair<L,R>什么?”的问题。答案是,这是具有两个(可能不同)类型的接口构建,并且具有返回每个类型的方法。您可以根据需要添加更多的语义。例如,如果您使用的是Position,并且确实要在代码中指出该位置,则可以定义PositionXPositionY包含Integer来组成一个Pair<PositionX,PositionY>。如果有JSR 308,您也可以使用Pair<@PositionX Integer, @PositionY Ingeger>来简化。

编辑:我应该在这里指出的一件事是,上面的定义明确地将类型参数名称和方法名称相关。这是对那些认为Pair缺乏语义信息的论点的答案。实际上,该方法的getL意思是“给我与类型参数L的类型相对应的元素”,这确实意味着一些。

编辑:这是一个简单的实用程序类,可以使生活更轻松:

class Pairs {
    static <L,R> Pair<L,R> makePair(final L l, final R r){
        return new Pair<L,R>(){
            public L getL() { return l; }
            public R getR() { return r; }   
        };
    }
}

用法:

return Pairs.makePair(new Integer(100), "123");

怎么样equalshashCodetoString
sdgfsdh

好吧,这只是一个最小的实现。如果您需要的还不止这些,可以编写一些帮助器函数以使其变得更容易,但仍然需要编写代码。
Earth Engine

要实施,toString您需要有关两个字段之间关系的更多知识。
Earth Engine

我的观点是,提供a class可能比仅仅提供一个更好,interface因为它可以实现这些事情。
sdgfsdh

3

尽管在语法上相似,但是Java和C ++具有非常不同的范例。像Java一样写C ++就是不好的C ++,而像C ++那样写Java就是不好的Java。

使用像Eclipse这样的基于反射的IDE,编写“ pair”类的必要功能既快捷又简单。创建课程,定义两个字段,使用各种“ Generate XX”菜单选项在几秒钟内填写课程。如果您想要Comparable接口,也许您必须快速输入一个“ compareTo”。

在C ++语言生成器中使用单独的声明/定义选项并不是那么好,因此,手写小的实用程序类会更加耗时。因为这对是一个模板,所以您不必为不使用的功能付费,并且typedef工具允许为代码分配有意义的类型名,因此对“无语义”的反对​​并没有真正成立。


2

Pair是一个好东西,成为复杂泛型的基本构造单元,例如,这是从我的代码中得出的:

WeakHashMap<Pair<String, String>, String> map = ...

它与Haskell的元组相同


1
现在我可以说,使用Pair <A,B>可以使代码的信息更少,而使用特殊对象代替使用Pair则要好得多
Illarion Kovalchuk 2010年

1
更好或更差。假设您有一个函数将其两个参数组合在一起(例如,将图形合并为一个),并且需要对其进行缓存。这里,Pair因为没有特殊的语义,所以是最佳的。为一个清晰的概念取一个清晰的名字是好事,但寻找一个“第一”和“第二”效果很好的名字却不是。
maaartinus 2012年

2

Object []的简单方法-可以用作尺寸元组


2
任何尺寸,是的。但是:创建起来很麻烦,而且不是类型安全的。
Michael Piefel 2011年

2

对于Java之类的编程语言,大多数程序员用来表示类似数据对的替代数据结构是两个数组,并且可以通过相同的索引访问数据

示例:http//www-igm.univ-mlv.fr/~lecroq/string/node8.html#SECTION0080

这不是理想的选择,因为应该将数据绑定在一起,但结果却很便宜。另外,如果您的用例需要存储坐标,则最好构建自己的数据结构。

我的图书馆里有这样的东西

public class Pair<First,Second>{.. }


2

为了方便起见,以下是一些具有多个元组度的库:

  • JavaTuples。1-10级的元组就足够了。
  • JavaSlang。0-8度的元组和许多其他功能的东西。
  • jOOλ。0-16度的元组和其他一些功能特性。(免责声明,我在维护公司工作)
  • 功能性Java。0-8度的元组和许多其他功能的东西。

已经提到其他库至少包含Pair元组。

具体来说,在使用大量结构化类型而不是名义上的类型(如公认的答案中所主张)的函数式编程的上下文中,这些库及其元组非常有用。




1

我注意到所有对实现都散布在这里,这意味着两个值的顺序相同。当我想到一对时,我想到的是两个项目的组合,其中两个项目的顺序并不重要。这是我对无序对的实现,带有hashCodeequals重写以确保集合中所需的行为。也可以克隆。

/**
 * 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&lt;T, U> can still return <code>true</code> for method <code>equals</code>
 * called with a Pair&lt;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&lt;T, U&gt;</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 &lt;v1, v2> of
     * this pair and &lt;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&lt;T, U> can return <code>true</code> for equality testing with
     * a Pair&lt;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 and Map中进行了尝试。

请注意,我并没有声称要在公共领域中发布它。这是我刚刚编写的用于应用程序的代码,因此,如果要使用它,请不要直接复制,也不要乱写注释和名称。赶上我的漂移?


3
实际上,请检查每个页面的底部:“ cc-wiki许可的用户贡献”
amara

啊,我没注意到。感谢您的单挑。在这种情况下,请使用您认为合适的代码。
2011年

1
问题是关于C ++等效对-是有序的。我还认为,只要引用了Pair对象,并且它们是可变的,就可以将Pairs插入集合中,这可能导致未定义的行为。
Mr_and_Mrs_D 2012年


1

com.sun.tools.javac.util.Pair是一对的简单实现。可以在jdk1.7.0_51 \ lib \ tools.jar中找到。

除了org.apache.commons.lang3.tuple.Pair之外,它还不仅仅是一个接口。


2
但是,没有人应该使用JDK内部API。
jpangamarca

0
public class Pair<K, V> {

    private final K element0;
    private final V element1;

    public static <K, V> Pair<K, V> createPair(K key, V value) {
        return new Pair<K, V>(key, value);
    }

    public Pair(K element0, V element1) {
        this.element0 = element0;
        this.element1 = element1;
    }

    public K getElement0() {
        return element0;
    }

    public V getElement1() {
        return element1;
    }

}

用法:

Pair<Integer, String> pair = Pair.createPair(1, "test");
pair.getElement0();
pair.getElement1();

一成不变,只有一对!


哦,哇 另一个?尝试将其与更复杂的泛型一起使用-在某些时候,它将无法推断出适当的类型。另外,应该有以下可能:Pair<Object, Object> pair = Pair.createPair("abc", "def")但是我想一个需要Pair.createPair((Object)"abc", (Object)"def")用您的代码编写吗?
退出了–Anony-Mousse 2011年

您可以用以下方法代替静态方法: @SuppressWarnings("unchecked") public static <K, V, X, Y> Pair<X, Y> createPair(K key, V value) { return new Pair<X, Y>((X) key, (Y) value); } 但我不知道这是否是一个好习惯
Bastiflew 2011年

不,那只会使事情变得更糟。以我的经验,至少有一个编译器(尝试使用java6,java7,javadoc和eclipse java编译器)会抱怨。new Pair<Object, Object>("abc", "def")在我的实验中,传统是最可靠的。
已退出-Anony-Mousse 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.