Generic pair class

送分小仙女□ 提交于 2019-11-27 08:56:17

Almost. I'd write it like this:

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

Edit: I agree with @karmakaze's comment. The code should skip the setters and make first and second final to keep it immutable.

simon.watts

The need for a Pair class usually crops up in larger projects - I'm about to (re)implement one for the current project (as previous implementations are not accessible).

Generally I make it an immutable POJO, with a convenience function to create instances. For example:

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

So that the end-user can write:

return Pair.of (a, b);

and

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

As mentioned above, the Pair class should also implement hashCode(), equals(), optional-but-useful toString(), as possibly clone() and compareTo() for use where these are supported by T and U - though extra work is required to describe how these contracts are supported by the Pair class.

Here is an implementation from the Android SDK

/**
 * 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);
    }
}

I think No. Quote:

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

I think they are expecting in terms of :

public class Pair<ThingA, ThingB>

Usually a generic Pair type has two generic type parameters, not one - so you could have (say) a Pair<String, Integer>. That's typically more useful, IMO.

I would also suggest that you think about a more conventional name for your type parameter than "thing". For example, you might use Pair<A, B> or Pair<T, U>.

Getters are broken

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

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

thing should be replaced with this

After editing, it looks good.

However, you really should implement the hashCode and equals methods, so that two pairs containing the same objects will be equal to each other, and can be used as keys in a HashMap. And toString if you're feeling generous. These methods are not required to fulfil the requirements you've been given, but they are things a good programmer would add.

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

You have only one parameter.

you need something like Pair<F,S> and use F where you use thing for first and S where thing for second.

No. Have you tried coding it to see if it works?

You seem to have missed this part of the requirement:

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

Which means the class should probably be defined as something more like:

public class Pair<T1, T2>

and the other methods updated accordingly. (By the way, I've used T1 and T2 to refer to the types as by convention a short - 1 or 2 char - identifier is used).

Also,

return thing.first;

and

return thing.second;

are not going to work, as in your example, thing is a type, not an object. Think about what you want to return here. Do you even need to call a method?

Once you've made your changes, code it and either write a unit test or a simple test-harness to check if it works.

thing is a Type Variable in an unsual notation - we usually use one uppercase latter (like T). Then: a type variable does not have any methods, so your getters won't compile.

Quick improvement: replace all thing with T

Quick fix for getters:

public T getFirst() {
 return first;
}

public T getSecond() {
 return second;
}

One requirement was to allow two different types for the pair members. So the class signature should look like:

public Pair<S,T> {
  private S first;
  private T second;
  //...
}
Brajesh Kumar

My version of Pair. This also handles compares. PS : Most of the code is taken from AOSP.

package util;

import java.util.Objects;

public class Pair<F extends Comparable<F>, S extends Comparable<S>>
  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<B>> 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;
    }
}

I implemented something similar but with static builder and chained setters

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;
}
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!