Comment créer un tableau de tableaux en Java

115

Hypothétiquement, j'ai 5 objets de tableau de chaînes:

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

et je veux qu'un autre objet de tableau contienne ces 5 objets de tableau de chaîne. Comment fait-on ça? Puis-je le mettre dans un autre tableau?

Terence Ponce
la source
43
Les questions Noob peuvent être sérieuses. En fait, ils le sont souvent. :-)
TJ Crowder
3
La question pertinente et la réponse ne sont pas évidentes pour qui sait comment l'alignement de la mémoire est effectué. +1
Benj

Réponses:

153

Comme ça:

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

ou

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

(Cette dernière syntaxe peut être utilisée dans des affectations autres qu'au point de déclaration de variable, alors que la syntaxe plus courte ne fonctionne qu'avec les déclarations.)

Jon Skeet
la source
Pourriez-vous expliquer davantage ce que fait la seconde syntaxe? Ce n'est pas clair pour moi.
Terence Ponce
4
@Terence: Il fait la même chose que le premier: il crée un tableau de références de tableau de chaînes, initialisé aux valeurs array1, array2, array3, array4 et array5 - dont chacun est en soi une référence de tableau de chaînes.
Jon Skeet
1
Question rapide: Comment vais-je faire cela au moment de l'exécution si je n'ai aucune idée du nombre d'objets de tableau qui seront créés?
Terence Ponce le
1
@Terence: Pouvez-vous donner un exemple plus précis? Lorsque vous spécifiez les valeurs initiales à la compilation, vous ne connaissez la taille. Voulez-vous dire quelque chose comme new String[10][]?
Jon Skeet
Oui. Similaire à la réponse de Peter.
Terence Ponce
71

essayer

String[][] arrays = new String[5][];
Peter Lawrey
la source
1
celui-ci est plus flexible
hetaoblog
Ne devriez-vous pas définir une taille fixe sur votre tableau?
Filip
@Filip, il est fixé à 5. La définition du niveau suivant les pré-attribue, mais cela peut être changé afin de ne pas être utile.
Peter Lawrey
8
Comment insérer des données dans le tableau? Si ses données dynamiques?
Prakhar Mohan Srivastava
1
@PrakharMohanSrivastava vous pouvez définir les éléments individuellement: arrays[0] = new String[] {"a", "b", "c"}ou utiliser une liste temporaire: <pre> <code> List <String []> myList = new ArrayList <> (); maListe.add (nouvelle chaîne [] {"a", "b", "c"}); maListe.add (nouvelle chaîne [] {"d", "e", "f"}); myList.toArray (tableaux); </code> </pre>
kntx
26

Bien qu'il existe deux excellentes réponses qui vous indiquent comment le faire, je pense qu'une autre réponse manque: dans la plupart des cas, vous ne devriez pas le faire du tout.

Les tableaux sont encombrants, dans la plupart des cas, il vaut mieux utiliser l' API Collection .

Avec les collections, vous pouvez ajouter et supprimer des éléments et il existe des collections spécialisées pour différentes fonctionnalités (recherche basée sur un index, tri, unicité, accès FIFO, concurrence, etc.).

Bien qu'il soit bien sûr bon et important de connaître les tableaux et leur utilisation, dans la plupart des cas, l'utilisation de collections rend les API beaucoup plus gérables (c'est pourquoi de nouvelles bibliothèques comme Google Guava utilisent à peine les tableaux).

Donc, pour votre scénario, je préférerais une liste de listes, et je la créerais en utilisant Guava:

List<List<String>> listOfLists = Lists.newArrayList();
listOfLists.add(Lists.newArrayList("abc","def","ghi"));
listOfLists.add(Lists.newArrayList("jkl","mno","pqr"));
Sean Patrick Floyd
la source
Un peu plus compliqué que String [] [], mais permet plus d'opérations telles que la concaténation de données. Cependant, votre solution ne garantit pas la taille des données, ce qui peut poser problème.
Benj
1
@Benj si nécessaire, il est toujours possible d'écrire un décorateur de liste qui n'accepte qu'un certain nombre d'éléments.
Sean Patrick Floyd
Exacts, les décorateurs / emballages sont un bon moyen d'assurer la cohérence. Ainsi, la façon dont nous parlons est bien plus complexe que de simples tableaux. Ce que j'ai fait est une petite classe utilitaire Array2D <T> qui encapsule certaines méthodes de base telles que les exixts (...) etc. J'ai posté ceci ci-dessous.
Benj
6

il y a la classe que j'ai mentionnée dans le commentaire que nous avons eu avec Sean Patrick Floyd: je l'ai fait avec une utilisation particulière qui nécessite WeakReference, mais vous pouvez la changer par n'importe quel objet avec facilité.

En espérant que cela puisse aider quelqu'un un jour :)

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

}

Exemple d'utilisation:

// 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
la source
4
+1 pour votre effort, mais: au lieu d'initialiser vos champs int à -1 et de les réaffecter dans le constructeur, vous devriez les rendre définitifs et les affecter uniquement dans le constructeur.
Sean Patrick Floyd
1
@Sean: J'ai modifié le code (en a publié un nouveau avec "no-GC buffer", y compris votre sage commentaire.
Benj