¿Tamaños de matriz dinámica de Java?

106

Tengo una clase - xClass, que quiero cargar en una matriz de xClass, entonces la declaración:

xClass mysclass[] = new xClass[10];
myclass[0] = new xClass();
myclass[9] = new xClass();

Sin embargo, no sé si necesitaré 10. Es posible que necesite 8 o 12 o cualquier otro número para el caso. No lo sabré hasta el tiempo de ejecución. ¿Puedo cambiar la cantidad de elementos en una matriz sobre la marcha? ¿Si es así, cómo?

Pablo
fuente
Arreglé el formato de la pregunta, puedes solo el título si quieres, solo sé descriptivo. ¡y bienvenido a stackoverflow! : D
Gordon Gustafson

Respuestas:

164

No, no puede cambiar el tamaño de una matriz una vez creada. Tiene que asignarlo más grande de lo que cree que necesitará o aceptar la sobrecarga de tener que reasignarlo para que crezca en tamaño. Cuando lo haga, tendrá que asignar uno nuevo y copiar los datos del antiguo al nuevo:

int[] oldItems = new int[10];
for (int i = 0; i < 10; i++) {
    oldItems[i] = i + 10;
}
int[] newItems = new int[20];
System.arraycopy(oldItems, 0, newItems, 0, 10);
oldItems = newItems;

Si se encuentra en esta situación, le recomiendo encarecidamente utilizar las colecciones de Java. En particular, ArrayListesencialmente envuelve una matriz y se encarga de la lógica para hacer crecer la matriz según sea necesario:

List<XClass> myclass = new ArrayList<XClass>();
myclass.add(new XClass());
myclass.add(new XClass());

En general, an ArrayListes una solución preferible a una matriz de todos modos por varias razones. Por un lado, las matrices son mutables. Si tienes una clase que hace esto:

class Myclass {
    private int[] items;

    public int[] getItems() {
        return items;
    }
}

ha creado un problema ya que una persona que llama puede cambiar su miembro de datos privados, lo que conduce a todo tipo de copias defensivas. Compare esto con la versión de la lista:

class Myclass {
    private List<Integer> items;

    public List<Integer> getItems() {
        return Collections.unmodifiableList(items);
    }
}
cletus
fuente
1
List es la interfaz y ArrayList es la implementación. Crearlo como ArrayList pero referirse a él como List (para que pueda cambiar más tarde) es correcto.
CBGraham
26

En java, la longitud de la matriz es fija.

Puede utilizar una lista para mantener los valores e invocar el toArraymétodo si es necesario. Consulte el siguiente ejemplo:

import java.util.List;
import java.util.ArrayList;
import java.util.Random;

public class A  {

    public static void main( String [] args ) {
        // dynamically hold the instances
        List<xClass> list = new ArrayList<xClass>();

        // fill it with a random number between 0 and 100
        int elements = new Random().nextInt(100);  
        for( int i = 0 ; i < elements ; i++ ) {
            list.add( new xClass() );
        }

        // convert it to array
        xClass [] array = list.toArray( new xClass[ list.size() ] );


        System.out.println( "size of array = " + array.length );
    }
}
class xClass {}
OscarRyz
fuente
8

Como han dicho otros, no puede cambiar el tamaño de una matriz Java existente.

ArrayList es lo más cercano que tiene Java estándar a una matriz de tamaño dinámico. Sin embargo, hay algunas cosas sobre ArrayList (en realidad, la interfaz List) que no son "como una matriz". Por ejemplo:

  • No se puede utilizar [ ... ]para indexar una lista. Tienes que usar los métodos get(int)y set(int, E).
  • Una ArrayList se crea con cero elementos. No puede simplemente crear una ArrayList con 20 elementos y luego llamar set(15, foo).
  • No puede cambiar directamente el tamaño de una ArrayList. Usted lo hace indirectamente utilizando los diversos add, inserty removemétodos.

Si desea algo más parecido a una matriz, deberá diseñar su propia API. (Tal vez alguien podría intervenir con una biblioteca de terceros existente ... no pude encontrar una con 2 minutos de "investigación" usando Google :-))

Si solo necesita una matriz que crece a medida que la inicializa , entonces la solución es algo como esto.

ArrayList<T> tmp = new ArrayList<T>();
while (...) {
    tmp.add(new T(...));
}
// This creates a new array and copies the element of 'tmp' to it.
T[] array = tmp.toArray(new T[tmp.size()]);
Stephen C
fuente
7

Establece el número de elementos en cualquier cosa que desee en el momento de crearlo:

xClass[] mysclass = new xClass[n];

Luego, puede inicializar los elementos en un bucle. Supongo que esto es lo que necesitas.

Si necesita agregar o eliminar elementos a la matriz después de crearla, tendrá que usar un archivo ArrayList.

newacct
fuente
6

Puede utilizar ArrayList:

import java.util.ArrayList;
import java.util.Iterator;

...

