java.lang.Number가 Comparable을 구현하지 않는 이유는 무엇입니까? [복제]
아무도 왜 java.lang.Number
구현하지 않는지 알고 Comparable
있습니까? 이것은 당신이 나에게 조금 이상하게 보이는 Number
s를 정렬 할 수 없음을 의미합니다 Collections.sort
.
토론 업데이트 후 :
유용한 답변에 감사드립니다. 나는 이 주제에 대해 더 많은 연구를하게되었다 .
java.lang.Number가 Comparable을 구현하지 않는 이유에 대한 가장 간단한 설명은 변경 가능성 문제에 있습니다.
검토의 비트를 들어, 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.lang.Number
처음 구현되었습니다.
변경 가능성 외에도 여기에 다른 고려 사항이있을 수 있습니다. compareTo
의 구현은 Number
모든 숫자 값을 촉진 할 것 BigDecimal
이 모든 수용 할 수 있기 때문에 Number
하위 유형을. 수학과 퍼포먼스 측면에서 그 승진이 의미하는 바는 분명하지 않지만, 직관에 따라 그 해결책은 어색합니다.
다음과 같은 표현을 언급 할 가치가 있습니다.
new Long(10).equals(new Integer(10))
는 항상 false
어느 시점에서 모두를 트립하는 경향이 있습니다. 따라서 임의 Number
의 s를 비교할 수있을뿐만 아니라 동일한 지 여부를 결정할 수도 없습니다.
또한 실제 기본 유형 ( 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 instanceof 문으로 분리되지 않는 안정적인 메소드 를 코딩 할 수 있습니까? Number
인스턴스에는 여섯 가지 방법 만 사용할 수 있습니다.
byteValue()
;shortValue()
;intValue()
;longValue()
;floatValue()
; 과doubleValue()
.
그래서 썬 은 자신들 Number
에게만 해당되는 (합리적인) 결정을 내렸다고 생각 Comparable
합니다.
이에 대한 답변은 Java bugparade 버그 4414323을 참조하십시오 . comp.lang.java.programmer 에서 토론을 찾을 수도 있습니다.
2001 년 버그 보고서에 대한 Sun의 답변을 인용하면 :
All "numbers" are not comparable; comparable assumes a total ordering of numbers is possible. This is not even true of floating-point numbers; NaN (not a number) is neither less than, greater than, nor equal to any floating-point value, even itself. {Float, Double}.compare impose a total ordering different from the ordering of the floating-point "<" and "=" operators. Additionally, as currently implemented, the subclasses of Number are only comparable to other instances of the same class. There are other cases, like complex numbers, where no standard total ordering exists, although one could be defined. In short, whether or not a subclass of Number is comparable should be left as a decision for that subclass.
in order to implement comparable on number, you would have to write code for every subclass pair. Its easier instead to just allow subclasses to implement comparable.
Very probably because it would be rather inefficient to compare numbers - the only representation into which every Number can fit to allow such comparison would be BigDecimal.
Instead, non-atomic subclasses of Number implements Comparable itself.
Atomic ones are mutable, so can't implement an atomic comparison.
You can use Transmorph to compare numbers using its NumberComparator class.
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);
To try to solve the original problem (sort a list of numbers), an option is to declare the list of a generic type extending Number and implementing Comparable.
Something like:
<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));
}
there is no stardard comparison for Numbers of different types. However you can write your own Comparator and use it to create a TreeMap<Number, Object>, TreeSet<Number> or Collections.sort(List<Number>, Comparator) or Arrays.sort(Number[], Comparator);
Write your own Comparator
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() + ", ");
}
}
}
why this would have been bad idea? :
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
}
another option may have been to declare class Number implements Comparable, omit compareTo implementation, and implement it in some classes like Integer while throw UnsupportedException in others like AtomicInteger.
My guess is that by not implementing Comparable, it give more flexibility to implementing classes to implement it or not. All the common numbers (Integer, Long, Double, etc) do implement Comparable. You can still call Collections.sort as long as the elements themselves implement Comparable.
Looking at the class hierarchy. Wrapper classes like Long, Integer, etc, implement Comparable, i.e. an Integer is comparable to an integer, and a long is comparable to a long, but you can't mix them. At least with this generics paradigm. Which I guess answers your question 'why'.
byte
(primitive) is a int
(primitive). Primitives have only one value at a time.
Language design rules allows this.
int i = 255
// down cast primitive
(byte) i == -1
A Byte
is not an Integer
. Byte
is a Number
and an Integer
is a Number
. Number
objects can have more than one value at the same time.
Integer iObject = new Integer(255);
System.out.println(iObject.intValue()); // 255
System.out.println(iObject.byteValue()); // -1
If a Byte
is an Integer
and an Integer
is a Number
, Which one value will you use in the compareTo(Number number1, Number number2)
method?
참고URL : https://stackoverflow.com/questions/480632/why-doesnt-java-lang-number-implement-comparable
'Programing' 카테고리의 다른 글
LaTeX의 코드를 * nice *로 보이게하기 (0) | 2020.06.29 |
---|---|
Chrome에서 로컬 링크를 열 수 있습니까? (0) | 2020.06.29 |
Java 프로젝트 (ant, cvs, hudson)의 빌드 및 버전 번호 매기기 (0) | 2020.06.29 |
비트 버킷으로 푸시 한 후 Atlassian“로고” (0) | 2020.06.29 |
잠금 해제 된 뮤텍스를 잠그는 것이 얼마나 효율적입니까? (0) | 2020.06.29 |