关于java:通用对类

Generic pair class

只是尝试这个问题,我在过去的考试试卷中发现,这样我就可以为即将进行的Java考试做准备。

提供用于表示事物对的通用类Pair。 该类应该提供一个构造函数,一个获取该对的第一个成员的方法,一个获取该对的第二个成员的方法,一个用于设置该对的第一个成员的方法,一个用于设置该对的第二个成员的方法。 该类应该针对第一个成员的两个类型进行参数化,并且对于该对的第二个成员进行参数化。

这是这个问题的正确实现吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Pair<firstThing, secondThing>{
   private firstThing first;//first member of pair
   private secondThing second;//second member of pair

   public Pair(firstThing first, secondThing second){
     this.first = first;
     this.second = second;
   }

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

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

   public thing getFirst() {
     return this.first;
   }

   public thing getSecond() {
     return this.second;
   }
}


几乎。我写的是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Pair<F, S> {
    private F first; //first member of pair
    private S second; //second member of pair

    public Pair(F first, S second) {
        this.first = first;
        this.second = second;
    }

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

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

    public F getFirst() {
        return first;
    }

    public S getSecond() {
        return second;
    }
}

编辑:我同意@ karmakaze的评论。代码应跳过setter并进行第一和第二次final以使其保持不变。


对类的需求通常会出现在更大的项目中 - 我即将(重新)为当前项目实现一个(因为以前的实现是不可访问的)。

通常我将它变成一个不可变的POJO,具有创建实例的便利功能。例如:

1
2
3
4
5
6
public class Pair<T,U>
{
    public final T first;
    public final U second;
    public static <T,U> Pair<T,U> of(T first, U second);
}

这样最终用户就可以写:

1
return Pair.of (a, b);

1
2
3
Pair<A,B> p = someThing ();
doSomething (p.first);
doSomethingElse (p.second);

如上所述,Pair类还应该实现hashCode(),equals(),optional-but-useful toString(),可能是clone()和compareTo(),用于T和U支持的地方 - 尽管额外的工作需要描述Pair类如何支持这些契约。


这是Android SDK的一个实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
 * Container to ease passing around a tuple of two objects. This object provides a sensible
 * implementation of equals(), returning true if equals() is true on each of the contained
 * objects.
 */

public class Pair<F, S> {
    public final F first;
    public final S second;

    /**
     * Constructor for a Pair.
     *
     * @param first the first object in the Pair
     * @param second the second object in the pair
     */

    public Pair(F first, S second) {
        this.first = first;
        this.second = second;
    }

    /**
     * Checks the two objects for equality by delegating to their respective
     * {@link Object#equals(Object)} methods.
     *
     * @param o the {@link Pair} to which this one is to be checked for equality
     * @return true if the underlying objects of the Pair are both considered
     *         equal
     */

    @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);
    }

    /**
     * Compute a hash code using the hash codes of the underlying objects
     *
     * @return a hashcode of the Pair
     */

    @Override
    public int hashCode() {
        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
    }

    /**
     * Convenience method for creating an appropriately typed pair.
     * @param a the first object in the Pair
     * @param b the second object in the pair
     * @return a Pair that is templatized with the types of a and b
     */

    public static <A, B> Pair <A, B> create(A a, B b) {
        return new Pair<A, B>(a, b);
    }
}


您可以查看标准Java类AbstractMap.SimpleEntry和AbstractMap.SimpleImmutableEntry的实现。 google来源非常简单:

  • http://www.docjar.com/html/api/java/util/AbstractMap.java.html
  • http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/AbstractMap.java


我想没有。引用:

"the class should be parameterised
over two types..."

我认为他们期望:

1
public class Pair<ThingA, ThingB>


编辑后,它看起来不错。

但是,您确实应该实现hashCodeequals方法,以便包含相同对象的两对将彼此相等,并且可以在HashMap中用作键。 toString如果你感觉很慷慨。这些方法不需要满足您给出的要求,但它们是优秀程序员可以添加的东西。


吸气剂坏了

