2010-04-27 13 views
30

Tengo dos números. Por ejemplo:¿Cómo agregar dos java.lang.Numbers?

Number a = 2; 
Number b = 3; 
//Following is an error: 
Number c = a + b; 

Por qué las operaciones de la aritmética no son compatibles con los números? De todos modos, ¿cómo agregaría estos dos números en java? (Por supuesto que los obtengo de algún lado y no sé si son enteros o float, etc.).

+0

¿Son realmente asignados así? Quiero decir, ¿es válido Number a = primitiveNumber? Si los obtiene de algún Método que devuelve "algo se extiende Número", podría verificar si el Número devuelto es una instancia de Doble o Float o BigDecimal o lo que sea. – Tedil

+0

@Tedil Sí, una asignación de este tipo es posible desde Java 1.5, gracias a una característica conocida como "autoboxing".El número primitivo '2' es un' int', que está encuadrado en un 'Entero', que es una subclase de' Número'. –

+0

Puede usar métodos sobrecargados también :) Funciona para todos los casos – Mob

Respuesta

18

Usted dice que no sabe si sus números son números enteros o flotan .. Cuando usas la clase Number, el compilador tampoco sabe si tus números son enteros, flotantes o s Otra cosa. Como resultado, los operadores matemáticos básicos como + y - no funcionan; la computadora no sabría cómo manejar los valores.

Start Edit

Sobre la base de la discusión, pensé un ejemplo podría ayudar. Las computadoras almacenan números en coma flotante como dos partes, un coeficiente y un exponente. Entonces, en un sistema teórico, 001110 podría dividirse como 0011 10 o 3 = 9. Pero los números enteros positivos almacenan los números como binarios, por lo que 001110 también podría significar 2 + 4 + 8 = 14. Cuando usa la clase Number, le está diciendo a la computadora que no sabe si el número es un flotante o un int o qué, entonces sabe que tiene 001110 pero no sabe si eso significa 9 o 14 o algún otro valor.

FIN EDITAR

Lo que puede hacer es hacer un poco de asunción y convertir a uno de los tipos que hacer los cálculos. Lo que podría tener

Number c = a.intValue() + b.intValue(); 

que bien podría convertirse en

Integer c = a.intValue() + b.intValue(); 

si estás dispuesto a sufrir algún error de redondeo, o

Float c = a.floatValue() + b.floatValue(); 

si sospecha que usted' no se trata de enteros y está bien con posibles problemas menores de precisión. O, si prefiere tomar un pequeño golpe de rendimiento en lugar de que el error,

BigDecimal c = new BigDecimal(a.floatValue()).add(new BigDecimal(b.floatValue())); 
+1

