2009-04-25 5 views
6

Estoy jugando con algunos códigos katas y tratando de obtener una mejor comprensión de los genéricos de Java al mismo tiempo. Tengo este pequeño método que imprime arreglos como si quisiera verlos y tengo un par de métodos de ayuda que aceptan una matriz de 'cosas' y un índice y devuelve la matriz de las 'cosas' por encima o por debajo del índice (es un algoritmo de búsqueda binario).¿Se puede pasar una matriz int a un método genérico en Java?

Dos preguntas,

nº 1 puedo evitar el reparto de T en splitBottom y splitTop? No se siente bien, o estoy haciendo esto de la manera incorrecta (no me diga que use Python o algo así ...;))

# 2 ¿Tengo que escribir métodos separados para tratar con primitivos? matrices o hay una mejor solución?

public class Util { 

    public static <T> void print(T[] array) { 
     System.out.print("{"); 
     for (int i = 0; i < array.length; i++) { 
      System.out.print(array[i]); 
      if (i < array.length - 1) { 
       System.out.print(", "); 
      } 
     } 
     System.out.println("}"); 
    } 

    public static <T> T[] splitTop(T[] array, int index) { 
     Object[] result = new Object[array.length - index - 1]; 
     System.arraycopy(array, index + 1, result, 0, result.length); 
     return (T[]) result; 
    } 

    public static <T> T[] splitBottom(T[] array, int index) { 
     Object[] result = new Object[index]; 
     System.arraycopy(array, 0, result, 0, index); 
     return (T[]) result; 
    } 

    public static void main(String[] args) { 

     Integer[] integerArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     print(integerArray); 
     print(splitBottom(integerArray, 3)); 
     print(splitTop(integerArray, 3)); 

     String[] stringArray = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"}; 
     print(stringArray); 
     print(splitBottom(stringArray, 3)); 
     print(splitTop(stringArray, 3)); 

     int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 
     // ??? 
    } 
} 

Respuesta

9

Los genéricos no manejan las primitivas de manera consistente. Esto se debe a que los genéricos no son como plantillas en C++, solo es una adición en tiempo de compilación a una sola clase.

Cuando se compilan genéricos, termina con Objeto [] en el ejemplo anterior como tipo de implementación. Como int [] y byte [] etc., no extienda Object [] no puede usarlos de manera intercambiable aunque el código implicado sea idéntico (de nuevo los genéricos no son plantillas)

La única clase int [] y Object [] compartir es Object. Puede escribir los métodos anteriores Objeto como tipo (consulte System.arraycopy, Array.getLength, Array.get, Array.set)

1

Pregunta 1: La generación de matrices no funciona como esperaba. Una cadena es un objeto, pero una matriz de cadena no es una matriz de objetos.

Trate de usar algo como:

public static <T> T[] splitTop(T[] array, int index) { 
    T[] result = Arrays.copyOfRange(array, index + 1, array.length); 
    return result; 
} 

Pregunta 2: Para las matrices de primitivas mi función, obviamente, no funciona bien. No hay una solución elegante para eso: consulte, por ejemplo, la biblioteca Arrays, que tiene varias copias de esencialmente el mismo método para cada tipo de matriz primitiva.

+0

No se puede hacer eso con genéricos, lo que da como resultado un error de tipo incompatible. – hbw

+0

@htw ¿Puedes explicar más? – blank

3

1 ¿Puedo evitar la conversión a T en splitBottom y splitTop? No se siente bien, o me voy de este el camino equivocado (no me diga a utilizar pitón o algo ..;))

No sólo no se puede evitar, pero no deberías hacerlo En Java, los diferentes tipos de matrices son en realidad diferentes tipos de tiempo de ejecución. Una matriz que se creó como Object[] no se puede asignar a una variable de AnythingElse []. El elenco no fallará de inmediato, porque en los genéricos se borrará el tipo T, pero luego arrojará una ClassCastException cuando el código intente usarlo como algo [] como se lo prometió, pero no lo es.

La solución es usar los métodos Arrays.copyOf... en Java 6 y posterior, o si está utilizando una versión anterior de Java, use Reflection para crear el tipo correcto de matriz. Por ejemplo,

T [] result = (T []) Array.newInstance (array.getClass().getComponentType(), size);

2 ¿Debo escribir métodos separados para tratar matrices primitivas o es hay una mejor solución?

Probablemente sea mejor escribir métodos separados. En Java, las matrices de tipos primitivos están completamente separadas de las matrices de tipos de referencia; y no hay una buena manera de trabajar con ambos.

Es posible usar Reflection para tratar ambas cosas al mismo tiempo. Reflection tiene Array.get() y Array.set() métodos que funcionarán tanto en matrices primitivas como en matrices de referencia. Sin embargo, pierde seguridad de tipo al hacer esto, ya que el único supertipo de matrices primitivas y matrices de referencia es Object.

1

Java no permite la construcción de matrices genéricas de forma segura. Use un tipo de secuencia genérica en su lugar (como java.util.List, por ejemplo).

Así es como me gustaría escribir el programa de prueba, utilizando una clase de contenedor genérico fj.data.Stream:

import fj.data.Stream; 
import static fj.data.Stream.range; 

// ... 

public int[] intArray(Stream<Integer> s) { 
    return s.toArray(Integer.class).array() 
} 

public static void main(String[] args) { 
    Stream<Integer> integerStream = range(1, 10); 
    print(intArray(integerStream)); 
    print(intArray(integerStream.take(3))); 
    print(intArray(integerStream.drop(3))); 

    // ... 
} 
0

Tienes dos problemas con lo que está tratando de lograr.

En primer lugar, intenta utilizar tipos primitivos, que en realidad no heredan de Object. Esto arruinará las cosas. Si realmente necesita hacer esto, explícitamente use entero en lugar de int, etc.

El segundo y mayor problema es que los genéricos de Java tienen borrado de tipo. Esto significa que, en tiempo de ejecución, no puede referirse al tipo de genérico. Esto fue hecho para permitirle mezclar código de apoyo genérico y no genérico, y terminó siendo (en mi humilde opinión) una gran fuente de dolor de cabeza para los desarrolladores de Java y otra prueba de que los genéricos deberían haber estado en Java desde el día 1. Le sugiero lea la parte en el tutorial al respecto, aclarará este problema.

0

Probablemente tendrá que envolver las primitivas en las colecciones correspondientes.

También sugiero echar un vistazo a las colecciones primitivas de Trove (http://trove.starlight-systems.com). Esto no está relacionado con tu pregunta de genéricos, pero puede ser bastante interesante.

Cuestiones relacionadas