1
2
3
4
5
6
7
public thing getFirst() {
  return thing.first;
}

public thing getSecond() {
  return thing.second;
}

thing应替换为this


通常,通用Pair类型有两个泛型类型参数,而不是一个 - 所以你可以有(比方说)一个Pair。这通常更有用,IMO。

我还建议您考虑类型参数比"事物"更常规的名称。例如,您可以使用PairPair


Apache Commons Lang有一个通用的对实现

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


不,您是否尝试过编码以确定它是否有效?

您似乎错过了这部分要求:

The class should be parameterised over two types one for the first member and one for the second member of the pair.

这意味着该类应该被定义为更像:

public class Pair

其他方法也相应更新。 (顺便说一下,我已经使用T1和T2来引用类型,按惯例,使用短 - 1或2个char - 标识符)。

也,

return thing.first;

return thing.second;

不会像在你的例子中那样工作,thing是一个类型,而不是一个对象。想想你想要回到这里。你甚至需要打电话给方法吗?

完成更改后,对其进行编码,然后编写单元测试或简单的测试工具来检查它是否有效。


The class should be parameterised over two types one for the first member and one for the second member of the pair.

您只有一个参数。

你需要像Pair这样的东西,并使用F,你首先使用thing,然后使用thing作为秒。


我实现了类似的东西,但使用静态构建器和链式setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class Pair<R, L> {

private R left;
private L right;

public static <K,V> Pair<K, V> of(K k, V v) {
    return new Pair<K,V>(k, v);
}

public Pair() {}

public Pair(R key, L value) {
    this.left(key);
    this.right(value);
}

public R left() {
    return left;
}

public Pair<R, L> left(R key) {
    this.left = key;
    return this;
}

public L right() {
    return right;
}

public Pair<R, L> right(L value) {
    this.right = value;
    return this;
}
}

我的双版本。这也处理比较。
PS:大部分代码都来自AOSP。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package util;

import java.util.Objects;

public class Pair<F extends Comparable<F>, S extends Comparable>
  implements Comparable<Pair<F, S>> {

    public final F first;
    public final S second;

    /**
     * Constructor for a Pair.
     *
     * @param first  the first object in the Pair
     * @param second the second object in the pair
     */

    public Pair(F first, S second) {
        this.first = first;
        this.second = second;
    }

    /**
     * Checks the two objects for equality by delegating to their respective
     * {@link Object#equals(Object)} methods.
     *
     * @param o the {@link Pair} to which this one is to be checked for equality
     * @return true if the underlying objects of the Pair are both considered
     * equal
     */

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Pair)) {
            return false;
        }
        Pair<?, ?> p = (Pair<?, ?>) o;
        return Objects.equals(p.first, first) && Objects.equals(p.second, second);
    }

    /**
     * Compute a hash code using the hash codes of the underlying objects
     *
     * @return a hashcode of the Pair
     */

    @Override
    public int hashCode() {
        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
    }

    /**
     * Convenience method for creating an appropriately typed pair.
     *
     * @param a the first object in the Pair
     * @param b the second object in the pair
     * @return a Pair that is templatized with the types of a and b
     */

    public static <A extends Comparable<A>, B extends Comparable> Pair<A, B> create(A a, B b) {
        return new Pair<>(a, b);
    }

    @Override
    public int compareTo(Pair<F, S> that) {
        int cmp = this.first.compareTo(that.first);
        if (cmp == 0)
            cmp = this.second.compareTo(that.second);
        return cmp;
    }
}

thing是一个非常规符号的类型变量 - 我们通常使用一个大写的后者(如T)。然后:一个类型变量没有任何方法,所以你的getter不会编译。

快速改进:用T替换所有thing

快速修复getter:

1
2
3
4
5
6
7
public T getFirst() {
 return first;
}

public T getSecond() {
 return second;
}

一个要求是允许两对不同类型的成员。所以类签名应如下所示:

1
2
3
4
5
public Pair<S,T> {
  private S first;
  private T second;
  //...
}