Estás casi en lo cierto. Pero no estoy de acuerdo con "... así que sabe que tiene 001110 pero no sabe si eso significa 9 o 14 o algún otro valor". Java TI tiene información del tipo de tiempo de ejecución. Java SABERá si el tipo de tiempo de ejecución de un objeto Number es Integer o Double u otra cosa. Teóricamente, podría comenzar a distinguir los tipos y comenzar a programar el Número público más (Número a, Número b) {si (una instancia de Entero && b instancia de Entero) {devolver nuevo Número entero (a.intValor + b.intValor();} .. .y así sucesivamente ... – fjf2002

7

java.lang.Number es simplemente la superclase de todas las clases contenedoras de tipos primitivos (consulte java doc). Use el tipo de primitiva apropiado (double, int, etc.) para su propósito, o la clase contenedora respectiva (Double, Integer, etc.).

Considera:

Number a = 1.5; // Actually Java creates a double and boxes it into a Double object 
Number b = 1; // Same here for int -> Integer boxed 

// What should the result be? If Number would do implicit casts, 
// it would behave different from what Java usually does. 
Number c = a + b; 

// Now that works, and you know at first glance what that code does. 
// Nice explicit casts like you usually use in Java. 
// The result is of course again a double that is boxed into a Double object 
Number d = a.doubleValue() + (double)b.intValue(); 
+2

Entiendo esto. Pero es extraño que no sea directamente compatible con la clase Number. – amit

+0

@ amit.dev No todas las subclases pueden implementar esto de la manera que usted esperaría. Especialmente con los tipos Atomic es difícil definir un contrato útil, por ej. añadir. Y Short.add (Long) también puede causar problemas. – extraneon

+1

@ amit.dev: ¿por qué debería ser soportado directamente? Eso no tiene sentido, porque exigiría que Java admitiera extraños moldes implícitos o sobrecargas de operador para cada permutación de tipos que se agreguen. Agregué un código de ejemplo a mi respuesta. Tal vez eso lo hace más claro. –

3

Usar la siguiente:

Number c = a.intValue() + b.intValue(); // Number is an object and not a primitive data type. 

O:

int a = 2; 
int b = 3; 
int c = 2 + 3; 
+8

intValue() no funcionará muy bien en Double, o Long, o BigDecimal y así sucesivamente ... – Thilo

0

Number es una clase abstract que no se puede hacer una instancia de. Siempre que tenga una instancia correcta, puede obtener number.longValue() o number.intValue() y agregarlos.

0

Antes que nada, debe tener en cuenta que Number es una clase abstracta.Lo que sucede aquí es que cuando creas tus 2 y 3, se interpretan como primitivas y se crea un subtipo (creo que un entero) en ese caso. Como un entero es un subtipo de número, puede asignar el entero recién creado a una referencia numérica.

Sin embargo, un número es solo una abstracción. Podría ser un número entero, podría ser un punto flotante, etc., por lo que la semántica de las operaciones matemáticas sería ambigua.

número no proporciona las operaciones de correlación clásicos por dos razones:

En primer lugar, los métodos de miembros en Java no se puede operadores. No es C++. En el mejor de los casos, podrían proporcionar un add()

En segundo lugar, averiguar qué tipo de operación hacer cuando tiene dos entradas (por ejemplo, una división de un flotante por un int) es bastante complicado.

Por lo tanto, en su lugar, es su responsabilidad hacer que la conversión vuelva al tipo primitivo específico en el que está interesado y aplicar los operadores matemáticos.

+0

Incorrecto, no puede crear una instancia de una clase abstracta. – Cam

+1

@incrediman: ¿Dónde indiqué que estoy generando instancias de una clase abstracta? Indiqué explícitamente que se creó un número entero y luego se asignó a la referencia de Número. – Uri

+0

@incrediman, en realidad, es legal declarar una referencia a una clase abstracta y señalarla a un objeto existente; simplemente no puede declarar una nueva instancia de una clase abstracta. – Pops

2

Creo que su pregunta tiene dos caras.

¿Por qué el operador no es compatible con Number?

Porque la especificación de lenguaje Java. no especifica esto, y no hay sobrecarga del operador. Tampoco hay una forma natural en tiempo de compilación para convertir el Número a algún tipo fundamental, y no hay un complemento natural para definir para algún tipo de operaciones.

¿Por qué las operaciones aritméticas básicas no son compatibles con Number?

(Copiado de mi comentario :)

No todas las subclases pueden implementar esto de una manera que se puede esperar. Especialmente con los tipos Atomic es difícil definir un contrato útil, por ej. añadir.

Además, agregar un método sería un problema si intenta agregar un largo a un corto.

7

También trabajaría para hacer un método para manejar el agregado por usted. Ahora no sé el impacto en el rendimiento que esto causará, pero supongo que será menor que con BigDecimal.

public static Number addNumbers(Number a, Number b) { 
    if(a instanceof Double || b instanceof Double) { 
     return new Double(a.doubleValue() + b.doubleValue()); 
    } else if(a instanceof Float || b instanceof Float) { 
     return new Float(a.floatValue() + b.floatValue()); 
    } else if(a instanceof Long || b instanceof Long) { 
     return new Long(a.longValue() + b.longValue()); 
    } else { 
     return new Integer(a.intValue() + b.intValue()); 
    } 
} 
+0

Puede guardarse repitiéndose usando un ' ', por lo que solo debe verificar el tipo de' N a'. – ndm13

+0

@ ndm13 en el fragmento de arriba. Solo estoy verificando el tipo de letra que indica el método de bruja. – SkidRunner

+0

Quise decir en vez de tener que verificar los tipos de a y b. El genérico aseguraría que sean del mismo tipo, por lo que solo necesitaría verificarlo. – ndm13

8

La única manera de añadir correctamente cualquiera de los dos tipos de java.lang.Number es:

Number a = 2f; // Foat 
Number b = 3d; // Double 
Number c = new BigDecimal(a.toString()).add(new BigDecimal(b.toString())); 

Esto funciona incluso para dos argumentos con un número de tipo diferente. No (¿debería?) No producir efectos secundarios como desbordamientos o pérdida de precisión, en la medida en que toString() del tipo de número no reduzca la precisión.

+1

Si solo pudiéramos tener la clase BigDecimal.getPrimitiveType() devolviendo int.class o double.class o lo que sea – Whimusical

0

La mejor respuesta sería hacer util con la perforación doble de despacho a tipos más conocidos (echar un vistazo a la aplicación addtition Smalltalk)

Cuestiones relacionadas