Размеры динамических массивов Java?

106

У меня есть класс - xClass, который я хочу загрузить в массив xClass, поэтому я декларирую:

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

Однако я не знаю, понадобится ли мне 10. Мне может понадобиться 8, 12 или любой другой номер в этом отношении. Я не узнаю до времени выполнения. Могу ли я изменять количество элементов в массиве на лету? Если да, то как?

Павел
источник
Я исправил форматирование вопроса, вы можете просто заголовок, если хотите, просто описательный. и добро пожаловать в stackoverflow! : D
Гордон Густафсон

Ответы:

164

Нет, вы не можете изменить размер созданного массива. Вы должны либо выделить его больше, чем вы думаете, что вам нужно, либо принять накладные расходы на перераспределение, необходимые для увеличения размера. Когда это произойдет, вам придется выделить новый и скопировать данные из старого в новый:

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;

Если вы окажетесь в такой ситуации, я настоятельно рекомендую вместо этого использовать Коллекции Java. В частности, по ArrayListсуществу обертывает массив и заботится о логике увеличения массива по мере необходимости:

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

Как правило, в ArrayListлюбом случае предпочтительным решением является массив по нескольким причинам. Во-первых, массивы изменяемы. Если у вас есть класс, который делает это:

class Myclass {
    private int[] items;

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

вы создали проблему, так как вызывающий абонент может изменить ваш личный член данных, что приводит ко всем видам защитного копирования. Сравните это с версией списка:

class Myclass {
    private List<Integer> items;

    public List<Integer> getItems() {
        return Collections.unmodifiableList(items);
    }
}
Cletus
источник
1
Список - это интерфейс, а ArrayList - реализация. Правильно создать его как ArrayList, но называть его списком (чтобы он мог измениться позже).
CBGraham
26

В java длина массива фиксирована.

Вы можете использовать список для хранения значений и toArrayпри необходимости вызывать метод. См. Следующий пример:

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
источник
8

Как говорили другие, вы не можете изменить размер существующего массива Java.

ArrayList - это наиболее близкий стандарт Java к массиву динамического размера. Однако в ArrayList (фактически интерфейсе List) есть кое-что, что не похоже на массив. Например:

  • Вы не можете использовать [ ... ]для индексации списка. Вы должны использовать get(int)и set(int, E)методы.
  • ArrayList создается с нулевыми элементами. Вы не можете просто создать ArrayList из 20 элементов, а затем вызвать set(15, foo).
  • Вы не можете напрямую изменить размер ArrayList. Вы делаете это косвенно , используя различные add, insertи removeметоды.

Если вы хотите что-то более похожее на массив, вам нужно будет разработать свой собственный API. (Может быть, кто-то сможет подключиться к существующей сторонней библиотеке ... Я не смог найти ни одной с двухминутным «исследованием» с помощью Google :-))

Если вам действительно нужен только массив, который растет по мере его инициализации , тогда решение будет примерно таким.

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()]);
Стивен С
источник
7

Вы устанавливаете количество элементов на все, что хотите, во время его создания:

xClass[] mysclass = new xClass[n];

Затем вы можете инициализировать элементы в цикле. Полагаю, это то, что вам нужно.

Если вам нужно добавить или удалить элементы в массив после его создания, вам придется использовать файл ArrayList.

newacct
источник
6

Вы можете использовать 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
источник
3

Arrays.copyOf() Метод имеет много вариантов решения проблемы с динамическим увеличением длины массива.

Java API

мужчина.2067067
источник
Чтобы быть конкретным: if (i> = mysclass.length) mysclass = Arrays.copyOf (mysclass, i + 1); mysclass [я] = новый MyClass ();
Мика Бергер
2

Да, заверните его и используйте фреймворк Коллекций.

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

Затем используйте List.toArray (), когда это необходимо, или просто перебирайте указанный List.

Jé Queue
источник
2

Как говорят другие пользователи, вам, вероятно, понадобится реализация java.util.List.

