wildcards useful type parameter method generic bounded are java generics

useful - Java Genéricos y números



java generics bounded wildcards (11)

En un intento de ver si puedo limpiar algunos de mis códigos matemáticos, principalmente de matriz, estoy tratando de usar algunos Java Genéricos. Tengo el siguiente método:

private <T> T[][] zeroMatrix(int row, int col) { T[][] retVal = (T[][])new Object[row][col]; for(int i = row; i < row; i++) { for(int j = col; j < col; j++) { retVal[i][j] = 0; } } return retVal; }

La línea retVal [i] [j] = 0 es la que me causa dolores de cabeza. El objetivo de la línea es inicializar la matriz con la representación de T en 0. He intentado hacer todo tipo de cosas con ella: (T se define en la clase cuando T amplía el número)

retVal[i][j] = (T)0; retVal[i][j] = new T(0);

Lo único que funciona es

retVal[i][j] = (T)new Object(0);

Que no es lo que quiero.

es posible? ¿Hay una forma más fácil de representar una matriz NxM de cualquier tipo de Número (incluido potencialmente BigDecimal), o estoy atascado?


Arrays y Genéricos no juegan bien juntos:

"Las matrices son covariantes, lo que significa que una matriz de referencias de supertipo es un supertipo de una matriz de referencias de subtipo. Es decir, Object[] es un supertipo de String[] y se puede acceder a una matriz de cadena a través de una variable de referencia de tipo Object[] . "

Vea las preguntas frecuentes de Java Generics :


Creo que estás luchando una batalla perdida. Incluso si resuelves esto, ¿cómo planeas resolver sumas, restas, etc.? La clase de número no es una superclase muy útil, y casi el único método útil es doubleValue ().

El cero se puede definir como la identidad adicional o un cero en la multiplicación, pero sin una definición genérica de suma o multiplicación, una definición genérica de cero es poco probable.

Si quieres esto, entonces es mejor que te quedes con BigDecimal para todo, pero por supuesto eso tendrá penalizaciones de rendimiento asociadas.

La otra opción obvia sería dejar la matriz con inicialización nula y luego cambiar su otro código para tratar a cero como cero.


Debe tener en cuenta que los genéricos solo se utilizan en tiempo de compilación para la verificación de seguridad de tipo. Esta información se pierde en el tiempo de ejecución, por lo que no puede usar el boxeo automático en la devolución [i] [j] = 0; ya que Java no puede auto-box para escribir Número u Objeto.

Si pasa el valor que desea establecer, funcionará. Aquí hay una muestra rápida:

private <T> T[][] fillMatrix(int row, int col, T value) { T[][] retVal = (T[][])new Object[row][col]; for(int i = 0; i < row; i++) { for(int j = 0; j < col; j++) { retVal[i][j] = value; } } return retVal; }

Por cierto, para (int i = row; i <row; i ++) y para (int j = col; j <col; j ++) nunca se repetirán, por lo que hay otro problema con su código.

edición: no podrá emitir el resultado a otra cosa que no sea Objeto [] [] porque ese es el tipo de matriz real.


El uso de Java del borrado para implementar genéricos significa que tendrá problemas para crear un nuevo tipo genérico.

¿Qué hay de usar nulo para representar 0

retVal[i][j] = null;

A continuación, puede asignar cualquier tipo que desee a la matriz más adelante.


En Java, el tipo se borra en tiempo de ejecución, por lo que debe pasar otro argumento para obtener el tipo en tiempo de ejecución.

Ese podría ser el valor para inicializar los arreglos con, o la clase a usar.

Si elige pasar en la clase, entonces tenga un Mapa de clase a valor para almacenar un valor cero para cada tipo.

Luego puede usar java.util.Arrays.fill para llenar la matriz:

private static HashMap<Class<?>, Object> ZEROS = new HashMap<Class<?>,Object>(); static { ZEROS.put( Integer.class, Integer.valueOf(0) ); ... } private static <T extends Number> T[][] zeroMatrix ( Class<T> type, int rows, int cols ) { @SuppressWarnings("unchecked") T[][] matrix = (T[][]) java.lang.reflect.Array.newInstance(type, rows, cols); Object zero = ZEROS.get(type); for ( T[] row : matrix ) java.util.Arrays.fill(row,zero); return matrix; } Integer[][] matrix = zeroMatrix (Integer.class, 10, 10);

