Jak stworzyć tablicę tablic w Javie

115

Hipotetycznie mam 5 obiektów typu string:

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

i chcę, aby inny obiekt tablicy zawierał te 5 obiektów tablicy ciągów. Jak mam to zrobić? Czy mogę umieścić go w innej tablicy?

Terence Ponce
źródło
43
Pytania Nooba mogą być poważne. W rzeczywistości często tak jest. :-)
TJ Crowder
3
Odpowiednie pytanie i odpowiedź nie są oczywiste dla tego, kto wie, w jaki sposób odbywa się wyrównanie pamięci. +1
Benj

Odpowiedzi:

153

Lubię to:

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

lub

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

(Ta ostatnia składnia może być używana w przypisaniach innych niż w punkcie deklaracji zmiennej, podczas gdy krótsza składnia działa tylko z deklaracjami).

Jon Skeet
źródło
Czy mógłbyś dokładniej wyjaśnić, co robi druga składnia? To dla mnie trochę niejasne.
Terence Ponce
4
@Terence: Robi to samo, co pierwszy: tworzy tablicę odwołań do tablicy ciągów, zainicjowaną do wartości tablica1, tablica2, tablica3, tablica4 i tablica5 - z których każda jest sama w sobie odwołaniem do tablicy ciągów.
Jon Skeet,
1
Szybkie pytanie: jak mam to zrobić w czasie wykonywania, jeśli nie mam pojęcia, ile obiektów tablic zostanie utworzonych?
Terence Ponce
1
@Terence: Czy możesz podać bardziej konkretny przykład? Podczas określania wartości początkowe w czasie kompilacji, to należy znać rozmiar. Czy masz na myśli coś takiego new String[10][]?
Jon Skeet
Tak. Podobna do odpowiedzi Piotra.
Terence Ponce
71

próbować

String[][] arrays = new String[5][];
Peter Lawrey
źródło
1
ten jest bardziej elastyczny
hetaoblog
Nie powinieneś zdefiniować stałego rozmiaru w swojej tablicy?
Filip
@Filip jest ustalona na 5. Ustawienie następnego poziomu powoduje ich wstępną alokację, ale można to zmienić, więc ustawienie może nie być przydatne.
Peter Lawrey
8
Jak wstawić dane do tablicy? Jeśli to dynamiczne dane?
Prakhar Mohan Srivastava
1
@PrakharMohanSrivastava możesz ustawić elementy indywidualnie: arrays[0] = new String[] {"a", "b", "c"}lub użyj tymczasowej listy: <pre> <code> List <String []> myList = new ArrayList <> (); myList.add (new String [] {"a", "b", "c"}); myList.add (new String [] {"d", "e", "f"}); myList.toArray (tablice); </code> </pre>
kntx
26

Chociaż istnieją dwie doskonałe odpowiedzi, które podpowiadają, jak to zrobić, wydaje mi się, że brakuje innej odpowiedzi: w większości przypadków w ogóle nie powinieneś tego robić.

Tablice są uciążliwe, w większości przypadków lepiej jest korzystać z Collection API .

Dzięki kolekcjom możesz dodawać i usuwać elementy i istnieją wyspecjalizowane kolekcje dla różnych funkcji (wyszukiwanie oparte na indeksach, sortowanie, unikalność, dostęp FIFO, współbieżność itp.).

Chociaż oczywiście dobrze i ważne jest, aby wiedzieć o tablicach i ich użyciu, w większości przypadków używanie Kolekcji sprawia, że ​​API jest o wiele łatwiejsze w zarządzaniu (dlatego nowe biblioteki, takie jak Google Guava, prawie w ogóle nie używają tablic).

Więc dla twojego scenariusza wolałbym listę list i utworzyłbym ją przy użyciu guawy:

List<List<String>> listOfLists = Lists.newArrayList();
listOfLists.add(Lists.newArrayList("abc","def","ghi"));
listOfLists.add(Lists.newArrayList("jkl","mno","pqr"));
Sean Patrick Floyd
źródło
Nieco bardziej skomplikowane niż String [] [], ale pozwala na więcej operacji, takich jak łączenie danych. Jednak Twoje rozwiązanie nie zapewnia rozmiaru danych, co może być problemem.
Benj
1
@Benj w razie potrzeby zawsze można napisać dekorator listy, który akceptuje tylko określoną liczbę elementów.
Sean Patrick Floyd
Dokładnie, dekoratory / opakowania to dobry sposób na zapewnienie spójności. Tak więc sposób, o którym mówimy, jest znacznie bardziej złożony niż proste tablice. To, co zrobiłem, to mała klasa narzędziowa Array2D <T>, która zawiera kilka podstawowych metod, takich jak exixts (...) itp. Opublikowałem to poniżej.
Benj
6

jest klasa, o której wspomniałem w komentarzu, który mieliśmy z Seanem Patrickiem Floydem: zrobiłem to w szczególny sposób, który wymaga WeakReference, ale z łatwością można to zmienić za pomocą dowolnego obiektu.

Mam nadzieję, że kiedyś komuś to pomoże :)

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();
        }
    }

}

Przykład użycia:

// 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
źródło
4
+1 za twój wysiłek, ale: zamiast inicjalizować pola int na -1 i ponownie przypisywać je w Konstruktorze, powinieneś uczynić je ostatecznymi i przypisać je tylko w Konstruktorze.
Sean Patrick Floyd
1
@Sean: Zmodyfikowałem kod (opublikowałem nowy z "bez bufora GC", w tym twój mądry komentarz.
Benj