Розміри динамічного масиву 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);
    }
}

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 {}

8

Як говорили інші, ви не можете змінити розмір існуючого масиву Java.

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

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

Якщо ви хочете щось схоже на масив, вам потрібно буде розробити власний API. (Можливо, хтось міг би прислухатись до наявної сторонньої бібліотеки ... Я не зміг знайти те, що пройшло 2 хвилини "дослідження" за допомогою 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.


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

3

Arrays.copyOf() метод має багато варіантів, щоб вирішити проблему з збільшенням довжини масиву динамічно.

Java API


Щоб бути конкретним: якщо (i> = mysclass.length) mysclass = Arrays.copyOf (mysclass, i + 1); mysclass [i] = новий MyClass ();
Micha Berger

2

Так, заверніть його та використовуйте рамки Колекції.

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

Потім використовуйте List.toArray (), коли це необхідно, або просто перебирайте цей список.


2

Як кажуть інші користувачі, вам, мабуть, потрібна реалізація java.util.List.

Якщо з якоїсь причини вам нарешті потрібен масив, ви можете зробити дві речі:

  • Скористайтеся списком, а потім перетворите його в масив за допомогою myList.toArray ()

  • Використовуйте масив певного розміру. Якщо вам потрібен більший чи менший розмір, ви можете змінити його методами java.util.Arrays.

Найкраще рішення залежатиме від вашої проблеми;)


2

Я рекомендую замість цього використовувати вектори. Дуже простий у використанні і має безліч заздалегідь визначених методів реалізації.

import java.util.*;

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

щоб додати елемент, просто використовуйте:

v.addElement(int);

У (5,2) перші 5 - початковий розмір вектора. Якщо перевищити початковий розмір, вектор зросте на 2 місця. Якщо вона знову перевищить, то вона знову збільшиться на 2 місця тощо.


4
Якщо вам конкретно не потрібен безпечний (-ish) тип потоку, слід використовувати ArrayList, а не вектор.
Стівен 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можуть містити об'єкти в відміну від інших типів даних примітивно і дуже легко маніпулювати, видаляючи що - небудь з середини легко , як добре, повністю dynamic.same з 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. Користувач вказує розмір, і ви можете додати цикл для виконання рекурсії.

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

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 для ініціалізації вмісту temp із вмістом вихідного масиву, тобто. stck []. А потім знову копіюємо його до оригіналу, даючи нам новий масив нового SIZE.

Без сумніву, він генерує накладні витрати на процесор завдяки повторній ініціалізації масиву, що використовує цикл, кілька разів. Але ви все одно можете використовувати та реалізовувати це у своєму коді. Для найкращої практики використовуйте "Зв'язаний список" замість масиву, якщо ви хочете, щоб дані зберігалися динамічно в пам'яті, різної довжини.

Ось приклад у режимі реального часу, заснований на динамічних стеках, щоб збільшити розмір масивів під час виконання

Назва файлу: 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;

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.