Sin embargo, si el rendimiento es una preocupación remota, no desea utilizar valores de recuadro para el código numérico.

Realmente no desea probar y utilizar nulo para cero, se triplicará la complejidad de todas las demás rutas en su código. Si bien puede salirse con una clase de soporte numérico que proporcionaría la suma y la multiplicación de los diversos tipos de números en caja, la cantidad de complejidad que ahorre será muy pequeña en comparación con la provisión de dos o tres matrices primitivas y un par de números grandes. particularmente si utiliza un sistema de plantillas (por ejemplo, la tarea de reemplazo de hormigas o XSLT) para generar el código fuente.



Los arreglos de Ye Olde (referencia) no funcionan bien con los genéricos. En este caso, las matrices también pueden ser ineficientes. Está creando una matriz de matrices, por lo que hay una indirección innecesaria y una verificación de límites. Mejor hacer una Matrix<T> clase Matrix<T> . También es posible que desee agregar a la Matrix una referencia a una instancia de T que represente un cero.


Los genéricos y las matrices no coinciden muy bien. La creación de una matriz genérica no está permitida ya que no sería segura para tipos. Se deriva del hecho de que si Sub es un subtipo de Super, entonces Sub [] es un subtipo de Super [], que no es el caso de los tipos genéricos; Para cualquiera de los dos tipos distintos Tipo 1 y Tipo 2, Lista no es un subtipo ni un supertipo de Lista. (Java efectivo cubre esto en el capítulo 5, artículo 25).


Si realmente quieres usar genéricos, podrías hacer algo como esto

private <T extends Number> T[][] zeroMatrix(int row, int col, Class<T> clazz) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { T[][] retVal = (T[][]) Array.newInstance(clazz, new int[] { row, col }); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { Constructor<T> c = clazz.getDeclaredConstructors()[0]; retVal[i][j] = c.newInstance("0"); } } return retVal; }

Ejemplo:

zeroMatrix(12, 12, Integer.class);


debería ser nulo en lugar de cero.

Si realmente quieres poner allí el equivalente de 0 para el objeto T, deberás proporcionar una fábrica de T. Algo como esto:

interface Factory<T> { T getZero(); }

y deberías hacer el método así:

private <T> T[][] zeroMatrix(int row, int col, Factory<T> factory) { T[][] retVal = (T[][])new Object[row][col]; for(int i = row; i < row; i++) { for(int j = col; j < col; j++) { retVal[i][j] = factory.getZero(); } } return retVal; }

También debe tener implementaciones adecuadas para la fábrica:

class IntegerFactory implements Factory<Integer> { Integer getZero() { return new Integer(0); } }

Normalmente, también pondría el getMatrix(int row, int column) en la implementación de fábrica para devolver una matriz tipada adecuada.


<T extends Number> T[][] zeroMatrix(Class<? extends Number> of, int row, int col) { T[][] matrix = (T[][]) java.lang.reflect.Array.newInstance(of, row, col); T zero = (T) of.getConstructor(String.class).newInstance("0"); // not handling exception for (int i = 0; i < row; i++) { for (int j = 0; j < col; matrix[i][j] = zero; } } return matrix; }

uso:

BigInteger[][] bigIntegerMatrix = zeroMatrix(BigInteger.class, 3, 3); Integer[][] integerMatrix = zeroMatrix(Integer.class, 3, 3); Float[][] floatMatrix = zeroMatrix(Float.class, 3, 3); String[][] error = zeroMatrix(String.class, 3, 3); // <--- compile time error System.out.println(Arrays.deepToString(bigIntegerMatrix)); System.out.println(Arrays.deepToString(integerMatrix)); System.out.println(Arrays.deepToString(floatMatrix));

EDITAR

una matriz genérica:

public static <T> T[][] fillMatrix(Object fill, int row, int col) { T[][] matrix = (T[][]) Array.newInstance(fill.getClass(), row, col); for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { matrix[i][j] = (T) fill; } } return matrix; } Integer[][] zeroMatrix = fillMatrix(0, 3, 3); // a zero-filled 3x3 matrix String[][] stringMatrix = fillMatrix("B", 2, 2); // a B-filled 2x2 matrix