Cómo hacer una matriz de matrices en Java

115

Hipotéticamente, tengo 5 objetos de matriz de cadenas:

String[] array1 = new String[];
String[] array2 = new String[];
String[] array3 = new String[];
String[] array4 = new String[];
String[] array5 = new String[];

y quiero que otro objeto de matriz contenga esos 5 objetos de matriz de cadena. ¿Cómo lo hago? ¿Puedo ponerlo en otra matriz?

Terence Ponce
fuente
43
Las preguntas de novatos pueden ser serias. De hecho, con frecuencia lo son. :-)
TJ Crowder
3
La pregunta pertinente y la respuesta no son obvias para quién sabe cómo se realiza la alineación de la memoria. +1
Benj

Respuestas:

153

Me gusta esto:

String[][] arrays = { array1, array2, array3, array4, array5 };

o

String[][] arrays = new String[][] { array1, array2, array3, array4, array5 };

(La última sintaxis se puede usar en asignaciones que no sean en el punto de la declaración de variable, mientras que la sintaxis más corta solo funciona con declaraciones).

Jon Skeet
fuente
¿Podría explicar más qué hace la segunda sintaxis? No me queda claro.
Terence Ponce
4
@Terence: hace lo mismo que el primero: crea una matriz de referencias de matriz de cadena, inicializada con los valores matriz1, matriz2, matriz3, matriz4 y matriz5, cada uno de los cuales es en sí mismo una referencia de matriz de cadena.
Jon Skeet
1
Pregunta rápida: ¿Cómo haré esto en tiempo de ejecución si no tengo idea de cuántos objetos de matriz se crearán?
Terence Ponce
1
@Terence: ¿Puede dar un ejemplo más específico? Cuando se está especificando los valores iniciales en tiempo de compilación, que no conoce el tamaño. ¿Te refieres a algo como new String[10][]?
Jon Skeet
Si. Similar a la respuesta de Peter.
Terence Ponce
71

tratar

String[][] arrays = new String[5][];
Peter Lawrey
fuente
1
este es más flexible
hetaoblog
¿No debería definir un tamaño fijo en su matriz?
Filip
@Filip está fijo en 5. La configuración del siguiente nivel los asigna previamente, pero esto se puede cambiar, por lo que configurarlo podría no ser útil.
Peter Lawrey
8
¿Cómo inserto datos en la matriz? ¿Si son datos dinámicos?
Prakhar Mohan Srivastava
1
@PrakharMohanSrivastava puede configurar los elementos individualmente: arrays[0] = new String[] {"a", "b", "c"}o usar una lista temporal: <pre> <code> List <String []> myList = new ArrayList <> (); myList.add (new String [] {"a", "b", "c"}); myList.add (new String [] {"d", "e", "f"}); myList.toArray (matrices); </code> </pre>
kntx
26

Si bien hay dos respuestas excelentes que le dicen cómo hacerlo, creo que falta otra respuesta: en la mayoría de los casos, no debería hacerlo en absoluto.

Las matrices son engorrosas, en la mayoría de los casos es mejor usar la API de colección .

Con Colecciones, puede agregar y eliminar elementos y hay Colecciones especializadas para diferentes funcionalidades (búsqueda basada en índices, clasificación, singularidad, acceso FIFO, concurrencia, etc.).

Si bien, por supuesto, es bueno e importante conocer las matrices y su uso, en la mayoría de los casos, el uso de colecciones hace que las API sean mucho más manejables (razón por la cual las nuevas bibliotecas como Google Guava apenas usan matrices).

Entonces, para su escenario, preferiría una Lista de Listas, y la crearía usando Guava:

List<List<String>> listOfLists = Lists.newArrayList();
listOfLists.add(Lists.newArrayList("abc","def","ghi"));
listOfLists.add(Lists.newArrayList("jkl","mno","pqr"));
Sean Patrick Floyd
fuente
Un poco más complicado que String [] [], pero permite más operaciones como concatenar datos. Sin embargo, su solución no garantiza el tamaño de los datos, lo que puede ser un problema.
Benj
1
@Benj si es necesario, siempre es posible escribir un decorador de listas que solo acepte un cierto número de elementos.
Sean Patrick Floyd
Los decoradores / envoltorios exactos son una buena manera de garantizar la coherencia. Por lo tanto, la forma en que estamos hablando es mucho más compleja que las matrices simples. Lo que he hecho es una pequeña clase de utilidad Array2D <T> que encapsula algunos métodos básicos como exixts (...), etc. Publiqué esto a continuación.
Benj
6

