Frage

    

Diese Frage bereits eine Antwort hier:

         

Weiß jemand, warum java.lang.Number Comparable nicht implementiert? Das bedeutet, dass Sie nicht Numbers mit Collections.sort, die mir scheint ein wenig seltsam sortieren.

Post Diskussion Update:

Vielen Dank für all die hilfreichen Antworten. Ich landete .

Die einfachste Erklärung dafür, warum java.lang.Number Vergleichbare nicht implementiert ist in Veränderlichkeit betrifft verwurzelt.

Für ein bisschen Bewertung ist java.lang.Number der abstrakte Supertyp AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long und Short. Auf dieser Liste, AtomicInteger und AtomicLong nicht implementieren Comparable.

Graben um, entdeckte ich, dass es nicht eine gute Praxis ist Comparable auf änderbare Typen zu implementieren, da die Objekte während oder nach dem Vergleich wodurch das Ergebnis des Vergleichs nutzlos ändern können. Sowohl AtomicLong und AtomicInteger sind wandelbar. Die API-Designer hatten die Vorbedacht nicht Number Comparable zu implementieren zu haben, weil sie die Umsetzung der künftigen Subtypen eingeschränkt hätte. Tatsächlich wurden AtomicLong und AtomicInteger hinzugefügt in Java 1.5 noch lange nach java.lang.Number umgesetzt wurde zunächst.

Neben Veränderlichkeit gibt es wahrscheinlich andere Überlegungen auch hier. Eine compareTo Implementierung in Number müßte alle numerischen Werte fördern, um BigDecimal, weil es die Unterbringung aller Number Untertypen fähig ist. Die Implikation, dass die Förderung in Bezug auf Mathematik und Leistung ein wenig unklar ist für mich, aber meine Intuition findet diese Lösung kludgy.

War es hilfreich?

Lösung

Es ist erwähnenswert, dass die folgende Gleichung:

new Long(10).equals(new Integer(10))

ist immer false, die jeder stolpern neigt zu einem bestimmten Zeitpunkt oder ein anderes auf. So können Sie nicht nur nicht willkürlich Numbers vergleichen, aber man kann nicht einmal feststellen, ob sie ist gleich oder nicht.

Auch mit den wirklichen primitiven Typen (float, double), zu bestimmen, ob zwei Werte gleich sind heikel ist und innerhalb einer akzeptablen Fehlerspanne durchgeführt werden. Versuchen Sie Code wie:

double d1 = 1.0d;
double d2 = 0.0d;
for (int i=0; i<10; i++) {
  d2 += 0.1d;
}
System.out.println(d2 - d1);

und Sie werden mit einigen kleinen Unterschied gelassen werden.

zur Ausgabe Also zurück Number Comparable machen. Wie würden Sie es umsetzen? Mit so etwas wie doubleValue() wäre es nicht zuverlässig tun. Denken Sie daran, die Number Subtypen sind:

  • Byte;
  • Short;
  • Integer;
  • Long;
  • AtomicInteger;
  • AtomicLong;
  • Float;
  • Double;
  • BigInteger; und
  • BigDecimal.

Könnten Sie eine zuverlässige compareTo() Methode Code, der nicht in eine Reihe, wenn Instanceof Aussagen nicht zufallen? Number Instanzen haben nur sechs Methoden zur Verfügung zu ihnen:

  • byteValue();
  • shortValue();
  • intValue();
  • longValue();
  • floatValue(); und
  • doubleValue().

Also ich denke, Sun die (vernünftige) Entscheidung getroffen, dass Numbers nur auf Instanzen von sich selbst Comparable wurden.

Andere Tipps

Für die Antwort finden Sie unter Java bugparade Fehler 4.414.323 . Sie können auch eine Diskussion von comp finden. lang.java.programmer

Ein Zitat aus der Sun Antwort auf den Bug-Report von 2001:

  

Alle „Zahlen“ nicht vergleichbar sind;   vergleichbar nimmt eine Gesamtbestellung von   Zahlen möglich ist. Das ist nicht einmal   gilt für Gleitkommazahlen; NaN   (Keine Zahl) ist weder weniger als,   größer, noch gleich irgendein   Gleitkommawert, auch selbst.   {Float, Double} .compare insgesamt verhängen   Bestellung unterscheidet sich von der Bestellung   die Floating-Point "<" und "="   Betreiber. Zusätzlich wird, wie zur Zeit   implementiert, die Unterklassen der Anzahl   nur vergleichbar sind mit anderen Instanzen   der gleichen Klasse. Da sind andere   Fälle, wie komplexe Zahlen, in denen keine   Standard totale Ordnung vorhanden ist,   obwohl man definiert werden kann. Im   Kurz gesagt, ob eine Unterklasse von   Zahl ist vergleichbar sollte gelassen werden, wie   eine Entscheidung für diese Unterklasse.

, um vergleichbare auf Nummer zu implementieren, würden Sie Code für jede Unterklasse Paar schreiben. Sein statt einfacher, nur Unterklassen ermöglichen vergleichbar zu implementieren.

Sehr wahrscheinlich, weil es ziemlich ineffizient wäre Zahlen zu vergleichen -. Die einzige Darstellung, in denen jede Zahl paßt so einen Vergleich zu ermöglichen wäre BigDecimal

Stattdessen Nicht-Atomunterklassen der Anzahl implementiert Comparable selbst.

Atomic diejenigen sind wandelbar, so kann nicht ein Atom Vergleich implementieren.

