实现Java可比较的接口?

时间:2016-03-12 12:13:46

标签: java interface comparable complex-numbers

我不确定如何在我的复杂类中实现类似的接口。我有以下示例代码,我正在尝试并试图解决它。我知道它应该像public double compareTo (Complex o)这样的东西,但我不太确定如何做到这一点。关于我将如何实施它的任何建议?:

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

}

3 个答案:

答案 0 :(得分:2)

首先,compareTo接口的Comparator方法返回int,而不是double。其次,如果要比较Comparator中的两个double值,则不应使用a - b模式。相反,请使用预定义的Double.compare方法:

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

此方法会仔细处理所有特殊值,例如-0.0NaN,这些值不易手动处理。请注意,其他类型也存在类似的方法:Integer.compareLong.compare等。它最好使用它们。

当然应该注意的是,对于复数而言,没有自然顺序。在这里,您只需比较实际部分,完全忽略虚部。

答案 1 :(得分:2)

从数学的角度来看,复数不能被排序,因此不适合Comparable接口。引用the wikipedia article

  

因为复数自然被认为存在于二维平面上,所以复数的集合没有自然的线性排序。
  复数上没有与加法和乘法兼容的线性排序。在形式上,我们说复数不能具有有序字段的结构。这是因为有序字段中的任何平方至少为0,但是i 2 = -1。

话虽如此,从技术上讲,没有什么可以阻止你实现这个界面。例如,您可以决定首先按实际部分排序,然后按虚部分排序。请注意,compareTo方法的合同要求您返回int,而不是double。此外,您应该将类​​定义为扩展Comparable<Complex>而不是原始Comparable,因此您不必使用转换和运行时类型检查:

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

修改:
JDK 8的Comparator接口的改进允许使用相同的行为实现更优雅的实现:

public int compareTo(Complex other) {
    return Comparator.comparingDouble(Complex::getReal)
                     .thenComparingDouble(Complex::getImag)
                     .compare(this, other);
}

答案 2 :(得分:1)

值得注意的几点。

  1. 正如其他答案所指出的那样,如果该类的实例具有自然排序,则通常应该只实现Comparable。由于复杂数字没有自然排序,因此您可能不应该实现Comparable

  2. 如果您要提供自然顺序,那么您应该实现Comparable<Complex>来表示与Complex的其他实例进行比较(而不是与其他对象进行比较)。

    < / LI>
  3. 实施Comparable的更好选择是为您的班级提供一个或多个Comparator个对象,可用于提供任意数量的订单。例如:

    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);
        }
     }
    
  4. 然后该类的用户可以选择对使用有意义的排序:

    Optional<Complex> closestToOrigin = complexList.stream().min(Complex::COMPARE_BY_MODULUS);