2009-09-01 4 views
5

제 질문은 기상에 대한 작업을 다루기 위해 클래스 작업에 영감을받는 것을 포함하여 "Writing a generic class to handle built-in types"과 매우 흡사합니다. 그 질문은 C#을 사용하여 질문했지만 Generic Operators에 대한 기사를 지적했습니다.일반적인 방식으로 숫자를 처리하는 방법은 무엇입니까?

나는 그것을 얻지 않는다. 당신이 자바에서 숫자의 여러 유형을 처리 할 수 ​​있도록하려는 경우를 처리 어떻게 그래서

public Number myAdd(Number a, Number b){ 
    return a.add(b); 
} 

: 자바 번호는 같은 방법을 가질 수 있도록 추가 방법이 없습니다?

답변

4

근본적인 문제는 매우 원시적 인 Java 유형 시스템입니다.

Java에서 밀폐 된 유형 세트의 개념이 없으므로 (Java가 Haskell과 같은 유형을 추론 할 수도 없으므로) 일반적인 수 + 번호 -> 수식없이 번호를 만들 수는 없습니다.

프리미티브 (및 자동으로 매핑 될 수있는 정수와 같은 개체)는 승격을 입력하고 + 연산은 언어의 일부입니다. (그리고 이것이 문제의 실제적인 부분입니다 : Number a + Number b는 a와 b가 다른 타입 일 때 무엇을 반환해야합니까?)

정말로이 동작을 원한다면 리플렉션 또는 일련의 검사 및 캐스트를 사용하는 사용자 지정 클래스를 찾아야합니다. 제네릭을 사용하더라도 (제네릭은 유형이 지워진다는 것을 기억하십시오) 캐스팅을 수행해야합니다.

이러한 문제가 Number가 그만한 이유의 일부라고 생각합니다.

+0

"a와 b가 다른 유형 인 경우 a + 숫자 b가 반환해야하는 것"은 문제가 거의 없습니다. :) –

-1

개인적으로, 저는 거의 모든 것을 위해 BigDecimal을 사용합니다 (그러나 주로 통화 값으로 작업하기 때문입니다). 모든 크기의 모든 숫자 값을 처리합니다. 그렇기 때문에, 제 생각에는 이것들은 일반적인 값이고 Number 추상 클래스 대신 가상의 예제에서 사용할 수 있습니다. 모두을 BigDecimal로 바꿀 수 있습니다. 사용하지 않으시겠습니까?

public BigDecimal myAdd(BigDecimal a, BigDecimal b) { 
    return a.add(b); 
} 

편집 : 당신은 항상 당신의 자신의 일반적인 방법을 만들 수있는 doubleValue() 메소드를 사용할 수 있습니다, BigBrothers은 아래에 의견을 해결하기 위해. 이 유일한 문제는, 당신은 누군가가 BigDecimal를 전달 일부 드문 경우에 정밀도를 잃을 수 있으며, 그것이 Double.maxValue

public Number myAdd(Number a, Number b) { 
    return new BigDecimal(a.doubleValue() + b.doubleValue()); 
} 

을 BigDecimal보다 큰만큼 하나 더의없는 반환하는 번호입니다 결과.

+0

나는 당신이 말하는 것을 보는 동안, 나는 더 우아한 뭔가를 기대하고 있었다. –

3

나는 그것을 얻지 못한다. 자바 번호는

어떻게 당신은 그것의 서명을 정의하는 것, java.lang.Numberadd 방법 또는 방법이 않았다고 가정 ... 이 추가 방법이 없습니다? 어떻게 그 의미를 정의하겠습니까? "혼합 모드"산술을 어떻게 다룰 것입니까?

이러한 질문에 대답하고 API를 디자인하는 것은 의심의 여지가 없지만 결과를 올바르게 사용하는 것은 어려울 수 있습니다. 또한 응용 프로그램에서 "표현에 의존하지 않는"산술을 수행해야하는 경우는 가장 드뭅니다. 일반적으로 산술이 수행되고 변환이 일어나는 방식을 명시 적으로 제어하고 싶거나 필요합니다. (자바 원시 형 프로모션 규칙은 이미 사람들이 주위에 그들의 머리를 얻을 충분히 어려운!)