Если по какой-то причине вам наконец понадобится массив, вы можете сделать две вещи:

  • Используйте список, а затем преобразуйте его в массив с помощью myList.toArray ()

  • Используйте массив определенного размера. Если вам нужен больший или меньший размер, вы можете изменить его с помощью методов java.util.Arrays.

Лучшее решение будет зависеть от вашей проблемы;)

Sinuhepop
источник
2

Вместо этого я рекомендую использовать векторы. Очень прост в использовании и имеет множество предопределенных методов для реализации.

import java.util.*;

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

чтобы добавить элемент, просто используйте:

v.addElement(int);

В (5,2) первые 5 - это начальный размер вектора. Если вы превысите начальный размер, вектор вырастет на 2 места. Если снова превысит, то снова увеличится на 2 места и так далее.

Шашанк Рагхунатх
источник
4
Если вам специально не нужен потокобезопасный (-ish) тип, вам следует использовать ArrayList, а не Vector.
Stephen C
1

Где вы объявляете массив myclass [] как:

xClass myclass[] = new xClass[10]

, просто передайте в качестве аргумента количество необходимых вам элементов XClass. В этот момент вы знаете, сколько вам понадобится? Объявляя массив как имеющий 10 элементов, вы не объявляете 10 объектов XClass, вы просто создаете массив из 10 элементов типа xClass.

Амир Афгани
источник
1

Размеры массивов Java фиксированы. Вы не можете создавать динамические массивы, как в C ++.


источник
0

Рекомендуется сначала получить сумму, которую нужно сохранить, а затем инициализировать массив.

например, вы могли бы спросить пользователя, сколько данных ему нужно сохранить, а затем инициализировать его, или запросить компонент или аргумент, сколько вам нужно сохранить. если вам нужен динамический массив, который вы могли бы использовать ArrayList()и использовать al.add();функцию для продолжения добавления, вы можете передать его в фиксированный массив.

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

делать это излишне, но просто чтобы показать вам идею, ArrayListможет содержать объекты, в отличие от других примитивных типов данных, и ими очень легко манипулировать, также легко удалить что-либо из середины, полностью динамически. то же самое с ListиStack

бакз
источник
0

Я не знаю, можете ли вы изменить размер во время выполнения, но вы можете выделить размер во время выполнения. Попробуйте использовать этот код:

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];
    }
}

это назначает размер вашего массива, чтобы он был введен во время выполнения в x.

Маранафа
источник
0

Вот метод, который не использует ArrayList. Пользователь указывает размер, и вы можете добавить цикл do-while для рекурсии.

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
источник
0

В Java размеры массивов всегда имеют фиксированную длину, но есть способ, которым вы можете динамически увеличивать размер массива во время выполнения.

Это наиболее "используемый", а также предпочтительный способ сделать это -

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

В приведенном выше коде мы инициализируем новый массив temp [] и далее используем цикл for для инициализации содержимого временного массива содержимым исходного массива, т.е. stck []. А затем снова копируем его обратно в исходный, давая нам новый массив new SIZE.

Несомненно, это вызывает накладные расходы ЦП из-за повторной инициализации массива с многократным использованием цикла for. Но вы все равно можете использовать и реализовать его в своем коде. Лучше всего использовать «Связанный список» вместо массива, если вы хотите, чтобы данные переменной длины динамически сохранялись в памяти.

Вот пример в реальном времени, основанный на динамических стеках, для увеличения размера массива во время выполнения

Имя файла: 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();
}

}

Имя файла: Exec.java
(с основным классом)

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

}

}

Надеюсь, это решит ваш вопрос.

Джатин Чаухан
источник
0

Да, мы можем так поступить.

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


}
джйоти бхушан
источник
0

Поскольку ArrayList занимает много памяти, когда мне нужен массив примитивных типов, я предпочитаю использовать IntStream.builder () для создания массива int (вы также можете использовать построители LongStream и DoubleStream).

Пример:

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

Примечание: доступно с Java 8.

Боско Попович
источник
0

Ты можешь кое-что сделать

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

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

    return personsArrayNew;

}
Чинтака Девинда
источник