Sie können mit Transmorph Zahlen vergleichen, seine NumberComparator Klasse.

NumberComparator numberComparator = new NumberComparator();
assertTrue(numberComparator.compare(12, 24) < 0);
assertTrue(numberComparator.compare((byte) 12, (long) 24) < 0);
assertTrue(numberComparator.compare((byte) 12, 24.0) < 0);
assertTrue(numberComparator.compare(25.0, 24.0) > 0);
assertTrue(numberComparator.compare((double) 25.0, (float) 24.0) > 0);
assertTrue(numberComparator.compare(new BigDecimal(25.0), (float) 24.0) > 0);

Um zu versuchen, das ursprüngliche Problem (sortiert eine Liste von Zahlen) zu lösen, ist eine Option, um die Liste eines generischen Typs zu deklarieren Nummer erstreckt und Umsetzung vergleichbar.

So etwas wie:

<N extends Number & Comparable<N>> void processNumbers(List<N> numbers) {
    System.out.println("Unsorted: " + numbers);
    Collections.sort(numbers);
    System.out.println("  Sorted: " + numbers);
    // ...
}

void processIntegers() {
    processNumbers(Arrays.asList(7, 2, 5));
}

void processDoubles() {
    processNumbers(Arrays.asList(7.1, 2.4, 5.2));
}

gibt es keinen stardard Vergleich zur Anzahl der verschiedenen Arten. Allerdings können Sie Ihre eigenen Vergleicher schreiben und es verwenden, um eine TreeMap , TreeSet oder Collections.sort (List , Vergleicher) oder Arrays.sort (Number [], Vergleicher) zu schaffen;

Schreiben Sie Ihren eigenen Vergleicher

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class NumberComparator implements Comparator {
    @SuppressWarnings("unchecked")
    @Override
    public int compare(Number number1, Number number2) {
 if (((Object) number2).getClass().equals(((Object) number1).getClass())) {
     // both numbers are instances of the same type!
     if (number1 instanceof Comparable) {
  // and they implement the Comparable interface
  return ((Comparable) number1).compareTo(number2);
     }
 }
 // for all different Number types, let's check there double values
 if (number1.doubleValue() < number2.doubleValue())
     return -1;
 if (number1.doubleValue() > number2.doubleValue())
     return 1;
 return 0;
    }

    /**
     * DEMO: How to compare apples and oranges.
     */
    public static void main(String[] args) {
 ArrayList listToSort = new ArrayList();
 listToSort.add(new Long(10));
 listToSort.add(new Integer(1));
 listToSort.add(new Short((short) 14));
 listToSort.add(new Byte((byte) 10));
 listToSort.add(new Long(9));
 listToSort.add(new AtomicLong(2));
 listToSort.add(new Double(9.5));
 listToSort.add(new Double(9.0));
 listToSort.add(new Double(8.5));
 listToSort.add(new AtomicInteger(2));
 listToSort.add(new Long(11));
 listToSort.add(new Float(9));
 listToSort.add(new BigDecimal(3));
 listToSort.add(new BigInteger("12"));
 listToSort.add(new Long(8));
 System.out.println("unsorted: " + listToSort);
 Collections.sort(listToSort, new NumberComparator());
 System.out.println("sorted:   " + listToSort);
 System.out.print("Classes:  ");
 for (Number number : listToSort) {
     System.out.print(number.getClass().getSimpleName() + ", ");
 }
    }
}

, warum dies hätte schlechte Idee? :

abstract class ImmutableNumber extends Number implements Comparable {
    // do NOT implement compareTo method; allowed because class is abstract
}
class Integer extends ImmutableNumber {
    // implement compareTo here
}
class Long extends ImmutableNumber {
    // implement compareTo here
}

eine weitere Option gewesen sein kann Klasse Anzahl implementiert Vergleichbar zu erklären, lassen compareTo Implementierung und implementieren es in einigen Klassen wie Integer, während UnsupportedException in anderen wie Atomicinteger werfen.

Meine Vermutung ist, dass durch nicht Umsetzung Vergleichbar es mehr Flexibilität zu implementierenden Klassen geben, sie umzusetzen oder nicht. Alle gemeinsamen Zahlen (Integer, Long, Double usw.) implementieren vergleichbar. Sie können immer noch Collections.sort so lange nennen, wie die Elemente selbst Vergleichbare implementieren.

in der Klassenhierarchie suchen. Wrapper-Klassen wie Long, Integer usw. implementieren Comparable, das heißt eine ganze Zahl ist vergleichbar mit einer ganzen Zahl und eine lange ist vergleichbar mit einem langen, aber man kann sie nicht mischen. Zumindest mit diesem Generika Paradigma. Welche Ich denke, beantwortet Ihre Frage ‚Warum‘.

byte (primitive) ist ein int (primitive). Primitives hat nur einen Wert zu einem Zeitpunkt.
Sprache Design-Regeln dies erlaubt.

int i = 255

// down cast primitive
(byte) i == -1

Ein Byte ist kein Integer. Byte ist ein Number und ein Integer ist ein Number. Number Objekte können mehr als einen Wert zur gleichen Zeit haben.

Integer iObject = new Integer(255);
System.out.println(iObject.intValue());   // 255
System.out.println(iObject.byteValue());  // -1

Wenn ein Byte ist ein Integer und ein Integer ist ein Number, die einen Wert finden Sie in der compareTo(Number number1, Number number2) Methode verwenden?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top