모두 모두, 나는 일이 하지는 산술을 지원하기 위해 노력에 의해 우리에게 좋은 서비스 일을했다고 생각한다 Number API.

3

결과가 얼마나 좋을까요? 대답이 "충분 대부분"다음이하면 충분해야한다 :

public Number myAdd(Number a, Number b){ 
    return a.doubleValue() + b.doubleValue(); 
} 

하지만 말, 자바 원시의 추진 의미와 일치 뭔가를 원한다면, 당신은 아마 작성해야 할거야 너 자신. 그런 다음 BigDecimal, BigInteger, AtomicDouble, AtomicLong, 모든 내용이 org.apache.commons.lang.mutable에 포함 된 모든 "비표준"Number 구현의 모든 조합에 대한 규칙과 누군가 다음주 화요일에 작성하기로 결정할 임의의 구현을 파악해야합니다. .

옳은 일은 대부분의 경우입니다. 예를 들어 모든 것을 BigDecimal으로 변환하는 것은 인수 중 하나가 Apache Commons 'Fraction.ONE_THIRD 인 경우 옵션이 아닙니다. 게다가 일반적인 방식으로 변환을하는 것은 일반적인 방식으로 추가하는 것과 동일한 문제를 나타냅니다. 그러나 add() 메서드를 Number에두면 모든 Number 구현이 이러한 모든 경우를 처리해야합니다. 그 이유는 여기에있는 이유 일 것입니다.

0

다른 이유로 두 숫자를 추가 할 수는 없지만 동일한 유형의 숫자를 추가 할 수 있으며 그 결과도 같은 유형이됩니다. 이 같은 뭔가, 자바 제네릭를 arithmetics를 만들 수 있습니다

interface Arithmetics<T> { 
    T add(T val1, T val2); 
} 

class IntegerArithmetics implements Arithmetics<Integer> { 
    Integer add(Integer val1, Integer val2) { return val1 + val2; } 
} 

//similarly DoubleArithmetics, BigIntegerArithmetics, ... 

Generic Java Math 라이브러리는 당신을 위해 정확하게는 않습니다.

1

일반 추가 메소드를 구현하는 한 가지 방법은 왼손 인수가 리턴 유형을 추론하도록하는 것입니다.

package mixins; 

import java.math.BigDecimal; 

public class Numbers { 

    public static boolean isZ(Number n) { 
     return n instanceof Integer || n instanceof Long || n instanceof Short || n instanceof Byte; 
    } 

    public static boolean isR(Number n) { 
     return n instanceof Double || n instanceof Float; 
    } 

    public static BigDecimal add(BigDecimal a, Number b) { 
     if (b instanceof BigDecimal) { 
      return a.add((BigDecimal) b); 
     } else if (isZ(b)) { 
      return a.add(new BigDecimal(b.longValue())); 
     } else if (isR(b)) { 
      return a.add(new BigDecimal(b.doubleValue())); 
     } 
     throw new IllegalArgumentException("No valid big decimal translation for " + b.getClass()); 
    } 

    public static Integer add(Integer a, Number b) { 
     return a + b.intValue(); 
    } 

    public static Long add(Long a, Number b) { 
     return a + b.longValue(); 
    } 

    public static Float add(Float a, Number b) { 
     return a + b.floatValue(); 
    } 

    public static Double add(Double a, Number b) { 
     return a + b.doubleValue(); 
    } 
} 

정적 메서드로 구현되는 경우 정적 가져 오기를 사용할 수 있습니다.

import static mixins.Numbers.*; 

public class Example { 

    public static void main(String[] args) { 
     BigDecimal fortytwo = new BigDecimal(42); 
     BigDecimal fiftyfive = add(fortytwo, 13); 
     System.out.println(fiftyfive); 
    } 

} 
관련 문제