문제

이 질문은 이미 여기에 답이 있습니다.

그 이유를 아는 사람이 있습니까? java.lang.Number 구현되지 않습니다 Comparable? 이것은 당신이 정렬 할 수 없다는 것을 의미합니다 NumberS와 함께 Collections.sort 나에게 조금 이상해 보인다.

토론 후 업데이트 :

모든 유용한 응답에 감사드립니다. 나는 끝났다 이 주제에 대한 더 많은 연구.

Java.lang.number가 비교할 수없는 이유에 대한 가장 간단한 설명은 돌연변이 문제에 근거가 있습니다.

약간의 검토를 위해 java.lang.Number 추상 슈퍼 타입입니다 AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long 그리고 Short. 그 목록에서 AtomicInteger 그리고 AtomicLong 구현하지 않기 위해 Comparable.

파고 들면서, 나는 구현하는 것이 좋은 관행이 아니라는 것을 알았습니다. Comparable 비교 결과가 쓸모없는 결과를 렌더링하는 비교 중 또는 비교 후에 객체가 변경 될 수 있기 때문에 변한 유형에서. 둘 다 AtomicLong 그리고 AtomicInteger 변이 가능합니다. API 디자이너는 예측하지 못했습니다 Number 구현하다 Comparable 미래 하위 유형의 구현을 제한했을 것입니다. 물론, AtomicLong 그리고 AtomicInteger 1.5 년 후에 Java에 추가되었습니다 java.lang.Number 처음에 구현되었습니다.

돌연변이와는 별도로 여기에는 다른 고려 사항도있을 수 있습니다. ㅏ compareTo 구현 Number 모든 숫자 값을 홍보해야합니다 BigDecimal 모든 것을 수용 할 수 있기 때문입니다 Number 하위 유형. 수학과 공연 측면에서 그 홍보의 의미는 나에게는 불분명하지만 직관은 그 해결책을 kludgy로 발견합니다.

도움이 되었습니까?

해결책

다음 표현을 언급 할 가치가 있습니다.

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

항상 false, 그것은 어느 시점에서 모든 사람을 끌어 올리는 경향이 있습니다. 따라서 임의적 인 비교할 수는 없습니다 Numbers 그러나 당신은 그들이 평등한지 아닌지를 판단 할 수 없습니다.

또한 실제 원시 유형 (float, double), 두 값이 평등한지 결정하는 것은 까다 롭고 허용 가능한 오류 마진 내에서 수행되어야합니다. 다음과 같은 코드를 시도하십시오.

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

그리고 당신은 약간의 차이가 남아있을 것입니다.

그래서 제작 문제로 돌아갑니다 Number Comparable. 어떻게 구현 하시겠습니까? 같은 것을 사용합니다 doubleValue() 안정적으로하지 않을 것입니다. 기억하십시오 Number 하위 유형은 다음과 같습니다.

  • Byte;
  • Short;
  • Integer;
  • Long;
  • AtomicInteger;
  • AtomicLong;
  • Float;
  • Double;
  • BigInteger; 그리고
  • BigDecimal.

신뢰할 수있는 코드를 코딩 할 수 있습니까? compareTo() IF 인스턴스 명령문으로 일련의 진술에 빠지지 않는 메소드? Number 인스턴스에는 6 가지 방법 만 사용할 수 있습니다.

  • byteValue();
  • shortValue();
  • intValue();
  • longValue();
  • floatValue(); 그리고
  • doubleValue().

그래서 나는 Sun이 (합리적인) 결정을 내린 것 같습니다. NumberS는 단지 Comparable 자신의 경우에.

다른 팁

답은 Java Bugparade를 참조하십시오 버그 4414323. 당신은 또한 토론을 찾을 수 있습니다 comp.lang.java.programmer

2001 년의 버그 보고서에 대한 태양 반응에서 인용 :

모든 "숫자"는 비교할 수 없습니다. 비슷한 숫자 순서가 가능하다고 가정합니다. 이것은 부동 소수점 숫자에도 해당되지 않습니다. NAN (숫자가 아님)은 그 자체로도 떠 다니는 지점 값보다 크거나 크거나 동일하지 않습니다. {float, double}. compare는 플로팅 포인트 "<"및 "="연산자의 순서와 다른 총 순서를 부과합니다. 또한 현재 구현 된 바와 같이, 숫자의 서브 클래스는 동일한 클래스의 다른 인스턴스와 비슷합니다. 표준 총 순서가 존재하지 않는 복소수와 같은 다른 경우가 있습니다. 요컨대, 숫자의 서브 클래스가 비교할 수 있는지 여부는 해당 서브 클래스의 결정으로 남겨 져야합니다.

숫자에 비해 비슷한 구현하려면 모든 서브 클래스 쌍에 대한 코드를 작성해야합니다. 대신 서브 클래스가 비슷한 구현을 허용하는 것이 더 쉽습니다.

아마도 숫자를 비교하는 것이 다소 비효율적 일 것이기 때문에, 그러한 비교를 허용하기 위해 모든 숫자가 적합 할 수있는 유일한 표현은 큰 것이 될 것입니다.

대신, 숫자의 비 원자 서브 클래스는 그 자체로 비슷합니다.

원자는 변이 가능하므로 원자 비교를 구현할 수 없습니다.

당신이 사용할 수있는 트랜스 모프 숫자를 사용하여 숫자를 비교합니다.

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

원래 문제를 해결하려면 (숫자 목록을 정렬) 옵션은 일반 유형 확장 숫자의 목록을 선언하고 비슷한 구현입니다.

같은 것 :

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

다른 유형의 수에 대한 스타드 비교는 없습니다. 그러나 자신의 비교기를 작성하여 Treemap을 만들 수 있습니다.u003CNumber, Object> , 트리 셋u003CNumber> 또는 collections.sort (목록u003CNumber> , 비교) 또는 배열 .SORT (number [], 비교기);

나만의 비교기를 작성하십시오

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

왜 이것이 나쁜 생각일까요? :

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
}

또 다른 옵션은 클래스 번호 구현을 비교할 수있는 선언하고, 비교 구현을 생략하고, Integer와 같은 일부 클래스에서 구현하는 동안 Atomicinteger와 같은 다른 사람들에게는 지원되지 않은 외환을 던지는 것입니다.

내 생각에 비슷한 구현을 구현하지 않으면 클래스를 구현하여 구현할 수있는 유연성을 더 많이 제공 할 것입니다. 모든 공통 숫자 (정수, 길고, 이중 등)는 비슷한 구현 가능합니다. 요소 자체가 비슷한 구현하는 한 여전히 Collections.sort를 호출 할 수 있습니다.

클래스 계층 구조를보고 있습니다. 긴, 정수 등과 같은 래퍼 클래스, 비슷한 구현, 즉 정수는 정수와 비교할 수 있으며 긴 길이와 비슷하지만 혼합 할 수는 없습니다. 적어도이 제네릭 패러다임으로. 나는 당신의 질문에 '왜' '라고 생각합니다.

byte (원시)은 a int (원어). 프리미티브는 한 번에 하나의 값 만 있습니다.
언어 설계 규칙이이를 허용합니다.

int i = 255

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

Byte 아닙니다 Integer. Byte a Number 그리고 Integer a Number. Number 객체는 동시에 하나 이상의 값을 가질 수 있습니다.

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

만약 Byte 이다 Integer 그리고 Integer a Number, 당신은 당신이 어떤 값을 사용할 것인지 compareTo(Number number1, Number number2) 방법?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top