- Изменить размер массива в Java
- Измените размер массива с помощью метода
arraycopy()
в Java - Изменение размера массива с помощью метода
copyOf()
в Java - Изменение размера массива с помощью цикла
for
в Java
В этом руководстве показано, как изменить размер массива, сохранив все его текущие элементы в Java. Мы включили несколько примеров программ, на которые вы можете ссылаться при выполнении программы в этом поле.
Массив определяется как контейнер, используемый для хранения подобных типов элементов в Java. Это контейнер фиксированного размера, что означает, что если массив имеет размер 10, он может хранить только 10 элементов — это одно из ограничений массива.
В этой статье мы научимся изменять размер массива с помощью некоторых встроенных методов, таких как функции arraycopy()
и copyOf()
, а также некоторых пользовательских кодов.
Изменить размер массива в Java
Самая верхняя альтернатива динамического массива — это класс структуры коллекции ArrayList
, который может хранить любое количество элементов и динамически увеличивается. Первое, что мы можем сделать, это создать ArrayList
и скопировать в него все элементы массива. Наконец-то у нас появился новый размер массива. См. Пример ниже:
import java.util.ArrayList;
import java.util.List;
public class SimpleTesting{
public static void main(String[] args) {
int arr[] = new int[]{12,34,21,33,22,55};
for(int a: arr) {
System.out.print(a+" ");
}
List<Integer> list = new ArrayList<>();
for(int a: arr) {
list.add(a);
}
System.out.println("n"+list);
list.add(100);
System.out.println(list);
}
}
Выход:
12 34 21 33 22 55
[12, 34, 21, 33, 22, 55]
[12, 34, 21, 33, 22, 55, 100]
Измените размер массива с помощью метода arraycopy()
в Java
Java предоставляет метод arraycopy()
, который принадлежит классу System
и может использоваться для создания копии массива. В этом примере мы создаем новый массив большего размера, а затем копируем в него все исходные элементы массива с помощью метода arraycopy()
. Следуйте приведенному ниже примеру программы:
public class SimpleTesting{
public static void main(String[] args) {
int arr[] = new int[]{12,34,21,33,22,55};
for(int a: arr) {
System.out.print(a+" ");
}
int arr2[] = new int[10];
System.arraycopy(arr, 0, arr2, 0, arr.length);
System.out.println();
for(int a: arr2) {
System.out.print(a+" ");
}
System.out.println();
arr2[6] = 100;
for(int a: arr2) {
System.out.print(a+" ");
}
}
}
Выход:
12 34 21 33 22 55
12 34 21 33 22 55 0 0 0 0
12 34 21 33 22 55 100 0 0 0
Изменение размера массива с помощью метода copyOf()
в Java
Класс Java Arrays
предоставляет метод copyOf()
, который можно использовать для создания массива нового размера путем копирования всех исходных элементов массива. Этот процесс принимает два аргумента: первый — это исходный массив, а второй — размер нового массива. См. Пример ниже:
import java.util.Arrays;
public class SimpleTesting{
public static void main(String[] args) {
int arr[] = new int[]{12,34,21,33,22,55};
for(int a: arr) {
System.out.print(a+" ");
}
int arr2[] = Arrays.copyOf(arr, 10);
System.out.println();
for(int a: arr2) {
System.out.print(a+" ");
}
System.out.println();
arr2[6] = 100;
for(int a: arr2) {
System.out.print(a+" ");
}
}
}
Выход:
12 34 21 33 22 55
12 34 21 33 22 55 0 0 0 0
12 34 21 33 22 55 100 0 0 0
Изменение размера массива с помощью цикла for
в Java
Этот метод прост и является более старым подходом, в котором мы используем цикл for
и присваиваем исходные элементы массива вновь созданному массиву на каждой итерации. Мы просто создаем новый массив большего размера и копируем в него все элементы с помощью цикла. См. Пример ниже:
public class SimpleTesting{
public static void main(String[] args) {
int arr[] = new int[]{12,34,21,33,22,55};
for(int a: arr) {
System.out.print(a+" ");
}
int arr2[] = new int[10];
for (int i = 0; i < arr.length; i++) {
arr2[i] = arr[i];
}
System.out.println();
for(int a: arr2) {
System.out.print(a+" ");
}
}
}
Выход:
12 34 21 33 22 55
12 34 21 33 22 55 0 0 0 0
Example
The simple answer is that you cannot do this. Once an array has been created, its size cannot be changed. Instead, an array can only be «resized» by creating a new array with the appropriate size and copying the elements from the existing array to the new one.
String[] listOfCities = new String[3]; // array created with size 3.
listOfCities[0] = "New York";
listOfCities[1] = "London";
listOfCities[2] = "Berlin";
Suppose (for example) that a new element needs to be added to the listOfCities
array defined as above. To do this, you will need to:
- create a new array with size 4,
- copy the existing 3 elements of the old array to the new array at offsets 0, 1 and 2, and
- add the new element to the new array at offset 3.
There are various ways to do the above. Prior to Java 6, the most concise way was:
String[] newArray = new String[listOfCities.length + 1];
System.arraycopy(listOfCities, 0, newArray, 0, listOfCities.length);
newArray[listOfCities.length] = "Sydney";
From Java 6 onwards, the Arrays.copyOf
and Arrays.copyOfRange
methods can do this more simply:
String[] newArray = Arrays.copyOf(listOfCities, listOfCities.length + 1);
newArray[listOfCities.length] = "Sydney";
For other ways to copy an array, refer to the following example. Bear in mind that you need an array copy with a different length to the original when resizing.
- Copying arrays
A better alternatives to array resizing
There two major drawbacks with resizing an array as described above:
- It is inefficient. Making an array bigger (or smaller) involves copying many or all of the existing array elements, and allocating a new array object. The larger the array, the more expensive it gets.
- You need to be able to update any «live» variables that contain references to the old array.
One alternative is to create the array with a large enough size to start with. This is only viable if you can determine that size accurately before allocating the array. If you cannot do that, then the problem of resizing the array arises again.
The other alternative is to use a data structure class provided by the Java SE class library or a third-party library. For example, the Java SE «collections» framework provides a number of implementations of the List
, Set
and Map
APIs with different runtime properties. The ArrayList
class is closest to performance characteristics of a plain array (e.g. O(N) lookup, O(1) get and set, O(N) random insertion and deletion) while providing more efficient resizing without the reference update problem.
(The resize efficiency for ArrayList
comes from its strategy of doubling the size of the backing array on each resize. For a typical use-case, this means that you only resize occasionally. When you amortize over the lifetime of the list, the resize cost per insert is O(1)
. It may be possible to use the same strategy when resizing a plain array.)
Arrays are fixed-size data structures and array sizes can not be changed once they have been initialized. However, in cases where array size needs to be changed, we have to follow one of the given approaches in this tutorial.
- 1. Using java.util.Arrays.copyOf()
- 2. Using ArrayList
- 3. Conclusion
1. Using java.util.Arrays.copyOf()
The copyOf(originalArray, newLength)
method takes an array and the new length of the array. The copyOf() creates a new array of required newLength and copies the originalArray to the new array using the System.arraycopy()
function.
If the new array is smaller in size then copyOf() truncates the remaining items; else if the new array is bigger in size then it pads the remaining indices with nulls. The resulting array is of exactly the same type as the original array.
Note that copyOf() method resizes a one-dimensional array only. For resizing multi-dimensional arrays, there is no generic solution and we need to provide our own logic.
String[] originalArray = {"A", "B", "C", "D", "E"};
String[] resizedArray = Arrays.copyOf(originalArray, 10);
resizedArray[5] = "F";
System.out.println(Arrays.toString(resizedArray));
//[A, B, C, D, E, F, null, null, null, null]
There are few other APIs to resize the array but internally they follow the same approach, so we can skip them.
2. Using ArrayList
Another approach is to think again about your design. If an ArrayList
is a better fit for such a usecase then consider using the List in place of the array.
Lists are already dynamically resizable, allow index-based accesses and provide great performance.
String[] originalArray = {"A", "B", "C", "D", "E"};
ArrayList<String> list = new ArrayList<>(Arrays.asList(originalArray));
list.add("F");
System.out.println(list);
//[A, B, C, D, E, F]
3. Conclusion
Resizing arrays in Java is no different than any other programming language. The resizing process allocates a new array with the specified size, copies elements from the old array to the new one, and then replace the old array with the new one.
In Java, we do not perform explicit memory management so the garbage collection takes care of the old array and frees the memory when it fits.
Happy Learning !!
Sourcecode on Github
Вступление
Массивы позволяют хранить и извлекать произвольное количество значений. Они аналогичны векторам в математике. Массивы массивов аналогичны матрицам и действуют как многомерные массивы. Массивы могут хранить любые данные любого типа: примитивы, такие как int
или ссылочные типы, такие как Object
.
Синтаксис
-
ArrayType[] myArray;
// Объявление массивов -
ArrayType myArray[];
// Другой допустимый синтаксис (менее часто используемый и обескураженный) -
ArrayType[][][] myArray;
// Объявление многомерных зубчатых массивов (repeat [] s) -
ArrayType myVar = myArray[index];
// Доступ к элементу (считыванию) по индексу -
myArray[index] = value;
// Присвоить значениеindex
позиции массива -
ArrayType[] myArray = new ArrayType[arrayLength];
// Синтаксис инициализации массива -
int[] ints = {1, 2, 3};
// Синтаксис инициализации массива с предоставленными значениями, длина выводится из числа предоставленных значений: {[value1 [, value2] *]} -
new int[]{4, -5, 6} // Can be used as argument, without a local variable
-
int[] ints = new int[3]; // same as {0, 0, 0}
-
int[][] ints = {{1, 2}, {3}, null};
// Инициализация многомерных массивов. int [] extends Object (а также anyType []), поэтому значение null является допустимым.
параметры
параметр | подробности |
---|---|
ArrayType |
Тип массива. Это может быть примитивным ( int , long , byte ) или Object ( String , MyObject и т. Д.). |
индекс | Индекс относится к позиции определенного объекта в массиве. |
длина | Каждому массиву при создании требуется заданная длина. Это делается либо при создании пустого массива ( new int[3] ), либо подразумевается при указании значений ( {1, 2, 3} ). |
Создание и инициализация массивов
Основные случаи
int[] numbers1 = new int[3]; // Array for 3 int values, default value is 0
int[] numbers2 = { 1, 2, 3 }; // Array literal of 3 int values
int[] numbers3 = new int[] { 1, 2, 3 }; // Array of 3 int values initialized
int[][] numbers4 = { { 1, 2 }, { 3, 4, 5 } }; // Jagged array literal
int[][] numbers5 = new int[5][]; // Jagged array, one dimension 5 long
int[][] numbers6 = new int[5][4]; // Multidimensional array: 5x4
Массивы могут быть созданы с использованием любого примитивного или ссылочного типа.
float[] boats = new float[5]; // Array of five 32-bit floating point numbers.
double[] header = new double[] { 4.56, 332.267, 7.0, 0.3367, 10.0 };
// Array of five 64-bit floating point numbers.
String[] theory = new String[] { "a", "b", "c" };
// Array of three strings (reference type).
Object[] dArt = new Object[] { new Object(), "We love Stack Overflow.", new Integer(3) };
// Array of three Objects (reference type).
В последнем примере обратите внимание, что подтипы объявленного типа массива разрешены в массиве.
Массивы для пользовательских типов также могут быть построены подобно примитивным типам
UserDefinedClass[] udType = new UserDefinedClass[5];
Массивы, коллекции и потоки
Java SE 1.2
// Parameters require objects, not primitives
// Auto-boxing happening for int 127 here
Integer[] initial = { 127, Integer.valueOf( 42 ) };
List<Integer> toList = Arrays.asList( initial ); // Fixed size!
// Note: Works with all collections
Integer[] fromCollection = toList.toArray( new Integer[toList.size()] );
//Java doesn't allow you to create an array of a parameterized type
List<String>[] list = new ArrayList<String>[2]; // Compilation error!
Java SE 8
// Streams - JDK 8+
Stream<Integer> toStream = Arrays.stream( initial );
Integer[] fromStream = toStream.toArray( Integer[]::new );
вступление
Массив — это структура данных, которая содержит фиксированное число примитивных значений или ссылок на экземпляры объектов.
Каждый элемент в массиве называется элементом, и каждый элемент получает доступ к его числовому индексу. Длина массива устанавливается при создании массива:
int size = 42;
int[] array = new int[size];
Размер массива фиксируется во время выполнения при инициализации. Он не может быть изменен после инициализации. Если размер должен быть изменен во время выполнения, вместо него следует использовать класс Collection
такой как ArrayList
. ArrayList
хранит элементы в массиве и поддерживает изменение размера путем выделения нового массива и копирования элементов из старого массива.
Если массив имеет примитивный тип, т. Е.
int[] array1 = { 1,2,3 };
int[] array2 = new int[10];
значения сохраняются в самом массиве. В отсутствие инициализатора (как в array2
выше) значение по умолчанию, присвоенное каждому элементу, равно 0
(ноль).
Если тип массива является ссылкой на объект, как в
SomeClassOrInterface[] array = new SomeClassOrInterface[10];
то массив содержит ссылки на объекты типа SomeClassOrInterface
. Эти ссылки могут ссылаться на экземпляр SomeClassOrInterface
или любого подкласса (для классов) или на реализацию класса (для интерфейсов) SomeClassOrInterface
. Если объявление массива не имеет инициализатора, то каждому элементу присваивается значение по умолчанию null
.
Поскольку все массивы являются int
-индексированными, размер массива должен быть задан с помощью int
. Размер массива не может быть задан как long
:
long size = 23L;
int[] array = new int[size]; // Compile-time error:
// incompatible types: possible lossy conversion from
// long to int
В массивах используется индексная система с нулевым значением , что означает, что индексирование начинается с 0
и заканчивается на length - 1
.
Например, следующее изображение представляет массив с размером 10
. Здесь первый элемент находится в индексе 0
а последний элемент находится в индексе 9
, а первый элемент находится в индексе 1
и последний элемент в индексе 10
(см. Рисунок ниже).
Доступ к элементам массивов осуществляется в постоянное время . Это означает, что доступ к первому элементу массива имеет одинаковую стоимость (по времени) доступа к второму элементу, третьему элементу и так далее.
Java предлагает несколько способов определения и инициализации массивов, включая буквенные и конструкторские обозначения. При объявлении массивов с использованием new Type[length]
каждый элемент будет инициализирован со следующими значениями по умолчанию:
-
0
для примитивных числовых типов :byte
,short
,int
,long
,float
иdouble
. -
'u0000'
(нулевой символ) для типаchar
. -
false
дляboolean
типа. -
null
для ссылочных типов .
Создание и инициализация массивов примитивных типов
int[] array1 = new int[] { 1, 2, 3 }; // Create an array with new operator and
// array initializer.
int[] array2 = { 1, 2, 3 }; // Shortcut syntax with array initializer.
int[] array3 = new int[3]; // Equivalent to { 0, 0, 0 }
int[] array4 = null; // The array itself is an object, so it
// can be set as null.
При объявлении массива []
будет отображаться как часть типа в начале объявления (после имени типа) или как часть декларатора для определенной переменной (после имени переменной) или обоих:
int array5[]; /* equivalent to */ int[] array5;
int a, b[], c[][]; /* equivalent to */ int a; int[] b; int[][] c;
int[] a, b[]; /* equivalent to */ int[] a; int[][] b;
int a, []b, c[][]; /* Compilation Error, because [] is not part of the type at beginning
of the declaration, rather it is before 'b'. */
// The same rules apply when declaring a method that returns an array:
int foo()[] { ... } /* equivalent to */ int[] foo() { ... }
В следующем примере обе декларации правильны и могут компилироваться и запускаться без каких-либо проблем. Однако как Конвенция по кодированию Java, так и Руководство по стилю Google Java препятствуют форме с помощью скобок после имени переменной — скобки идентифицируют тип массива и должны появляться с обозначением типа . То же самое следует использовать для сигнатур возврата метода.
float array[]; /* and */ int foo()[] { ... } /* are discouraged */
float[] array; /* and */ int[] foo() { ... } /* are encouraged */
Воспринимаемый тип предназначен для размещения переходных пользователей C , которые знакомы с синтаксисом C, который имеет скобки после имени переменной.
В Java возможно иметь массивы размером 0
:
int[] array = new int[0]; // Compiles and runs fine.
int[] array2 = {}; // Equivalent syntax.
Однако, поскольку это пустой массив, никакие элементы не могут быть прочитаны или назначены ему:
array[0] = 1; // Throws java.lang.ArrayIndexOutOfBoundsException.
int i = array2[0]; // Also throws ArrayIndexOutOfBoundsException.
Такие пустые массивы обычно полезны в качестве возвращаемых значений, поэтому вызывающий код должен беспокоиться только о работе с массивом, а не о потенциальном null
значении, которое может привести к исключению NullPointerException
.
Длина массива должна быть неотрицательным целым числом:
int[] array = new int[-1]; // Throws java.lang.NegativeArraySizeException
Размер массива можно определить, используя публичное конечное поле с названием length
:
System.out.println(array.length); // Prints 0 in this case.
Примечание . array.length
возвращает фактический размер массива, а не количество элементов массива, которым было присвоено значение, в отличие от ArrayList.size()
которое возвращает количество элементов массива, которым было присвоено значение.
Создание и инициализация многомерных массивов
Самый простой способ создания многомерного массива состоит в следующем:
int[][] a = new int[2][3];
Это создаст две три длины int
arrays- а a[0]
и a[1]
. Это очень похоже на классическую инициализацию прямоугольных многомерных массивов в стиле C.
Вы можете создавать и инициализировать одновременно:
int[][] a = { {1, 2}, {3, 4}, {5, 6} };
В отличие от C , где поддерживаются только прямоугольные многомерные массивы, внутренние массивы не должны быть одинаковой длины или даже определены:
int[][] a = { {1}, {2, 3}, null };
Здесь, a[0]
является одной длиной int
массива, в то время как a[1]
представляет собой две длины int
массива и a[2]
является null
. Такие массивы называются зубчатыми массивами или оборванными массивами , то есть массивами массивов. Многомерные массивы в Java реализованы как массивы массивов, т. array[i][j][k]
эквивалентен ((array[i])[j])[k]
. В отличие от C # , синтаксический array[i,j]
не поддерживается в Java.
Источник — Live on Ideone
Создание и инициализация массивов ссылочных типов
String[] array6 = new String[] { "Laurel", "Hardy" }; // Create an array with new
// operator and array initializer.
String[] array7 = { "Laurel", "Hardy" }; // Shortcut syntax with array
// initializer.
String[] array8 = new String[3]; // { null, null, null }
String[] array9 = null; // null
Живой на Ideone
В дополнение к String
литералам и примитивам, показанным выше, синтаксис ярлыков для инициализации массива также работает с каноническими типами Object
:
Object[] array10 = { new Object(), new Object() };
Поскольку массивы являются ковариантными, массив ссылочного типа может быть инициализирован как массив подкласса, хотя ArrayStoreException
будет ArrayStoreException
, если вы попытаетесь установить элемент в нечто иное, чем String
:
Object[] array11 = new String[] { "foo", "bar", "baz" };
array11[1] = "qux"; // fine
array11[1] = new StringBuilder(); // throws ArrayStoreException
Синтаксис ярлыка не может использоваться для этого, потому что синтаксис ярлыка будет иметь неявный тип Object[]
.
Массив может быть инициализирован нулевыми элементами, используя String[] emptyArray = new String[0]
. Например, массив с нулевой длиной, подобный этому, используется для создания Array
из Collection
когда методу нужен тип среды выполнения объекта.
В обоих примитивных и ссылочных типах пустая инициализация массива (например, String[] array8 = new String[3]
) инициализирует массив значением по умолчанию для каждого типа данных .
Создание и инициализация массивов типичного типа
В родовых классах массивы генерических типов не могут быть инициализированы, например, из-за стирания типа :
public class MyGenericClass<T> {
private T[] a;
public MyGenericClass() {
a = new T[5]; // Compile time error: generic array creation
}
}
Вместо этого они могут быть созданы с использованием одного из следующих способов: (обратите внимание, что они будут генерировать непроверенные предупреждения)
-
Создав массив
Object
и переведя его в общий тип:a = (T[]) new Object[5];
Это самый простой метод, но поскольку базовый массив по-прежнему имеет тип
Object[]
, этот метод не обеспечивает безопасность типов. Поэтому этот метод создания массива лучше всего использовать только в универсальном классе — не публично публиковаться. -
Используя
Array.newInstance
с параметром класса:public MyGenericClass(Class<T> clazz) { a = (T[]) Array.newInstance(clazz, 5); }
Здесь класс
T
должен быть явно передан конструктору. Возвращаемый типArray.newInstance
всегда являетсяObject
. Однако этот метод более безопасен, потому что вновь созданный массив всегда имеет типT[]
и поэтому может быть безопасно экстернализирован.
Заполнение массива после инициализации
Java SE 1.2
Arrays.fill()
может использоваться для заполнения массива с тем же значением после инициализации:
Arrays.fill(array8, "abc"); // { "abc", "abc", "abc" }
Живой на Ideone
fill()
также может присваивать значение каждому элементу указанного диапазона массива:
Arrays.fill(array8, 1, 2, "aaa"); // Placing "aaa" from index 1 to 2.
Живой на Ideone
Java SE 8
Поскольку Java-версия 8, метод setAll
и ее Concurrent
эквивалент parallelSetAll
, могут использоваться для установки каждого элемента массива на сгенерированные значения. Этим методам передается функция генератора, которая принимает индекс и возвращает желаемое значение для этой позиции.
Следующий пример создает целочисленный массив и устанавливает все его элементы в соответствующее значение индекса:
int[] array = new int[5];
Arrays.setAll(array, i -> i); // The array becomes { 0, 1, 2, 3, 4 }.
Живой на Ideone
Отдельная декларация и инициализация массивов
Значение индекса для элемента массива должно быть целым числом (0, 1, 2, 3, 4, …) и меньше длины массива (индексы основаны на нуле). В противном случае будет выбрано исключение ArrayIndexOutOfBoundsException :
int[] array9; // Array declaration - uninitialized
array9 = new int[3]; // Initialize array - { 0, 0, 0 }
array9[0] = 10; // Set index 0 value - { 10, 0, 0 }
array9[1] = 20; // Set index 1 value - { 10, 20, 0 }
array9[2] = 30; // Set index 2 value - { 10, 20, 30 }
Массивы не могут быть повторно инициализированы синтаксисом ярлыка инициализатора массива
Невозможно повторно инициализировать массив с помощью синтаксиса ярлыков с инициализатором массива, поскольку инициализатор массива может быть указан только в объявлении поля или объявлении локальной переменной или как часть выражения создания массива.
Тем не менее, можно создать новый массив и назначить его переменной, используемой для ссылки на старый массив. Хотя это приводит к тому, что массив, на который ссылается эта переменная, повторно инициализируется, содержимое переменной представляет собой совершенно новый массив. Для этого new
оператор может использоваться с инициализатором массива и назначается переменной массива:
// First initialization of array
int[] array = new int[] { 1, 2, 3 };
// Prints "1 2 3 ".
for (int i : array) {
System.out.print(i + " ");
}
// Re-initializes array to a new int[] array.
array = new int[] { 4, 5, 6 };
// Prints "4 5 6 ".
for (int i : array) {
System.out.print(i + " ");
}
array = { 1, 2, 3, 4 }; // Compile-time error! Can't re-initialize an array via shortcut
// syntax with array initializer.
Живой на Ideone
Создание массива из коллекции
Два метода в java.util.Collection
создают массив из коллекции:
-
Object[] toArray()
-
<T> T[] toArray(T[] a)
Object[] toArray()
может использоваться следующим образом:
Java SE 5
Set<String> set = new HashSet<String>();
set.add("red");
set.add("blue");
// although set is a Set<String>, toArray() returns an Object[] not a String[]
Object[] objectArray = set.toArray();
<T> T[] toArray(T[] a)
можно использовать следующим образом:
Java SE 5
Set<String> set = new HashSet<String>();
set.add("red");
set.add("blue");
// The array does not need to be created up front with the correct size.
// Only the array type matters. (If the size is wrong, a new array will
// be created with the same type.)
String[] stringArray = set.toArray(new String[0]);
// If you supply an array of the same size as collection or bigger, it
// will be populated with collection values and returned (new array
// won't be allocated)
String[] stringArray2 = set.toArray(new String[set.size()]);
Разница между ними больше, чем просто отсутствие нетипизированных или типизированных результатов. Их производительность может также отличаться (подробности см. В этом разделе анализа эффективности ):
-
Object[] toArray()
использует векторизованнуюarraycopy
, которая намного быстрее, чем провереннаяarraycopy
используемая вT[] toArray(T[] a)
. -
T[] toArray(new T[non-zero-size])
должен обнулить массив во время выполнения, аT[] toArray(new T[0])
. Такое избегание заставляет последнего звонить быстрее первого. Подробный анализ здесь: Массивы Мудрости Древних .
Java SE 8
Начиная с Java SE 8+, где была введена концепция Stream
, можно использовать Stream
созданный сборкой, для создания нового массива с использованием метода Stream.toArray
.
String[] strings = list.stream().toArray(String[]::new);
Примеры, взятые из двух ответов ( 1 , 2 ) на преобразование ‘ArrayList в’ String [] ‘в Java на переполнение стека.
Массивы для строки
Java SE 5
Начиная с Java 1.5 вы можете получить представление String
содержимого указанного массива без итерации по каждому элементу. Просто используйте Arrays.toString(Object[])
или Arrays.deepToString(Object[])
для многомерных массивов:
int[] arr = {1, 2, 3, 4, 5};
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5]
int[][] arr = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
System.out.println(Arrays.deepToString(arr)); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Arrays.toString()
использует метод Object.toString()
для получения значений String
каждого элемента в массиве, помимо массива примитивного типа, его можно использовать для всех типов массивов. Например:
public class Cat { /* implicitly extends Object */
@Override
public String toString() {
return "CAT!";
}
}
Cat[] arr = { new Cat(), new Cat() };
System.out.println(Arrays.toString(arr)); // [CAT!, CAT!]
Если для класса не существует переопределенного toString()
, тогда будет использоваться унаследованная toString()
из Object
. Обычно выход не очень полезен, например:
public class Dog {
/* implicitly extends Object */
}
Dog[] arr = { new Dog() };
System.out.println(Arrays.toString(arr)); // [[email protected]]
Создание списка из массива
Метод Arrays.asList()
может использоваться для возврата List
фиксированного размера, содержащего элементы данного массива. Полученный List
будет иметь тот же тип параметра, что и базовый тип массива.
String[] stringArray = {"foo", "bar", "baz"};
List<String> stringList = Arrays.asList(stringArray);
Примечание . Этот список поддерживается ( представлением ) исходного массива, что означает, что любые изменения в списке изменят массив и наоборот. Однако изменения в списке, который изменит его размер (и, следовательно, длину массива), вызовут исключение.
Чтобы создать копию списка, используйте конструктор java.util.ArrayList
взяв Collection
в качестве аргумента:
Java SE 5
String[] stringArray = {"foo", "bar", "baz"};
List<String> stringList = new ArrayList<String>(Arrays.asList(stringArray));
Java SE 7
В Java SE 7 и более поздних версиях может использоваться пара угловых скобок <>
(пустой набор аргументов типа), который называется Diamond . Компилятор может определить аргументы типа из контекста. Это означает, что информация о типе может быть опущена при вызове конструктора ArrayList
и будет автоматически выведена во время компиляции. Это называется Type Inference, который является частью Java Generics .
// Using Arrays.asList()
String[] stringArray = {"foo", "bar", "baz"};
List<String> stringList = new ArrayList<>(Arrays.asList(stringArray));
// Using ArrayList.addAll()
String[] stringArray = {"foo", "bar", "baz"};
ArrayList<String> list = new ArrayList<>();
list.addAll(Arrays.asList(stringArray));
// Using Collections.addAll()
String[] stringArray = {"foo", "bar", "baz"};
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, stringArray);
Точка стоит отметить о Даймонд , что она не может быть использована с классами Anonymous .
Java SE 8
// Using Streams
int[] ints = {1, 2, 3};
List<Integer> list = Arrays.stream(ints).boxed().collect(Collectors.toList());
String[] stringArray = {"foo", "bar", "baz"};
List<Object> list = Arrays.stream(stringArray).collect(Collectors.toList());
Важные замечания, связанные с использованием метода Arrays.asList ()
-
Этот метод возвращает
List
, который является экземпляромArrays$ArrayList
(статический внутренний классArrays
), а неjava.util.ArrayList
. ПолученныйList
имеет фиксированный размер. Это означает, что добавление или удаление элементов не поддерживается и будетUnsupportedOperationException
исключениеUnsupportedOperationException
:stringList.add("something"); // throws java.lang.UnsupportedOperationException
-
Новый
List
можно создать, передавList
с поддержкой массива в конструктор новогоList
. Это создает новую копию данных, которая имеет изменяемый размер и не поддерживается исходным массивом:List<String> modifiableList = new ArrayList<>(Arrays.asList("foo", "bar"));
-
Вызов
<T> List<T> asList(T... a)
в примитивном массиве, такой какint[]
, приведет к созданиюList<int[]>
, единственным элементом которого является исходный примитивный массив вместо фактических элементов исходного массива.Причиной такого поведения является то, что примитивные типы не могут использоваться вместо параметров типового типа, поэтому весь примитивный массив заменяет параметр типового типа в этом случае. Чтобы преобразовать примитивный массив в
List
, прежде всего, преобразовать примитивный массив в массив соответствующего типа-оболочки (т.Arrays.asList
вInteger[]
вместоint[]
).Поэтому это будет напечатать
false
:int[] arr = {1, 2, 3}; // primitive array of int System.out.println(Arrays.asList(arr).contains(1));
Посмотреть демо
С другой стороны, это будет
true
:Integer[] arr = {1, 2, 3}; // object array of Integer (wrapper for int) System.out.println(Arrays.asList(arr).contains(1));
Посмотреть демо
Это также напечатает
true
, потому что массив будет интерпретироваться какInteger[]
):System.out.println(Arrays.asList(1,2,3).contains(1));
Посмотреть демо
Многомерные и зубчатые массивы
Можно определить массив с более чем одним измерением. Вместо того, чтобы получать доступ, предоставляя единый индекс, доступ к многомерному массиву можно получить, указав индекс для каждого измерения.
Объявление многомерного массива можно сделать, добавив []
для каждого измерения к регулярному объявлению массива. Например, чтобы создать двумерный массив int
, добавьте еще один набор скобок в объявление, например int[][]
. Это продолжается для 3-мерных массивов ( int[][][]
) и т. Д.
Чтобы определить двумерный массив с тремя строками и тремя столбцами:
int rows = 3;
int columns = 3;
int[][] table = new int[rows][columns];
Массив можно индексировать и присваивать ему значения с помощью этой конструкции. Обратите внимание, что неназначенные значения являются значениями по умолчанию для типа массива, в этом случае 0
для int
.
table[0][0] = 0;
table[0][1] = 1;
table[0][2] = 2;
Также возможно одновременное создание измерений и даже создание непрямоугольных массивов. Они чаще всего называются зубчатыми массивами .
int[][] nonRect = new int[4][];
Важно отметить, что, хотя можно определить любой размер массива с зубчатым контуром, должен быть определен предшествующий уровень.
// valid
String[][] employeeGraph = new String[30][];
// invalid
int[][] unshapenMatrix = new int[][10];
// also invalid
int[][][] misshapenGrid = new int[100][][10];
Как многомерные массивы представлены в Java
![]()
Источник изображения: http://math.hws.edu/eck/cs124/javanotes3/c8/s5.html
Литературная инициализация массива Jagged
Многомерные массивы и зубчатые массивы также могут быть инициализированы литеральным выражением. Следующее объявляет и заполняет массив 2×3 int
:
int[][] table = {
{1, 2, 3},
{4, 5, 6}
};
Примечание : Subarrays с зубцами также может быть null
. Например, следующий код объявляет и заполняет двумерный массив int
чей первый подмассив имеет значение null
, второй субарейр имеет нулевую длину, третий подмассив имеет одну длину, а последний подмассива представляет собой массив из двух длин:
int[][] table = {
null,
{},
{1},
{1,2}
};
Для многомерного массива можно выделить массивы измерения нижнего уровня по их индексам:
int[][][] arr = new int[3][3][3];
int[][] arr1 = arr[0]; // get first 3x3-dimensional array from arr
int[] arr2 = arr1[0]; // get first 3-dimensional array from arr1
int[] arr3 = arr[0]; // error: cannot convert from int[][] to int[]
ArrayIndexOutOfBoundsException
ArrayIndexOutOfBoundsException
генерируется при доступе к несуществующему индексу массива.
Массивы индексируются с нулевым индексом, поэтому индекс первого элемента равен 0
а индекс последнего элемента — array.length - 1
массива минус 1
(т. array.length - 1
).
Поэтому любой запрос элемента массива индексом i
должен удовлетворять условию 0 <= i < array.length
, иначе будет 0 <= i < array.length
ArrayIndexOutOfBoundsException
.
Следующий код — простой пример, в котором генерируется ArrayIndexOutOfBoundsException
.
String[] people = new String[] { "Carol", "Andy" };
// An array will be created:
// people[0]: "Carol"
// people[1]: "Andy"
// Notice: no item on index 2. Trying to access it triggers the exception:
System.out.println(people[2]); // throws an ArrayIndexOutOfBoundsException.
Выход:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
at your.package.path.method(YourClass.java:15)
Обратите внимание, что незаконный индекс, к которому обращаются, также включен в исключение ( 2
в примере); эта информация может быть полезна, чтобы найти причину исключения.
Чтобы этого избежать, просто проверьте, что индекс находится в пределах массива:
int index = 2;
if (index >= 0 && index < people.length) {
System.out.println(people[index]);
}
Получение длины массива
Массивы — это объекты, которые обеспечивают пространство для хранения до размера элементов указанного типа. Размер массива не может быть изменен после создания массива.
int[] arr1 = new int[0];
int[] arr2 = new int[2];
int[] arr3 = new int[]{1, 2, 3, 4};
int[] arr4 = {1, 2, 3, 4, 5, 6, 7};
int len1 = arr1.length; // 0
int len2 = arr2.length; // 2
int len3 = arr3.length; // 4
int len4 = arr4.length; // 7
Поле length
в массиве сохраняет размер массива. Это final
поле и не может быть изменено.
Этот код показывает разницу между length
массива и количеством объектов, хранящихся в массиве.
public static void main(String[] args) {
Integer arr[] = new Integer[] {1,2,3,null,5,null,7,null,null,null,11,null,13};
int arrayLength = arr.length;
int nonEmptyElementsCount = 0;
for (int i=0; i<arrayLength; i++) {
Integer arrElt = arr[i];
if (arrElt != null) {
nonEmptyElementsCount++;
}
}
System.out.println("Array 'arr' has a length of "+arrayLength+"n"
+ "and it contains "+nonEmptyElementsCount+" non-empty values");
}
Результат:
Array 'arr' has a length of 13
and it contains 7 non-empty values
Сравнение массивов для равенства
Типы массивов наследуют реализации equals()
(и hashCode()
) из java.lang.Object , поэтому equals()
возвращает true только при сравнении с тем же самым объектом массива. Чтобы сравнить массивы для равенства на основе их значений, используйте java.util.Arrays.equals
, который перегружен для всех типов массивов.
int[] a = new int[]{1, 2, 3};
int[] b = new int[]{1, 2, 3};
System.out.println(a.equals(b)); //prints "false" because a and b refer to different objects
System.out.println(Arrays.equals(a, b)); //prints "true" because the elements of a and b have the same values
Когда тип элемента является ссылочным типом, Arrays.equals()
вызывает equals()
для элементов массива для определения равенства. В частности, если тип элемента сам по себе является типом массива, будет использоваться сравнение идентичности. Чтобы сравнить многомерные массивы для равенства, используйте Arrays.deepEquals()
как Arrays.deepEquals()
ниже:
int a[] = { 1, 2, 3 };
int b[] = { 1, 2, 3 };
Object[] aObject = { a }; // aObject contains one element
Object[] bObject = { b }; // bObject contains one element
System.out.println(Arrays.equals(aObject, bObject)); // false
System.out.println(Arrays.deepEquals(aObject, bObject));// true
Поскольку наборы и карты используют equals()
и hashCode()
, массивы обычно не полезны в качестве заданных элементов или клавиш карты. Либо оберните их в класс-помощник, который реализует equals()
и hashCode()
в терминах элементов массива или преобразует их в экземпляры List
и сохраняет списки.
Массивы для потока
Java SE 8
Преобразование массива объектов в Stream
:
String[] arr = new String[] {"str1", "str2", "str3"};
Stream<String> stream = Arrays.stream(arr);
Преобразование массива примитивов в Stream
с использованием Arrays.stream()
преобразует массив в примитивную специализацию Stream:
int[] intArr = {1, 2, 3};
IntStream intStream = Arrays.stream(intArr);
Вы также можете ограничить Stream
для диапазона элементов в массиве. Начальный индекс является включительным, а конечный индекс — исключительным:
int[] values = {1, 2, 3, 4};
IntStream intStream = Arrays.stream(values, 2, 4);
В классе Stream
появляется метод, аналогичный Arrays.stream()
: Stream.of()
. Разница в том, что Stream.of()
использует параметр varargs, поэтому вы можете написать что-то вроде:
Stream<Integer> intStream = Stream.of(1, 2, 3);
Stream<String> stringStream = Stream.of("1", "2", "3");
Stream<Double> doubleStream = Stream.of(new Double[]{1.0, 2.0});
Итерация по массивам
Вы можете перебирать массивы либо с помощью расширенного цикла for (aka foreach), либо с использованием индексов массива:
int[] array = new int[10];
// using indices: read and write
for (int i = 0; i < array.length; i++) {
array[i] = i;
}
Java SE 5
// extended for: read only
for (int e : array) {
System.out.println(e);
}
Здесь стоит отметить, что нет прямого способа использовать Iterator в массиве, но через библиотеку Arrays его можно легко преобразовать в список, чтобы получить объект Iterable
.
Для массивов в коробке используйте Arrays.asList :
Integer[] boxed = {1, 2, 3};
Iterable<Integer> boxedIt = Arrays.asList(boxed); // list-backed iterable
Iterator<Integer> fromBoxed1 = boxedIt.iterator();
Для примитивных массивов (с использованием java используйте потоки (в частности, в этом примере — Arrays.stream -> IntStream ):
int[] primitives = {1, 2, 3};
IntStream primitiveStream = Arrays.stream(primitives); // list-backed iterable
PrimitiveIterator.OfInt fromPrimitive1 = primitiveStream.iterator();
Если вы не можете использовать потоки (без java 8), вы можете использовать goava- библиотеку guava :
Iterable<Integer> fromPrimitive2 = Ints.asList(primitives);
В двумерных массивах или более, обе методики могут быть использованы несколько более сложным образом.
Пример:
int[][] array = new int[10][10];
for (int indexOuter = 0; indexOuter < array.length; indexOuter++) {
for (int indexInner = 0; indexInner < array[indexOuter].length; indexInner++) {
array[indexOuter][indexInner] = indexOuter + indexInner;
}
}
Java SE 5
for (int[] numbers : array) {
for (int value : numbers) {
System.out.println(value);
}
}
Невозможно установить Array на любое неравномерное значение без использования цикла, основанного на индексе.
Конечно, вы также можете использовать while
или do-while
циклы при итерации с использованием индексов.
Одно примечание: при использовании индексов массива убедитесь, что индекс находится между 0
и array.length - 1
(оба array.length - 1
). Не делайте жестко закодированные предположения относительно длины массива, иначе вы можете сломать свой код, если длина массива изменится, но ваши жестко закодированные значения не будут.
Пример:
int[] numbers = {1, 2, 3, 4};
public void incrementNumbers() {
// DO THIS :
for (int i = 0; i < numbers.length; i++) {
numbers[i] += 1; //or this: numbers[i] = numbers[i] + 1; or numbers[i]++;
}
// DON'T DO THIS :
for (int i = 0; i < 4; i++) {
numbers[i] += 1;
}
}
Это также лучше, если вы не используете причудливые вычисления для получения индекса, но используете индекс для итерации, и если вам нужны разные значения, подсчитайте их.
Пример:
public void fillArrayWithDoubleIndex(int[] array) {
// DO THIS :
for (int i = 0; i < array.length; i++) {
array[i] = i * 2;
}
// DON'T DO THIS :
int doubleLength = array.length * 2;
for (int i = 0; i < doubleLength; i += 2) {
array[i / 2] = i;
}
}
Доступ к массивам в обратном порядке
int[] array = {0, 1, 1, 2, 3, 5, 8, 13};
for (int i = array.length - 1; i >= 0; i--) {
System.out.println(array[i]);
}
Использование временных массивов для уменьшения повторения кода
Итерация по временному массиву вместо повторения кода может сделать ваш код более чистым. Он может использоваться, когда одна и та же операция выполняется для нескольких переменных.
// we want to print out all of these
String name = "Margaret";
int eyeCount = 16;
double height = 50.2;
int legs = 9;
int arms = 5;
// copy-paste approach:
System.out.println(name);
System.out.println(eyeCount);
System.out.println(height);
System.out.println(legs);
System.out.println(arms);
// temporary array approach:
for(Object attribute : new Object[]{name, eyeCount, height, legs, arms})
System.out.println(attribute);
// using only numbers
for(double number : new double[]{eyeCount, legs, arms, height})
System.out.println(Math.sqrt(number));
Имейте в виду, что этот код не должен использоваться в критически важных средах, поскольку массив создается каждый раз, когда вводится цикл, и что примитивные переменные будут скопированы в массив и, следовательно, не могут быть изменены.
Копирование массивов
Java предоставляет несколько способов копирования массива.
для цикла
int[] a = { 4, 1, 3, 2 };
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) {
b[i] = a[i];
}
Обратите внимание, что использование этой опции с массивом Object вместо примитивного массива будет заполнять копию ссылкой на исходное содержимое вместо его копии.
Object.clone ()
Поскольку массивы Object
в Java, вы можете использовать Object.clone()
.
int[] a = { 4, 1, 3, 2 };
int[] b = a.clone(); // [4, 1, 3, 2]
Обратите внимание, что метод Object.clone
для массива выполняет мелкую копию , то есть возвращает ссылку на новый массив, который ссылается на те же элементы, что и исходный массив.
Arrays.copyOf ()
java.util.Arrays
предоставляет простой способ выполнить копию массива в другой. Вот основное использование:
int[] a = {4, 1, 3, 2};
int[] b = Arrays.copyOf(a, a.length); // [4, 1, 3, 2]
Обратите внимание, что Arrays.copyOf
также обеспечивает перегрузку, которая позволяет вам изменять тип массива:
Double[] doubles = { 1.0, 2.0, 3.0 };
Number[] numbers = Arrays.copyOf(doubles, doubles.length, Number[].class);
System.arraycopy ()
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
Копирует массив из указанного исходного массива, начиная с указанной позиции, в указанную позицию целевого массива.
Ниже приведен пример использования
int[] a = { 4, 1, 3, 2 };
int[] b = new int[a.length];
System.arraycopy(a, 0, b, 0, a.length); // [4, 1, 3, 2]
Arrays.copyOfRange ()
В основном используется для копирования части массива, вы также можете использовать его для копирования целого массива в другой, как показано ниже:
int[] a = { 4, 1, 3, 2 };
int[] b = Arrays.copyOfRange(a, 0, a.length); // [4, 1, 3, 2]
Литейные массивы
Массивы — это объекты, но их тип определяется типом содержащихся объектов. Поэтому нельзя просто отбрасывать A[]
в T[]
, но каждый член A[]
конкретного A[]
должен быть переведен в объект T
Общий пример:
public static <T, A> T[] castArray(T[] target, A[] array) {
for (int i = 0; i < array.length; i++) {
target[i] = (T) array[i];
}
return target;
}
Таким образом, с учетом массива A[]
:
T[] target = new T[array.Length];
target = castArray(target, array);
Java SE предоставляет для этой цели метод Arrays.copyOf(original, newLength, newType)
:
Double[] doubles = { 1.0, 2.0, 3.0 };
Number[] numbers = Arrays.copyOf(doubles, doubles.length, Number[].class);
Удалить элемент из массива
Java не предоставляет прямой метод в java.util.Arrays
для удаления элемента из массива. Для его выполнения вы можете скопировать исходный массив в новый, не удаляя элемент или преобразовывая его в другую структуру, позволяющую удалить.
Использование ArrayList
Вы можете преобразовать массив в java.util.List
, удалить элемент и преобразовать список обратно в массив следующим образом:
String[] array = new String[]{"foo", "bar", "baz"};
List<String> list = new ArrayList<>(Arrays.asList(array));
list.remove("foo");
// Creates a new array with the same size as the list and copies the list
// elements to it.
array = list.toArray(new String[list.size()]);
System.out.println(Arrays.toString(array)); //[bar, baz]
Использование System.arraycopy
System.arraycopy()
можно использовать для создания копии исходного массива и удаления System.arraycopy()
элемента. Ниже пример:
int[] array = new int[] { 1, 2, 3, 4 }; // Original array.
int[] result = new int[array.length - 1]; // Array which will contain the result.
int index = 1; // Remove the value "2".
// Copy the elements at the left of the index.
System.arraycopy(array, 0, result, 0, index);
// Copy the elements at the right of the index.
System.arraycopy(array, index + 1, result, index, array.length - index - 1);
System.out.println(Arrays.toString(result)); //[1, 3, 4]
Использование Apache Commons Lang
Чтобы легко удалить элемент, вы можете использовать библиотеку Apache Commons Lang и особенно статический метод removeElement()
класса ArrayUtils
. Ниже пример:
int[] array = new int[]{1,2,3,4};
array = ArrayUtils.removeElement(array, 2); //remove first occurrence of 2
System.out.println(Arrays.toString(array)); //[1, 3, 4]
Ковариантность массива
Объектные массивы являются ковариантными, что означает, что так же, как Integer
является подклассом Number
, Integer[]
является подклассом Number[]
. Это может показаться интуитивным, но может привести к неожиданному поведению:
Integer[] integerArray = {1, 2, 3};
Number[] numberArray = integerArray; // valid
Number firstElement = numberArray[0]; // valid
numberArray[0] = 4L; // throws ArrayStoreException at runtime
Хотя Integer[]
является подклассом Number[]
, он может содержать только Integer
s, и попытка назначить элемент Long
выдает исключение во время выполнения.
Обратите внимание, что это поведение уникально для массивов, и его можно избежать, используя вместо этого общий List
:
List<Integer> integerList = Arrays.asList(1, 2, 3);
//List<Number> numberList = integerList; // compile error
List<? extends Number> numberList = integerList;
Number firstElement = numberList.get(0);
//numberList.set(0, 4L); // compile error
Для всех элементов массива не обязательно использовать один и тот же тип, если они являются подклассом типа массива:
interface I {}
class A implements I {}
class B implements I {}
class C implements I {}
I[] array10 = new I[] { new A(), new B(), new C() }; // Create an array with new
// operator and array initializer.
I[] array11 = { new A(), new B(), new C() }; // Shortcut syntax with array
// initializer.
I[] array12 = new I[3]; // { null, null, null }
I[] array13 = new A[] { new A(), new A() }; // Works because A implements I.
Object[] array14 = new Object[] { "Hello, World!", 3.14159, 42 }; // Create an array with
// new operator and array initializer.
Object[] array15 = { new A(), 64, "My String" }; // Shortcut syntax
// with array initializer.
Как изменить размер массива?
Простой ответ заключается в том, что вы не можете этого сделать. После создания массива его размер не может быть изменен. Вместо этого массив может быть только «изменен», создав новый массив с соответствующим размером и скопировав элементы из существующего массива в новый.
String[] listOfCities = new String[3]; // array created with size 3.
listOfCities[0] = "New York";
listOfCities[1] = "London";
listOfCities[2] = "Berlin";
Предположим (например), что новый элемент необходимо добавить в массив listOfCities
как указано выше. Для этого вам необходимо:
- создайте новый массив размером 4,
- скопируйте существующие 3 элемента старого массива в новый массив при смещениях 0, 1 и 2 и
- добавьте новый элемент в новый массив со смещением 3.
Существуют различные способы сделать это. До появления Java 6 наиболее кратким способом было:
String[] newArray = new String[listOfCities.length + 1];
System.arraycopy(listOfCities, 0, newArray, 0, listOfCities.length);
newArray[listOfCities.length] = "Sydney";
Начиная с Java 6 методы Arrays.copyOf
и Arrays.copyOfRange
могут сделать это проще:
String[] newArray = Arrays.copyOf(listOfCities, listOfCities.length + 1);
newArray[listOfCities.length] = "Sydney";
Для других способов копирования массива см. Следующий пример. Имейте в виду, что при изменении размера вам понадобится копия массива с другой длиной до оригинала.
- Копирование массивов
Лучшие альтернативы изменению размера массива
Существуют два основных недостатка с изменением размера массива, как описано выше:
- Это неэффективно. Создание массива больше (или меньше) включает в себя копирование многих или всех существующих элементов массива и выделение нового объекта массива. Чем больше массив, тем он дороже.
- Вы должны иметь возможность обновлять любые «живые» переменные, содержащие ссылки на старый массив.
Один из вариантов — создать массив с достаточно большим размером для начала. Это возможно только в том случае, если вы можете точно определить этот размер до выделения массива . Если вы не можете этого сделать, возникает проблема изменения размера массива.
Другой альтернативой является использование класса структуры данных, предоставляемого библиотекой классов Java SE или сторонней библиотекой. Например, структура «коллекций» Java SE предоставляет ряд реализаций API-интерфейсов List
, Set
и Map
с различными свойствами среды выполнения. Класс ArrayList
ближе всего к характеристикам производительности простого массива (например, O (N) lookup, O (1) get и set, O (N) случайная вставка и удаление), обеспечивая при этом более эффективное изменение размера без проблемы с эталонным обновлением.
(Эффективность изменения размера для ArrayList
исходит из стратегии удвоения размера массива поддержки при каждом изменении размера. Для типичного варианта использования это означает, что вы иногда изменяете размер. Когда вы амортизируете за весь срок службы списка, стоимость изменения размера для каждой вставки O(1)
. При изменении размера простого массива может быть использована одна и та же стратегия.)
Поиск элемента в массиве
Существует множество способов найти местоположение значения в массиве. В приведенных ниже примерах показано, что массив является одним из следующих:
String[] strings = new String[] { "A", "B", "C" };
int[] ints = new int[] { 1, 2, 3, 4 };
Кроме того, каждый устанавливает index
или index2
либо индексу требуемого элемента, либо -1
если элемент отсутствует.
Использование Arrays.binarySearch
(только для отсортированных массивов)
int index = Arrays.binarySearch(strings, "A");
int index2 = Arrays.binarySearch(ints, 1);
Использование массива Arrays.asList
(только для не примитивных массивов)
int index = Arrays.asList(strings).indexOf("A");
int index2 = Arrays.asList(ints).indexOf(1); // compilation error
Использование Stream
Java SE 8
int index = IntStream.range(0, strings.length)
.filter(i -> "A".equals(strings[i]))
.findFirst()
.orElse(-1); // If not present, gives us -1.
// Similar for an array of primitives
Линейный поиск с использованием цикла
int index = -1;
for (int i = 0; i < array.length; i++) {
if ("A".equals(array[i])) {
index = i;
break;
}
}
// Similar for an array of primitives
Линейный поиск с использованием сторонних библиотек, таких как org.apache.commons
int index = org.apache.commons.lang3.ArrayUtils.contains(strings, "A");
int index2 = org.apache.commons.lang3.ArrayUtils.contains(ints, 1);
Примечание. Использование прямого линейного поиска более эффективно, чем перенос в список.
Тестирование, если массив содержит элемент
Вышеприведенные примеры могут быть адаптированы для проверки того, содержит ли массив элемент, просто проверяя, вычисляется ли вычисляемый индекс больше или равен нулю.
Кроме того, есть также несколько более сжатых вариантов:
boolean isPresent = Arrays.asList(strings).contains("A");
Java SE 8
boolean isPresent = Stream<String>.of(strings).anyMatch(x -> "A".equals(x));
boolean isPresent = false;
for (String s : strings) {
if ("A".equals(s)) {
isPresent = true;
break;
}
}
boolean isPresent = org.apache.commons.lang3.ArrayUtils.contains(ints, 4);
Сортировка массивов
Сортировка массивов можно легко сделать с Массивы апи.
import java.util.Arrays;
// creating an array with integers
int[] array = {7, 4, 2, 1, 19};
// this is the sorting part just one function ready to be used
Arrays.sort(array);
// prints [1, 2, 4, 7, 19]
System.out.println(Arrays.toString(array));
Сортировка массивов строк:
String
— это не числовые данные, она определяет ее собственный порядок, который называется лексикографическим порядком, также известным как алфавитный порядок. Когда вы сортируете массив String с помощью метода sort()
, он сортирует массив в естественный порядок, определенный интерфейсом Comparable, как показано ниже:
Увеличение порядка
String[] names = {"John", "Steve", "Shane", "Adam", "Ben"};
System.out.println("String array before sorting : " + Arrays.toString(names));
Arrays.sort(names);
System.out.println("String array after sorting in ascending order : " + Arrays.toString(names));
Выход:
String array before sorting : [John, Steve, Shane, Adam, Ben]
String array after sorting in ascending order : [Adam, Ben, John, Shane, Steve]
Уменьшение порядка
Arrays.sort(names, 0, names.length, Collections.reverseOrder());
System.out.println("String array after sorting in descending order : " + Arrays.toString(names));
Выход:
String array after sorting in descending order : [Steve, Shane, John, Ben, Adam]
Сортировка массива объектов
Чтобы отсортировать массив объектов, все элементы должны реализовать интерфейс Comparable
или Comparator
для определения порядка сортировки.
Мы можем использовать любой метод sort(Object[])
для сортировки массива объектов в его естественном порядке, но вы должны убедиться, что все элементы в массиве должны реализовать Comparable
.
Кроме того, они должны быть взаимно сопоставимыми, например, e1.compareTo(e2)
не должен бросать ClassCastException
для любых элементов e1 и e2 в массиве. В качестве альтернативы вы можете отсортировать массив объектов в пользовательском порядке, используя метод sort(T[], Comparator)
как показано в следующем примере.
// How to Sort Object Array in Java using Comparator and Comparable
Course[] courses = new Course[4];
courses[0] = new Course(101, "Java", 200);
courses[1] = new Course(201, "Ruby", 300);
courses[2] = new Course(301, "Python", 400);
courses[3] = new Course(401, "Scala", 500);
System.out.println("Object array before sorting : " + Arrays.toString(courses));
Arrays.sort(courses);
System.out.println("Object array after sorting in natural order : " + Arrays.toString(courses));
Arrays.sort(courses, new Course.PriceComparator());
System.out.println("Object array after sorting by price : " + Arrays.toString(courses));
Arrays.sort(courses, new Course.NameComparator());
System.out.println("Object array after sorting by name : " + Arrays.toString(courses));
Выход:
Object array before sorting : [#101 [email protected] , #201 [email protected] , #301 [email protected] , #401 [email protected] ]
Object array after sorting in natural order : [#101 [email protected] , #201 [email protected] , #301 [email protected] , #401 [email protected]00 ]
Object array after sorting by price : [#101 [email protected] , #201 [email protected] , #301 [email protected] , #401 [email protected] ]
Object array after sorting by name : [#101 [email protected] , #301 [email protected] , #201 [email protected] , #401 [email protected] ]
Преобразование массивов между примитивами и коробочными типами
Иногда требуется преобразование примитивных типов в бокс- типы.
Для преобразования массива можно использовать потоки (в Java 8 и выше):
Java SE 8
int[] primitiveArray = {1, 2, 3, 4};
Integer[] boxedArray =
Arrays.stream(primitiveArray).boxed().toArray(Integer[]::new);
С более низкими версиями это может быть путем итерации примитивного массива и явного копирования его в массив в штучной упаковке:
Java SE 8
int[] primitiveArray = {1, 2, 3, 4};
Integer[] boxedArray = new Integer[primitiveArray.length];
for (int i = 0; i < primitiveArray.length; ++i) {
boxedArray[i] = primitiveArray[i]; // Each element is autoboxed here
}
Точно так же массив в коробке может быть преобразован в массив его примитивной копии:
Java SE 8
Integer[] boxedArray = {1, 2, 3, 4};
int[] primitiveArray =
Arrays.stream(boxedArray).mapToInt(Integer::intValue).toArray();
Java SE 8
Integer[] boxedArray = {1, 2, 3, 4};
int[] primitiveArray = new int[boxedArray.length];
for (int i = 0; i < boxedArray.length; ++i) {
primitiveArray[i] = boxedArray[i]; // Each element is outboxed here
}
Массив — набор определённого числа однотипных элементов. Использование массива позволяет нам не создавать большое количество переменных, а создать всего лишь одну переменную, имеющую вид массива. В отличие от стандартных переменных массивы содержат больше, чем одно значение. В программировании это очень важно, ведь при разработке софта может потребоваться огромное количество данных.
Лучшая ассоциация для массива — стена с почтовыми ячейками. Каждая ячейка помечена квартирными номерами (индексы массива), внутри лежат газеты и письма (элементы массива), а получить содержимое можно, открыв ящик ключом (обратиться к содержимому по позиции элемента в массиве через индекс). При этом содержимое массива может включать в себя как простые данные (это одномерный массив), так и несколько вложенных массивов (это многомерный массив).
Массив однороден, и во всех ячейках должны храниться элементы одного типа. Если это int, то мы говорим про массив целых чисел, который может содержать лишь целые числа. Массив строк будет содержать лишь строки, а массив, состоящий из элементов созданного класса Dog, может содержать лишь объекты Dog.
Как происходит объявление массива в Java
Как и любую переменную в Java, массив надо объявить. Для этого есть два способа. Первый больше отвечает стилю Java, второй является наследием языка C.
Вне зависимости от способа, dataType — это тип переменных в массиве. Посмотрите внимательно на примеры — в них объявлены 2 массива. Один предназначен для целых чисел типа int, другой — для объектов типа Object.
Можно сказать, что во время объявления массива ему присваивается как имя (ArrayName), так и тип переменных.
Создание массива
Чтобы создать массив в Java, нужно зарезервировать место в памяти, для чего используем оператор new:
new typeOfArray [length];Здесь у нас typeOfArray — тип массива, length — длина массива или число ячеек, выраженное в целых числах (int). Но мы лишь выделили память под массив, не связав его ни с какой переменной, ранее объявленной. Как правило, сначала массив объявляют, потом создают:
int[] myArray; // объявление массива myArray = new int[10]; // создание массива, выделение памяти на 10 элементов типа intИтак, объявлен массив из целых чисел с именем myArray. После объявления мы сообщили, что массив состоит из 10 ячеек. Но можно использовать и более сокращённый синтаксис:
int[] myArray = new int[10]; // объявление и выделение памяти за один разЧто же, мы создали массив с помощью new. После этого в его ячейках будут записаны значения по умолчанию. Например, для численных типов — это нули (0), для boolean — false, а если говорить о ссылочных типах, то null. Это значит, что после выполнения кода
int[] myArray = new int[10];у нас на выходе будет массив из 10 целых чисел, причём в каждой ячейке будет записан 0.
Длина массива length
Длина массива — число элементов, под которое этот массив рассчитан. Длину массива изменить после создания нельзя.
Ещё нюанс: элементы массива в Java нумеруются с нуля. Таким образом, массив на 10 элементов состоит из чисел в диапазоне 0-9.
Если нужно получить доступ к длине нашего массива, используют переменную length:
int[] myArray = new int[10]; // создали массив, присвоили имя myArray System.out.println(myArray.length); // вывели в консоль длину массиваИнициализация массива
Инициализация — это заполнение массива конкретными данными, а не данными по умолчанию.
Нижеследующий код позволит создать массив, включающий в себя 4 сезона года. Также мы выполним заполнение массива строками-названиями сезонов:
String[] seasons = new String[4]; /* выполнили объявление и создание массива из 4 строк, где по умолчанию записано null, ведь строка — ссылочный тип данных*/ seasons[0] = "Winter"; /* в первую ячейку записали строку Winter*/ seasons[1] = "Spring"; /* во вторую ячейку (номер 1) записали строку Spring и т. д.*/ seasons[2] = "Summer"; seasons[3] = "Autumn";Так мы записали названия всех сезонов. Но в принципе можно всё сделать проще, совместив инициализацию и объявление:
String[] seasons = new String[] {"Winter", "Spring", "Summer", "Autumn"};Или даже так, опустив оператор new:
String[] seasons = {"Winter", "Spring", "Summer", "Autumn"};Динамический массив в Java
Минус массива — статичность, то есть необходимость задавать размер заранее. Для этого и придумали динамический массив, который может менять размер в процессе выполнения программы.
Например, статические массивы работают по следующей схеме:
А динамические массивы в Java функционируют несколько иначе:
Так как для копирования массива используется специальная нативная функция, проблем с «переездом» не возникает.
В общем, как вы уже догадались, динамические массивы применяются во время обработки наборов однородных данных, размер которых на момент написания программы нам неизвестен.