está la clase que mencioné en el comentario que tuvimos con Sean Patrick Floyd: lo hice con un uso peculiar que necesita WeakReference, pero puedes cambiarlo por cualquier objeto con facilidad.

Espero que esto pueda ayudar a alguien algún día :)

import java.lang.ref.WeakReference;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.Queue;


/**
 *
 * @author leBenj
 */
public class Array2DWeakRefsBuffered<T>
{
    private final WeakReference<T>[][] _array;
    private final Queue<T> _buffer;

    private final int _width;

    private final int _height;

    private final int _bufferSize;

    @SuppressWarnings( "unchecked" )
    public Array2DWeakRefsBuffered( int w , int h , int bufferSize )
    {
        _width = w;
        _height = h;
        _bufferSize = bufferSize;
        _array = new WeakReference[_width][_height];
        _buffer = new LinkedList<T>();
    }

    /**
     * Tests the existence of the encapsulated object
     * /!\ This DOES NOT ensure that the object will be available on next call !
     * @param x
     * @param y
     * @return
     * @throws IndexOutOfBoundsException
     */public boolean exists( int x , int y ) throws IndexOutOfBoundsException
    {
        if( x >= _width || x < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (get) : [ x = " + x + "]" );
        }
        if( y >= _height || y < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (get) : [ y = " + y + "]" );
        }
        if( _array[x][y] != null )
        {
            T elem = _array[x][y].get();
            if( elem != null )
            {
            return true;
            }
        }
        return false;
    }

    /**
     * Gets the encapsulated object
     * @param x
     * @param y
     * @return
     * @throws IndexOutOfBoundsException
     * @throws NoSuchElementException
     */
    public T get( int x , int y ) throws IndexOutOfBoundsException , NoSuchElementException
    {
        T retour = null;
        if( x >= _width || x < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (get) : [ x = " + x + "]" );
        }
        if( y >= _height || y < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (get) : [ y = " + y + "]" );
        }
        if( _array[x][y] != null )
        {
            retour = _array[x][y].get();
            if( retour == null )
            {
            throw new NoSuchElementException( "Dereferenced WeakReference element at [ " + x + " ; " + y + "]" );
            }
        }
        else
        {
            throw new NoSuchElementException( "No WeakReference element at [ " + x + " ; " + y + "]" );
        }
        return retour;
    }

    /**
     * Add/replace an object
     * @param o
     * @param x
     * @param y
     * @throws IndexOutOfBoundsException
     */
    public void set( T o , int x , int y ) throws IndexOutOfBoundsException
    {
        if( x >= _width || x < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (set) : [ x = " + x + "]" );
        }
        if( y >= _height || y < 0 )
        {
            throw new IndexOutOfBoundsException( "Index out of bounds (set) : [ y = " + y + "]" );
        }
        _array[x][y] = new WeakReference<T>( o );

        // store local "visible" references : avoids deletion, works in FIFO mode
        _buffer.add( o );
        if(_buffer.size() > _bufferSize)
        {
            _buffer.poll();
        }
    }

}

Ejemplo de cómo usarlo:

// a 5x5 array, with at most 10 elements "bufferized" -> the last 10 elements will not be taken by GC process
Array2DWeakRefsBuffered<Image> myArray = new Array2DWeakRefsBuffered<Image>(5,5,10);
Image img = myArray.set(anImage,0,0);
if(myArray.exists(3,3))
{
    System.out.println("Image at 3,3 is still in memory");
}
Benj
fuente
4
+1 por su esfuerzo, pero: en lugar de inicializar sus campos int a -1 y reasignarlos en el Constructor, debe hacerlos finales y asignarlos solo en el Constructor.
Sean Patrick Floyd
1
@Sean: Modifiqué el código (publiqué uno nuevo con "búfer sin GC", incluido su sabio comentario.
Benj