ArrayList<String> arr = new ArrayList<String>();
arr.add("neo");
arr.add("morpheus");
arr.add("trinity");
Iterator<String> foreach = arr.iterator();
while (foreach.hasNext()) System.out.println(foreach.next());
Pascal9x
fuente
3

Arrays.copyOf() El método tiene muchas opciones para solucionar el problema con el aumento dinámico de la longitud de la matriz.

API de Java

hombre.2067067
fuente
Para ser específico: if (i> = mysclass.length) mysclass = Arrays.copyOf (mysclass, i + 1); mysclass [i] = new MyClass ();
Micha Berger
2

Sí, envuélvalo y use el marco de Colecciones.

List l = new ArrayList();
l.add(new xClass());
// do stuff
l.add(new xClass());

Luego use List.toArray () cuando sea necesario, o simplemente itere sobre dicha List.

Jé Queue
fuente
2

Como dicen otros usuarios, probablemente necesite una implementación de java.util.List.

Si, por alguna razón, finalmente necesita una matriz, puede hacer dos cosas:

  • Use una lista y luego conviértala en una matriz con myList.toArray ()

  • Utilice una matriz de cierto tamaño. Si necesita más o menos tamaño, puede modificarlo con los métodos java.util.Arrays.

La mejor solución dependerá de su problema;)

sinuhepop
fuente
2

Recomiendo usar vectores en su lugar. Muy fácil de usar y tiene muchos métodos predefinidos de implementación.

import java.util.*;

Vector<Integer> v=new Vector<Integer>(5,2);

para agregar un elemento simplemente use:

v.addElement(int);

En (5,2), los primeros 5 son el tamaño inicial del vector. Si excede el tamaño inicial, el vector crecerá 2 lugares. Si vuelve a excederse, volverá a aumentar en 2 lugares y así sucesivamente.

Shashank Raghunath
fuente
4
A menos que necesite específicamente un tipo seguro para subprocesos (-ish), debe usar ArrayList en lugar de Vector.
Stephen C
1

Donde declara la matriz myclass [] como:

xClass myclass[] = new xClass[10]

, simplemente pase como argumento el número de elementos XClass que necesitará. En ese momento, ¿sabe cuántos necesitará? Al declarar que la matriz tiene 10 elementos, no declara 10 objetos XClass, simplemente está creando una matriz con 10 elementos de tipo xClass.

Amir Afghani
fuente
1

Los tamaños de las matrices de Java son fijos. No se pueden crear matrices dinámicas como en C ++.


fuente
0

Es una buena práctica obtener la cantidad que necesita almacenar primero y luego inicializar la matriz.

por ejemplo, le preguntaría al usuario cuántos datos necesita almacenar y luego lo inicializaría, o consultaría el componente o argumento de cuántos necesita almacenar. Si desea una matriz dinámica, puede usar ArrayList()y usar la al.add();función para seguir agregando, entonces puede transferirla a una matriz fija.

//Initialize ArrayList and cast string so ArrayList accepts strings (or anything
ArrayList<string> al = new ArrayList(); 
//add a certain amount of data
for(int i=0;i<x;i++)
{
  al.add("data "+i); 
}

//get size of data inside
int size = al.size(); 
//initialize String array with the size you have
String strArray[] = new String[size]; 
//insert data from ArrayList to String array
for(int i=0;i<size;i++)
{
  strArray[i] = al.get(i);
}

hacerlo es redundante, pero sólo para mostrar la idea, ArrayListpuede sostener objetos a diferencia de otros tipos de datos simples y son muy fáciles de manipular, la eliminación de cualquier cosa, desde el centro es fácil, así, por completo con dynamic.same ListyStack

bakz
fuente
0

No sé si puede cambiar el tamaño en tiempo de ejecución, pero puede asignar el tamaño en tiempo de ejecución. Intente usar este código:

class MyClass {
    void myFunction () {
        Scanner s = new Scanner (System.in);
        int myArray [];
        int x;

        System.out.print ("Enter the size of the array: ");
        x = s.nextInt();

        myArray = new int[x];
    }
}

esto asigna el tamaño de su matriz para que sea el que se ingresó en el tiempo de ejecución en x.

Maranatha
fuente
0

Aquí hay un método que no usa ArrayList. El usuario especifica el tamaño y puede agregar un bucle do-while para la recursividad.

import java.util.Scanner;
    public class Dynamic {
        public static Scanner value;
        public static void main(String[]args){
            value=new Scanner(System.in);
            System.out.println("Enter the number of tests to calculate average\n");
            int limit=value.nextInt();
            int index=0;
            int [] marks=new int[limit];
            float sum,ave;
            sum=0;      
            while(index<limit)
            {
                int test=index+1;
                System.out.println("Enter the marks on test " +test);
                marks[index]=value.nextInt();
                sum+=marks[index];
                index++;
            }
            ave=sum/limit;
            System.out.println("The average is: " + ave);
        }
    }
wallace_stev
fuente
0

