Tamanhos de array dinâmico Java?

106

Eu tenho uma classe - xClass, que desejo carregar em uma matriz de xClass, então faço a declaração:

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

No entanto, não sei se vou precisar de 10. Posso precisar de 8 ou 12 ou qualquer outro número para esse assunto. Eu não saberei até o tempo de execução. Posso alterar o número de elementos em uma matriz rapidamente? Se sim, como?

Paulo
fonte
Eu corrigi a formatação da pergunta, você pode apenas o título se quiser, apenas descritivo. e bem-vindo ao stackoverflow! : D
Gordon Gustafson

Respostas:

164

Não, você não pode alterar o tamanho de uma matriz uma vez criada. Você deve alocá-lo maior do que pensa que precisará ou aceitar a sobrecarga de ter que realocá-lo para crescer em tamanho. Quando isso acontecer, você terá que alocar um novo e copiar os dados do antigo para o novo:

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;

Se você se encontrar nesta situação, eu recomendo usar as coleções Java. Em particular, ArrayListessencialmente envolve uma matriz e cuida da lógica para aumentar a matriz conforme necessário:

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

Geralmente um ArrayListé uma solução preferível para um array por vários motivos. Por um lado, os arrays são mutáveis. Se você tem uma classe que faz isso:

class Myclass {
    private int[] items;

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

você criou um problema, pois um chamador pode alterar seu membro de dados privado, o que leva a todos os tipos de cópia defensiva. Compare isso com a versão da lista:

class Myclass {
    private List<Integer> items;

    public List<Integer> getItems() {
        return Collections.unmodifiableList(items);
    }
}
cletus
fonte
1
List é a interface e ArrayList é a implementação. Criá-lo como um ArrayList, mas referindo-se a ele como uma lista (para que possa mudar mais tarde) está correto.
CBGraham
26

Em java, o comprimento do array é fixo.

Você pode usar uma lista para conter os valores e invocar o toArraymétodo, se necessário. Consulte o exemplo a seguir:

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
fonte
8

Como já foi dito, você não pode alterar o tamanho de um array Java existente.

ArrayList é o mais próximo que o Java padrão tem de uma matriz de tamanho dinâmico. No entanto, existem algumas coisas sobre ArrayList (na verdade, a interface List) que não são "semelhantes a array". Por exemplo:

  • Você não pode usar [ ... ]para indexar uma lista. Você deve usar os métodos get(int)e set(int, E).
  • Um ArrayList é criado com zero elementos. Você não pode simplesmente criar um ArrayList com 20 elementos e depois chamar set(15, foo).
  • Você não pode alterar diretamente o tamanho de um ArrayList. Você fazê-lo indiretamente usando os vários add, inserte removemétodos.

Se você quiser algo mais parecido com array, precisará projetar sua própria API. (Talvez alguém possa entrar em contato com uma biblioteca existente de terceiros ... Não consegui encontrar uma com 2 minutos de "pesquisa" usando o Google :-))

Se você realmente precisa apenas de um array que cresce conforme você o inicializa , a solução é algo assim.

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
fonte
7

Você define o número de elementos como quiser no momento em que os cria:

xClass[] mysclass = new xClass[n];

Então você pode inicializar os elementos em um loop. Suponho que é disso que você precisa.

Se você precisar adicionar ou remover elementos do array depois de criá-lo, terá que usar um ArrayList.

newacct
fonte
6

Você pode usar 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
fonte
3

Arrays.copyOf() método tem muitas opções para corrigir o problema com o comprimento do Array aumentando dinamicamente.

API Java

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

Sim, envolva-o e use a estrutura de coleções.

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

Em seguida, use List.toArray () quando necessário ou apenas itere sobre a referida Lista.

Jé Queue
fonte
2

Como outros usuários dizem, você provavelmente precisa de uma implementação de java.util.List.

Se, por algum motivo, você finalmente precisar de uma matriz, poderá fazer duas coisas:

  • Use uma lista e converta-a em uma matriz com myList.toArray ()

  • Use uma matriz de determinado tamanho. Se você precisar de mais ou menos tamanho, pode modificá-lo com os métodos java.util.Arrays.

