Mise en œuvre de l'interface Java comparable? [fermé]


Je ne sais pas comment implémenter une interface comparable dans ma classe complexe. J'ai l'exemple de code suivant que j'utilise pour essayer de le contourner. Je sais que cela devrait être quelque chose comme public double compareTo (Complex o) et quelque chose comme ça mais je ne suis pas si sûr de la façon de le faire. Des suggestions sur la façon dont je vais le mettre en œuvre?:

import java.util.Scanner;

public class Complex implements Cloneable, Comparable {
    private double real;
    private double imag;

    /*
     * public Object clone() throws CloneNotSupportedException { Complex
     * objClone = new Complex(); objClone.setReal(this.real);
     * objClone.setImag(this.imag); return objClone; }
     */

    public Complex(double real, double imag) {
        this.real = real;
        this.imag = imag;
    }

    public Complex(double real) {
        this.real = real;
    }

    public Complex() {

    }

    public void setReal(double real) {
        this.real = real;
    }

    public void setImag(double imag) {
        this.imag = imag;
    }

    public double getReal() {
        return real;
    }

    public double getImag() {
        return imag;
    }

    public void add(Complex num1, Complex num2) {
        this.real = num1.real + num2.real;
        this.imag = num1.imag + num2.imag;

    }

    public Complex subtract(Complex num) {
        Complex a = this;
        double real = a.real - num.real;
        double imag = a.imag - num.imag;
        return new Complex(real, imag);
    }

    public Complex multiply(Complex num) {
        Complex a = this;
        double real = a.real * num.real - a.imag * num.imag;
        double imag = a.real * num.imag + a.imag * num.real;
        return new Complex(real, imag);
    }

    public Complex divide(Complex c1, Complex c2) {
        return new Complex((c1.real * c2.real + c1.imag * c2.imag) / (c2.real * c2.real + c2.imag * c2.imag),
                (c1.imag * c2.real - c1.real * c2.imag) / (c2.real * c2.real + c2.imag * c2.imag));
    }

    public double absolute() {
        return Math.sqrt(real * real + imag * imag);
    }

    public String toString() {
        return this.real + " + " + this.imag + "i";
    }

    @Override
    public Complex clone() throws CloneNotSupportedException {
        super.clone();
        return new Complex(real, imag);
    }

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        System.out.print("Enter the first set of complex numbers respectively: ");
        double a = in.nextDouble();
        double b = in.nextDouble();

        Complex c1 = new Complex(a, b);

        System.out.print("Enter the second set of complex numbers respectively: ");
        double c = in.nextDouble();
        double d = in.nextDouble();

        Complex c2 = new Complex(c, d);

        Complex result = new Complex(c, d);
        result.add(c1, c2);

        System.out.println("(" + a + " + " + b + "i) + (" + c + " + " + d + "i) = " + result.toString());
        System.out.println("(" + a + " + " + b + "i) - (" + c + " + " + d + "i) = " + c1.subtract(c2));
        System.out.println("(" + a + " + " + b + "i) * (" + c + " + " + d + "i) = " + c1.multiply(c2));
        System.out.println("(" + a + " + " + b + "i) / (" + c + " + " + d + "i) = " + result.divide(c1, c2).toString());
        System.out.println("|" + a + " + " + b + "i| = " + c1.absolute());

    }

    public double compareTo(Complex other) {

        return this.getReal() - other.getReal();
    }

}
Author: Mureinik, 2016-03-12

3 answers

Quelques points à noter.

  1. Comme d'autres réponses l'ont noté, vous ne devriez généralement implémenter Comparable que s'il existe un ordre naturel pour les instances de la classe. Comme il n'y a pas d'ordre naturel pour les nombres complexes, vous ne devriez probablement pas implémenter Comparable.

  2. Si vous allez fournir un ordre naturel, vous devez implémenter Comparable<Complex> pour indiquer la comparaison avec d'autres instances de Complex (plutôt que de comparer à d'autres objets).

  3. Un meilleur une alternative à l'implémentation de Comparable consiste à fournir un ou plusieurs objets Comparator pour votre classe qui peuvent être utilisés pour fournir autant d'ordres que vous le souhaitez. Par exemple:

    public class Complex {
        private double real;
        private double imaginary;
    
        public static final Comparator<Complex> COMPARE_BY_REAL =
            Comparator.comparingDouble(Complex::getReal);
    
        public static final Comparator<Complex> COMPARE_BY_IMAGINARY =
            Comparator.comparingDouble(Complex::getImaginary);
    
        public static final Comparator<Complex> COMPARE_BY_MODULUS =
            Comparator.comparingDouble(Complex::getModulus);
    
        private double getModulus() {
            return Math.sqrt(real * real + imaginary * imaginary);
        }
     }
    

, Puis l'utilisateur de la classe peut choisir l'ordre qui fait sens pour l'utiliser:

Optional<Complex> closestToOrigin = complexList.stream().min(Complex::COMPARE_BY_MODULUS);
 1
Author: sprinter, 2016-03-12 14:09:13

Tout d'abord, la méthode compareTo de l'interface Comparator renvoie int, pas double. Deuxièmement, si vous souhaitez comparer deux valeurs doubles dans le comparateur, vous ne devez jamais utiliser a - b pattern. Au lieu de cela, utilisez la méthode prédéfinie Double.compare:

public int compareTo(Complex other) {
    return Double.compare(this.getReal(), other.getReal());
}

Cette méthode gère soigneusement toutes les valeurs spéciales comme -0.0 ou NaN qui ne sont pas très faciles à manipuler manuellement. Notez que des méthodes similaires existent pour d'autres types: Integer.compare, Long.compare et ainsi de suite. Il est préférable de les utiliser.

Bien sûr, il convient de noter qu'il n'y a pas d'ordre naturel pour les nombres complexes. Ici, vous comparez les parties réelles, en ignorant complètement les parties imaginaires.

 2
Author: Tagir Valeev, 2016-03-12 12:23:46

D'un point de vue mathématique, les nombres complexes ne peuvent pas être ordonnés, et en tant que tels ne conviennent pas à la Comparable interface. Pour citer l'article de wikipédia:

Parce que les nombres complexes sont naturellement considérés comme existant sur un plan bidimensionnel, il n'y a pas d'ordre linéaire naturel sur l'ensemble des nombres complexes.
Il n'y a pas d'ordre linéaire sur les nombres complexes compatible avec l'addition et la multiplication. Formellement, nous disons que les nombres complexes ne peuvent pas avoir la structure d'un champ ordonné. En effet, tout carré dans un champ ordonné est au moins 0, mais je2 = -1.

Cela dit, rien ne vous empêche techniquement d'implémenter cette interface. Par exemple, vous pouvez décider que vous triez par la partie réelle en premier et par la partie imaginaire en second. Notez que le contrat de la compareTo la méthode vous oblige à renvoyer un int, pas un double. Aussi, vous devez définir votre classe comme étendant Comparable<Complex> au lieu d'un Comparable brut, donc vous n'avez pas à jouer avec le casting et la vérification du type d'exécution:

@Override
public int compareTo(Complex other) {
    int realCompare = Double.compare(getReal(), other.getReal());
    if (realCompare != 0) {
        return realCompare;
    }
    return = Double.compare(getImag(), other.getImag()); 
}

MODIFIER:
Les améliorations de JDK 8Comparator l'interface permet une implémentation beaucoup plus élégante avec le même comportement:

public int compareTo(Complex other) {
    return Comparator.comparingDouble(Complex::getReal)
                     .thenComparingDouble(Complex::getImag)
                     .compare(this, other);
}
 2
Author: Mureinik, 2016-03-12 12:33:54