En Java, los tamaños de matriz son siempre de longitud fija, pero hay una forma en la que puede aumentar dinámicamente el tamaño de la matriz en tiempo de ejecución.

Esta es la forma más "utilizada" y preferida de hacerlo.

    int temp[]=new int[stck.length+1];
    for(int i=0;i<stck.length;i++)temp[i]=stck[i];
    stck=temp;

En el código anterior estamos inicializando una nueva matriz temp [], y además usamos un bucle for para inicializar el contenido de la temp con el contenido de la matriz original, es decir. stck []. Y luego copiarlo nuevamente al original, lo que nos da una nueva matriz de TAMAÑO nuevo.

Sin duda, genera una sobrecarga de CPU debido a la reinicialización de una matriz usando el bucle for repetidamente. Pero aún puede usarlo e implementarlo en su código. Para las mejores prácticas, use "Lista enlazada" en lugar de Array, si desea que los datos se almacenen dinámicamente en la memoria, de longitud variable.

Aquí hay un ejemplo en tiempo real basado en pilas dinámicas para AUMENTAR EL TAMAÑO DE LA ARRAY en tiempo de ejecución

Nombre de archivo: DStack.java

public class DStack {
private int stck[];
int tos;

void Init_Stck(int size) {
    stck=new int[size];
    tos=-1;
}
int Change_Stck(int size){
    return stck[size];
}

public void push(int item){
    if(tos==stck.length-1){
        int temp[]=new int[stck.length+1];
        for(int i=0;i<stck.length;i++)temp[i]=stck[i];
        stck=temp;
        stck[++tos]=item;
    }
    else
        stck[++tos]=item;
}
public int pop(){
    if(tos<0){
        System.out.println("Stack Underflow");
        return 0;
    }
    else return stck[tos--];
}

public void display(){
    for(int x=0;x<stck.length;x++){
        System.out.print(stck[x]+" ");
    }
    System.out.println();
}

}

Nombre de archivo: Exec.java
(con la clase principal)

import java.util.*;
public class Exec {

private static Scanner in;

public static void main(String[] args) {
    in = new Scanner(System.in);
    int option,item,i=1;
    DStack obj=new DStack();
    obj.Init_Stck(1);
    do{
        System.out.println();
        System.out.println("--MENU--");
        System.out.println("1. Push a Value in The Stack");
        System.out.println("2. Pop a Value from the Stack");
        System.out.println("3. Display Stack");
        System.out.println("4. Exit");
        option=in.nextInt();
        switch(option){
        case 1:
            System.out.println("Enter the Value to be Pushed");
            item=in.nextInt();
            obj.push(item);
            break;
        case 2:
            System.out.println("Popped Item: "+obj.pop());
            obj.Change_Stck(obj.tos);
            break;
        case 3:
            System.out.println("Displaying...");
            obj.display();
            break;
        case 4:
            System.out.println("Exiting...");
            i=0;
            break;
        default:
            System.out.println("Enter a Valid Value");

        }
    }while(i==1);

}

}

Espero que esto resuelva su consulta.

Jatin Chauhan
fuente
0

Sí, podemos hacerlo de esta manera.

import java.util.Scanner;

public class Collection_Basic {

    private static Scanner sc;

    public static void main(String[] args) {

        Object[] obj=new Object[4];
        sc = new Scanner(System.in);


        //Storing element
        System.out.println("enter your element");
        for(int i=0;i<4;i++){
            obj[i]=sc.nextInt();
        }

        /*
         * here, size reaches with its maximum capacity so u can not store more element,
         * 
         * for storing more element we have to create new array Object with required size
         */

        Object[] tempObj=new Object[10];

        //copying old array to new Array

        int oldArraySize=obj.length;
        int i=0;
        for(;i<oldArraySize;i++){

            tempObj[i]=obj[i];
        }

        /*
         * storing new element to the end of new Array objebt
         */
        tempObj[i]=90;

        //assigning new array Object refeence to the old one

        obj=tempObj;

        for(int j=0;j<obj.length;j++){
            System.out.println("obj["+j+"] -"+obj[j]);
        }
    }


}
jyoti bhushan
fuente
0

Dado que ArrayList ocupa mucha memoria cuando necesito una matriz de tipos primitivos, prefiero usar IntStream.builder () para crear una matriz int (también puede usar los constructores LongStream y DoubleStream).

Ejemplo:

Builder builder = IntStream.builder();
int arraySize = new Random().nextInt();
for(int i = 0; i<arraySize; i++ ) {
    builder.add(i);
}
int[] array = builder.build().toArray();

Nota: disponible desde Java 8.

Bosko Popovic
fuente
0

Puedes hacer algo

private  static Person []  addPersons(Person[] persons, Person personToAdd) {
    int currentLenght = persons.length;

    Person [] personsArrayNew = Arrays.copyOf(persons, currentLenght +1);
    personsArrayNew[currentLenght]  = personToAdd;

    return personsArrayNew;

}
Chinthaka Devinda
fuente