A melhor solução dependerá do seu problema;)

sinuhepop
fonte
2

Eu recomendo usar vetores em vez disso. Muito fácil de usar e possui vários métodos predefinidos de implementação.

import java.util.*;

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

para adicionar um elemento, basta usar:

v.addElement(int);

Em (5,2), os primeiros 5 são o tamanho inicial do vetor. Se você exceder o tamanho inicial, o vetor aumentará 2 casas. Se exceder novamente, aumentará novamente em 2 casas e assim por diante.

Shashank Raghunath
fonte
4
A menos que você precise especificamente de um tipo thread-safe (-ish), você deve usar ArrayList em vez de Vector.
Stephen C
1

Onde você declara a matriz myclass [] como:

xClass myclass[] = new xClass[10]

, simplesmente passe como argumento o número de elementos XClass de que você precisa. Nesse ponto, você sabe de quantos você precisará? Ao declarar a matriz como tendo 10 elementos, você não está declarando 10 objetos XClass, mas simplesmente criando uma matriz com 10 elementos do tipo xClass.

Amir Afghani
fonte
1

Os tamanhos do array Java são fixos, você não pode criar arrays dinâmicos como no C ++.


fonte
0

É uma boa prática obter a quantidade que você precisa armazenar primeiro e, em seguida, inicializar o array.

por exemplo, você perguntaria ao usuário quantos dados ele precisa armazenar e, em seguida, inicializaria, ou consultaria o componente ou argumento de quantos dados você precisa armazenar. se quiser um array dinâmico, você pode usar ArrayList()e usar a al.add();função para continuar adicionando, então você pode transferi-lo para um array fixo.

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

isso é redundante, mas apenas para mostrar-lhe a idéia, ArrayListpode segurar objetos ao contrário de outros tipos de dados primitivos e são muito fáceis de manipular, remover qualquer coisa a partir do meio é tão fácil assim, completamente dynamic.same com ListeStack

Bakz
fonte
0

Não sei se você pode alterar o tamanho em tempo de execução, mas você pode alocar o tamanho em tempo de execução. Tente 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];
    }
}

isso atribui o tamanho do seu array aquele inserido em tempo de execução em x.

Maranatha
fonte
0

Aqui está um método que não usa ArrayList. O usuário especifica o tamanho e você pode adicionar um loop do-while para recursão.

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
fonte
0

Em Java Array, os tamanhos são sempre de comprimento fixo, mas há uma maneira de aumentar dinamicamente o tamanho do array no próprio tempo de execução

Esta é a maneira mais "usada" e preferida de fazer isso-

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

No código acima, estamos inicializando um novo array temp [] e, posteriormente, usando um loop for para inicializar o conteúdo do temp com o conteúdo do array original, ou seja. stck []. E, em seguida, copiá-lo novamente para o original, nos dando uma nova matriz de novo SIZE.

Sem dúvida, ele gera uma sobrecarga de CPU devido à reinicialização de um array usando o loop for repetidamente. Mas você ainda pode usar e implementar em seu código. Para a melhor prática, use "Linked List" em vez de Array, se quiser que os dados sejam armazenados dinamicamente na memória, de comprimento variável.

Aqui está um exemplo em tempo real baseado em pilhas dinâmicas para AUMENTAR O TAMANHO DA ARRAY em tempo de execução

Nome do arquivo: 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();
}

}

Nome do arquivo: Exec.java
(com a classe 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 isso resolva sua dúvida.

Jatin Chauhan
fonte
0

Sim, podemos fazer assim.

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
fonte
0

Visto que ArrayList consome muita memória quando preciso de uma matriz de tipos primitivos, prefiro usar IntStream.builder () para criar uma matriz int (você também pode usar os construtores LongStream e DoubleStream).

Exemplo:

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: disponível desde Java 8.

Bosko Popovic
fonte
0

Você pode fazer alguma coisa

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
fonte