En essayant simplement cette question, je l'ai trouvée dans un examen antérieur afin de me préparer à un prochain examen Java.
Fournissez une paire de classe générique pour représenter des paires d'objets. La classe devrait fournir un constructeur, une méthode pour obtenir le premier membre de la paire, une méthode pour obtenir le deuxième membre de la paire, une méthode pour définir le premier membre de la paire, une méthode pour définir le deuxième membre de la paire . La classe doit être paramétrée sur deux types, un pour le premier membre et un pour le second membre de la paire.
Est-ce une implémentation correcte pour cette question?
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;
}
}
Presque. J'écrirais ça comme ça:
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: Je suis d'accord avec le commentaire de @ karmakaze. Le code doit ignorer les setters et faire les première et deuxième finales pour le garder immuable.
La nécessité d'une classe Pair apparait généralement dans les projets plus importants - je suis sur le point d'en (ré) implémenter une pour le projet actuel (car les implémentations précédentes ne sont pas accessibles).
En général, j'en fais un POJO immuable, avec une fonction de commodité pour créer des instances. Par exemple:
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);
}
Pour que l'utilisateur final puisse écrire:
return Pair.of (a, b);
et
Pair<A,B> p = someThing ();
doSomething (p.first);
doSomethingElse (p.second);
Comme mentionné ci-dessus, la classe Pair devrait également implémenter hashCode (), equals (), toString () facultatif mais utile, comme éventuellement clone () et compareTo () pour une utilisation lorsque ceux-ci sont pris en charge par T et U - bien que des efforts supplémentaires soient nécessaires est nécessaire pour décrire comment ces contrats sont pris en charge par la classe Pair.
Voici une implémentation du SDK Android
/**
* 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);
}
}
Vous pouvez rechercher une implémentation de classes Java standard AbstractMap.SimpleEntry et AbstractMap.SimpleImmutableEntry . Il est assez facile de rechercher des sources dans Google:
Je pense non. Quote:
"la classe devrait être paramétrée sur deux types ..."
Je pense qu'ils attendent en termes de:
public class Pair<ThingA, ThingB>
Après montage, ça a l'air bien.
Cependant, vous devez réellement implémenter les méthodes hashCode
et equals
, de sorte que deux paires contenant les mêmes objets soient égales, et puissent être utilisées comme clés dans un HashMap. Et toString
si vous vous sentez généreux. Ces méthodes ne sont pas nécessaires pour répondre aux exigences qui vous ont été données, mais ce sont les choses qu'un bon programmeur ajouterait.
Généralement, un type de paire générique a deux paramètres de type générique, pas un - vous pouvez donc avoir (par exemple) un Pair<String, Integer>
. C'est généralement plus utile, OMI.
Je suggérerais également que vous pensiez à un nom plus conventionnel pour votre paramètre de type que "chose". Par exemple, vous pouvez utiliser Pair<A, B>
ou Pair<T, U>
.
Les Getters sont cassés
public thing getFirst() {
return thing.first;
}
public thing getSecond() {
return thing.second;
}
thing
devrait être remplacé par this
La classe doit être paramétrée sur deux types, un pour le premier membre et un pour le second membre de la paire.
Vous avez un seul paramètre.
vous avez besoin de quelque chose comme Pair<F,S>
et utilisez F où vous utilisez thing
pour premier et S où thing
pour second.
Apache Commons Lang a une implémentation de paire générique
https://commons.Apache.org/proper/commons-lang/apidocs/org/Apache/commons/lang3/Tuple/Pair.html
Avez-vous essayé de le coder pour voir si cela fonctionne?
Vous semblez avoir manqué cette partie de l'exigence:
La classe doit être paramétrée sur deux types, un pour le premier membre et un pour le second membre de la paire.
Ce qui signifie que la classe devrait probablement être définie comme quelque chose de plus semblable à:
public class Pair<T1, T2>
et les autres méthodes mises à jour en conséquence. (A propos, j'ai utilisé T1 et T2 pour faire référence aux types car, par convention, un identifiant court - 1 ou 2 caractères est utilisé).
Également,
return thing.first;
et
return thing.second;
ne vont pas fonctionner, comme dans votre exemple, thing
est un type, pas un objet. Pensez à ce que vous voulez retourner ici. Avez-vous même besoin d'appeler une méthode?
Une fois vos modifications effectuées, codez-les et écrivez un test unitaire ou un simple harnais de tests pour vérifier son fonctionnement.
thing
est un Variable de type dans une notation inhabituelle - nous utilisons généralement une dernière lettre majuscule (comme T
). Ensuite: une variable de type n'a pas de méthode, donc vos accesseurs ne compileront pas.
Amélioration rapide: remplace tout thing
par T
Solution rapide pour les getters:
public T getFirst() {
return first;
}
public T getSecond() {
return second;
}
L'une des conditions était de permettre deux types différents pour les membres de la paire. Donc, la signature de classe devrait ressembler à:
public Pair<S,T> {
private S first;
private T second;
//...
}
J'ai implémenté quelque chose de similaire mais avec un générateur statique et des setters chaînés
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;
}
}
Ma version de Pair. Cela gère également compare. PS: La plupart du code provient de 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;
}
}