Как найти длину элемента массива java

In Java. Let’s say you’re given the following Array. Or something similar

int[] anArray = {10, 20, 30, 40, 1000};

Is there a way to take the length of the array element at anArray[4]; ?

I need to know if the array[x] is == 4. As in 2004, or 1000, or 1968.

How can i do this?

asked Feb 27, 2011 at 0:15

Snow_Mac's user avatar

1

You can convert the element to a string and get the length of the string, or if its integers you can test if it’s between 1000 and 9999.

answered Feb 27, 2011 at 0:17

Mark Byers's user avatar

Mark ByersMark Byers

804k190 gold badges1575 silver badges1450 bronze badges

Convert your array object to string and check is length :

anArray[x].toString().length

Community's user avatar

answered Feb 27, 2011 at 0:17

krtek's user avatar

krtekkrtek

26.2k5 gold badges56 silver badges84 bronze badges

1

You could convert the element to a string and then find the length of the string.

You could also use repeated division by 10 in a while loop to find your answer.

answered Feb 27, 2011 at 0:17

WuHoUnited's user avatar

WuHoUnitedWuHoUnited

8,2193 gold badges24 silver badges27 bronze badges

if (Integer.toString(anArray[x]).length() == 4) {
    // it's 4 long
}

answered Feb 27, 2011 at 2:36

Ted Hopp's user avatar

Ted HoppTed Hopp

232k48 gold badges394 silver badges520 bronze badges

Slightly geekier approach:

int lengthOfElement4 = (int) Math.floor((Math.log(anArray[4]) / Math.log(10) + 1);

@Mark’s second option will probably be quicker though…

answered Feb 27, 2011 at 1:05

Mac's user avatar

MacMac

14.6k9 gold badges62 silver badges80 bronze badges

Since car has not been initialized, it has no length, its value is null. However, the compiler won’t even allow you to compile that code as is, throwing the following error: variable car might not have been initialized.

You need to initialize it first, and then you can use .length:

String car[] = new String[] { "BMW", "Bentley" };
System.out.println(car.length);

If you need to initialize an empty array, you can use the following:

String car[] = new String[] { }; // or simply String car[] = { };
System.out.println(car.length);

If you need to initialize it with a specific size, in order to fill certain positions, you can use the following:

String car[] = new String[3]; // initialize a String[] with length 3
System.out.println(car.length); // 3
car[0] = "BMW";
System.out.println(car.length); // 3

However, I’d recommend that you use a List instead, if you intend to add elements to it:

List<String> cars = new ArrayList<String>();
System.out.println(cars.size()); // 0
cars.add("BMW");
System.out.println(cars.size()); // 1

Table of contents

      • Java Array Length: How do you find the length of an array?
      • Searching a value using Array Length in Java
      • Searching for the lowest value in the array
      • Searching for the highest value in the array
      • Frequently Asked Questions
      • Conclusion
  1. Java Array Length: How do you find the length of an array?
  2. Searching a value using Array Length in Java
  3. Searching for the lowest value in the array
  4. Searching for the highest value in the array
  5. Frequently Asked Questions
  6. Conclusion

Java Array Length: How do you find the length of an array?

The length attribute of Java holds the number of elements in the array. In Java, there is no predefined method by which you can find the length of an array. But you can use the length attribute to find the length of an array. When we declare an array, the total number of elements in it is called the array’s length, or we can also call it the size of the array. You can also take up a java programming free online course and learn more about the concepts before learning about arrays in java.

Let us see the below example for a better understanding:

int len = thisArray.length;

Let us see a program using the Array Length attribute of Java:

import java.util.*;
class Main
{
    public static void main(String[] args)
    {
        Integer[] intArray = {1,3,5,7}; //integer array
        String[] strArray = { "one", "two", "three", “four” }; //string array
 
                //print each array and their corresponding length
        System.out.println("Contents of Integer Array : " + Arrays.toString(intArray));
        System.out.println("The length of the array is : " + intArray.length);
 
        System.out.println("Contents of String array : " + Arrays.toString(strArray));
        System.out.println("The length of the String array is : " + strArray.length);
    }
}

OUTPUT:

Contents of Integer Array: [1,2,5,7]

The length of the array is: 4

Contents of String array: [one, two, three, four]

The length of the String array is: 4

In the above program, the length function counts the total number of elements in the array, whether a string or a number. The length attribute takes the length of the array. There can be different scenarios where you can use the Array Length attribute, such as:

  • To search for a minimum value in the array.
  • To find the maximum number in an array.
  • To get any specific value from the array. 
  • To check if any specific value is there in the array or not.

There can be more scenarios where you can use the Array Length attribute in Java. 

In this article, we will see more scenarios of using the Array Length attribute of Java with some useful programs and examples. 

Searching a value using Array Length in Java

The Array Length attribute can be used for several cases, so it is essential. It can also be used for searching for a value in an array. You need to use a loop that will iterate through all the elements in the array one after the other until it finds the searched element. 

When the code runs, the loop will start searching the element in the array until it reaches the last element or traverses the complete length of the array. When it is traversing through each element in the array, it compares the value of each element to the value to be searched, and if the value of the element is matched, then it stops the loop.

The program below does the same we just discussed, and it will help you to understand better how the code will work:

import java.util.*;
class Main{
public static void main(String[] args) {
    String[] strArray = { “HTML”, “CSS”, "Java", "Python", "C++", "Scala", }; //array of strings
                //search for a string using searchValue function
    System.out.println(searchValue(strArray, "C++")?" value C++ found":"value C++ not found");
    System.out.println(searchValue(strArray, "Python")?"value Python found":"value Python not found");
}
 
private static boolean findValue(String[] searchArray, String lookup)
{
    if (searchArray != null) {
        int arrayLength = searchArray.length; //computes the array length
        for (int i = 0; i <= arrayLength - 1; i++)
        {
            String value = searchArray[i]; //searching for value using for loop
            if (value.equals(lookup)) {
               return true;
            }
        }
    }
return false;
}

Value C++ found

Value Python found

In the above program, as you can see, we have an array that contains the names of some programming languages. There’s a function with the name ‘findValue’ that searches for the specific value we are trying to find in the array. We used the for loop that traverses through each element in the array and finds it the value exists in our array or not. We gave two statements for both the cases, such as if the value is in the array or not. What it does is it returns true if the value is found in the array and false otherwise. 

In our case, the values C++ and Python were there in our array and that’s the reason it returned true or the statements that we provided as true. 

Searching for the lowest value in the array

As we have seen, how the Array length attribute works and how it makes our code easier to find the value we are searching for. In this section, we will see how we can find the minimum value in an array. 

The below program is used to find the lowest value in an array:

import java.util.*;
class Main {
    public static void main(String[] args) {
       int[] intArray = { 2,40,11,10,3,44 }; //int array
       System.out.println("The given array:" + Arrays.toString(intArray));
       int min_Val = intArray[0]; // we are assigning first element to min value
       int length = intArray.length;
       for (int i = 1; i <= length - 1; i++) // it goes till end of array, compares with each element and finds the minimum value
        {
            int value = intArray[i];
            if (value <min_Val) {
               min_Val = value;
            }
        }
 
    System.out.println("The lowest value in the array: "+min_Val);
    }
}

OUTPUT:

The given array: [2, 40, 11, 10, 3, 44]

The lowest value in the array: 2

We gave the first element as the lowest element in the array in the above program. But still, it assigned the first element 2 as the minimum value and compared it with other elements in the array. When it is found that the value 2 is the only minimum, it comes out from the loop and returns the min value from the array. 

Suppose we have provided the minimum value at some other place in the array. In that case, it will assign each value in the array as a minimum value and compare it with other elements until it finds the correct one. This way, we can find the minimum value in the array.

Searching for the highest value in the array

In the above section, we saw how to find the minimum value in an array. The same logic will be applied in this example, where we search for the maximum value in an array. The only thing that will change is only the smaller than (<) sign. 

Let us see the example below:

import java.util.*;
class Main {
   public static void main(String[] args) {
        int[] intArray = { 2,40,1,10,95,24 }; //int array
        System.out.println("The given array:" + Arrays.toString(intArray));
        int max_Val = intArray[0]; //reference element as maximum value
        int length = intArray.length;
        for (int i = 1; i <= length - 1; i++) // It finds the maximum value of the element by comparing others to reference
        {
        int value = intArray[i];
        if (value >max_Val) {
             max_Val = value;
            }
        }
       System.out.println("The largest value in the array: "+max_Val);
    }
}

OUTPUT:

The given array: [2,40,1, 10,95,24]

The largest value in the array: 95

The above code did the same as it did to find the smallest value in the array. The thing that is changed is the condition for comparing with another element. We compared the smallest elements, and now we used to find the largest ones. 

Frequently Asked Questions

Q. What is the difference between the Size of ArrayList and the length of an Array?

A. In the ArrayList attribute, there is no length property, but it still gives the length by using the size() method, whereas the length property of the array gives the total number of elements in the array or the length of the array. 

Q. Are length and length() same in Java?

A. Length() is a method used for the string objects to return the number of characters in a string where ‘length’ is the property to find the total number of elements in an array, and it returns the size of the array. 

Q. How to find the largest number in an array using the array length attribute in Java?

A. To find the largest number or value in an array, we need to create a loop that will traverse through each element in the array and compares each element by assigning the first value of the array as the maximum. To understand better, go to the section ‘Searching for the highest value in the array’ of this article, where we discussed an example. 

Q. How to get the length in Java?

A. There are different scenarios to find the length. For example, we have two options to use the length() method or the java length attribute. Both of them are used for different purposes and return different values. So, if you want to find the length of characters in a string, you need to use the length() method, whereas if you want to find the length or size of an array, you must use the length attribute of Java. 

Q. What do you mean by length function in Java?

A. The length() function in Java is used to get the number of characters in a string. 

Conclusion

Thus, we have come to the end of this article where we discussed the Java Array Length attribute, which is very useful in different programming scenarios. We also discussed specific cases, such as finding the largest and smallest value in an array. However, there are more uses for this attribute. So, we encourage you to find more cases and try to use this length attribute. 

In this blog post, we are going to learn an important topic pertaining to Java i.e Array length.

Java is a high-end programming language by accompanying robustness, security, and greater performance.

An array length in Java represents a series of elements that an array could really hold. There really is no predetermined method for determining an object’s length. In Java, developers can discover its array length with the help of array attribute length. One such attribute is used in conjunction with array names. To gain deeper insights into this programming language, java training is compulsory. Therefore in this blog post, we’ll look at how to calculate the size as well as the length of the arrays in Java.

Length Attribute in Java

The length attribute throughout Java represents the size of the array. Each array has a length property, for which the value seems to be the array’s size. The overall quantity of elements that the array can encompass is denoted by its size. In order to access the length property, use dot (.) operator which is accompanied by an array name. Also we can determine the length of int[ ]double[] and  String[]. As an example:

int[] arr=new int[5];  

int arrayLength=arr.length

In the above sample code, arr represents the array type and it is the int with a capacity of 5 elements. In simple terms array Length perhaps is the variable that keeps track of the length of an array. An array name (arr) is accompanied by a dot operator as well as the length attribute to determine the length of the array. It defines the array’s size.

Array length = Array’s last Index+1

Array Length in Java with Examples

Array last index = 7

Array length = 7+1 = 8

It is important to note that such length of the array defines the upper limit number of the elements that can hold or its capacity. This does not include the elements which are added to the array. It is, length comes back the array’s total size. The length and size of arrays for whom the elements have been configured just at the time of their establishment were the same.

However, if we’re talking well about an array’s logical size or index, after which merely int arrayLength=arr.length-1, since an array index begins at 0. As a result, the logical, as well as an array index, was always one less than the real size.

First Index:

0 1 2 3 4 5 6 7 8 9

In the above picture, 0 is the first index and the array length will be 10.

Now we will explore how to fetch the length of an array using an example.

Arraylengthex1.java

public class ArrayLengthExample1

{

    public static void main(String[] args)

    {

        //defining an array of type int named num

        //the square bracket contain the length of an array

        int[] num = new int[11];

        //length is an Array attribute that determines the array length

        int arrayLength=num.length;

        //prints array length

        System.out.println(“length of an array is “+ arrayLength);

    }

}

Output:

length of an array is 11

Arraylenghtex2.java

public class ArrayLengthExample2 {

    public static void main(String[] args) {

        //initializing an array of type String named country

        String[] country = { “cat”, “dog”, “pig”, “mouse”, };

        //length is an Array attribute that determines the array length

        int arrayLength=country.length;

        //prints array length

        System.out.println(“Size of an array is: “ + arrayLength);

    }

}

Output:

Size of an array is 4

ArraylengthEx3.java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

public class ArrayLengthEx3 {

    private static void LengthOfArray(String[] array) {

        //checks array is empty or not

        if (array == null)

        {

            //if the array is empty prints the following statement

            System.out.println(“an array length cannot be empty.”);

        }

        else {

            //length attribute of the Array class determines the length of an array

            int arrayLength = array.length;

            //prints the array length

            System.out.println(“An array length is: “+arrayLength);

        }

    }

    public static void main(String[] args) {

        String[] fruits = { “Banana”, “Apple”, “Melon”, };

        String[] alphabets = { “k”, “t”, “l”, “m”, };

        String[] numbers = { “25”, “63”, “84”, “90”, “11”, };

        //passing null value to the function

        LengthOfArray(null);

        //passing fruits array to the function

        LengthOfArray(fruits);

        //passing alphabets array to the functiona

        LengthOfArray(alphabets);

        //passing numbers array to the function

        LengthOfArray(numbers);

    }

}

Output:

an array length cannot be empty.
An array length is: 3
An array length is: 4
An array length is: 5

Searching a Value Using the Array Length in Java

The array length does have a lot of good properties which can be used in coding. In the following scenario, we just use the length of an array to loop through all elements and see if the specified value is visible.

Example:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public class ArrayLengthJava {

    private static boolean arrayContainsValue(String[] myArray,

    String lookForValue) {

        if (myArray != null) {

            int arrayLength = myArray.length;

            for (int i = 0; i <= arrayLength 1; i++) {

                String value = myArray[i];

                if (value.equals(lookForValue)) {

                    return true;

                }

            }

        }

        return false;

    }

    public static void main(String[] args) {

        String[] JavaArray = { “I”, “hate”, “sweets”};

        System.out.println(arrayContainsValue(JavaArray, “hate”));

        System.out.println(arrayContainsValue(JavaArray, “love”));

    }

}

Output:

true
false

The program above returns true because “hate” is present in the array, but “love” is a non-existent element, so the result is false.

Search for the Lowest Value in the Array

The length of an array can be used to find the lowest value in an array object.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class ArrayLengthJava {

    private static int minValue(int[] myArray) {

        int minValue = myArray[0];

        int arrayLength = myArray.length;

        for (int i = 1; i <= arrayLength 1; i++) {

            int value = myArray[i];

            if (value < minValue) {

                minValue = value;

            }

        }

        return minValue;

    }

    public static void main(String[] args) {

        int[] JavaArray = { 28, 46, 69, 50 };

        System.out.println(“The min value in the array is: “+minValue(JavaArray));

    }

}

Output:

The minimum value in an array is: 28

Search for the Max Value in an Array

Moreover, we could use an array’s length to find the highest value in an array object.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public class ArrayLengthJava {

    private static int maxValue(int[] myArray) {

        int maxValue = myArray[0];

        int arrayLength = myArray.length;

        for (int i = 1; i <= arrayLength 1; i++) {

            int value = myArray[i];

            if (value > maxValue) {

                maxValue = value;

            }

        }

        return maxValue;

    }

    public static void main(String[] args) {

        int[] JavaArray = { 29, 46, 85, 69 };

        System.out.println(“The max value in an array is: “+maxValue(JavaArray));

    }

}

Output:

The max value in an array is: 85

Conclusion

Hope you have got enough knowledge in handling array length in java. If you have any queries please drop them in the comments section to get them clarified.

Happy Coding!

Author Bio:

I am VarshaDutta Dusa, Working as a Senior Digital Marketing professional & Content writer in HKR Trainings. I Have good experience in handling technical content writing and aspire to learn new things to grow professionally. I am expertise in delivering content on the market demanding technologies like mulesoft Training, Dell Boomi Tutorial, Elasticsearch Course, Fortinet Course, postgresql Training, splunk, Success Factor, Denodo, etc.

Для хранения данных, используемых при работе программы, применяются переменные того или иного типа. Например, если требуется сохранить имя игрока, то создается переменная String name, если целочисленное значение, то int number и т. д. Когда таких значений немного или их количество заранее известно, то для них приемлемо использовать отдельные переменные.

Но что делать, когда в программе задействовано не одно, а 10 чисел, или их количество становится известно только на этапе запуска приложения, когда пользователь вводит его с клавиатуры? Или в какой-то игре может участвовать разное количество игроков, устанавливаемое при ее старте. В таких ситуациях отдельными переменными уже не обойтись, т. к. их точное количество будет невозможно определить. Да и, если все же попытаться это сделать, код станет громоздким и не универсальным, а работа с ним будет крайне ограниченной из-за невозможности использования цикла для автоматизированной обработки данных.

Вот тут-то и приходит на выручку такая структура данных как массив, которая позволяет хранить в себе значения одного типа, что значительно упрощает их обработку.

Дадим определение массиву.

Массив — это структура данных фиксированного размера, являющаяся объектом и состоящая из ячеек, расположенных последовательно в памяти, которые могут хранить в себе значения только одного, заранее заданного типа. При этом каждая ячейка обладает адресом (порядковым номером, индексом), позволяющим получать к ней доступ.

На картинке ниже схематично изображен массив размерностью 10, заполненный числами, а также индексы ячеек:

В повседневной жизни мы постоянно сталкиваемся с массивами, например, пчелиные соты, контейнер для куриных яиц, коробка с конфетами, формочки для заморозки льда и т. д. Все эти хранилища тоже содержат ячейки, где размещается тот или иной продукт одного типа (яйца не могут храниться в сотах, как и лед вместо конфет — для каждого продукта используется свой контейнер).

Далее мы подробно и обстоятельно рассмотрим массив и его устройство.

1. Объявление переменной массива

Для того, чтобы можно было работать с массивом, необходимо иметь к нему доступ. Для этого требуется объявить (создать, декларировать) переменную, с помощью которой, как через пульт, мы могли бы обращаться к конкретным ячейкам массива, указывая номер нужного «канала» (индекса).

Пример объявления таких переменных:


double[] numbers;
char[] letters;
int[] ids;

Такие переменные в Java объявляются точно так же, как любые другие (у них есть тип данных и имя). Отличие лишь в наличии квадратных скобок [], размещаемых после типа хранимых в массиве данных (при этом перед [] пробел не ставится). Скобки являются специальным маркером, указывающим на то, что переменная предназначена для массива.

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

Все возможные варианты оформления:


int[] arr; — общепринятый Java-стиль
int arr[];
int [] arr;
int arr [];

По историческим причинам (наследство от языка С/С++) Java позволяет размещать [] в разных местах, но это не значит, что нужно использовать какой-то иной стиль, кроме общепринятого (или используемого в конкретной компании), даже если вы увидите подобный код у кого-то в интернете или книге. Всегда придерживайтесь одного стиля, не смешивайте разные способы написания в одной программе.

Т. к. массив всегда хранит множество значений, то для именования переменной используется:

  • существительное во множественном числе, например, cats, cars, resumes, playerAttempts
  • местоимение, например, allNumbers, myBooks
  • прилагательное, например, physicalConstants

String[] fullNames;
Player[] players;
short[] nums;

Массив может хранить не только значения примитивных, но и ссылочных типов. И сам он тоже является ссылочным типом данных. В первой строке объявляется переменная массива строк, во второй — массива игроков, а в третьей — переменная для хранения примитивных целых значений.

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

Чтобы создать массив, необходимо использовать ключевое слово new с указанием его размерности и типа:


int[] array = new int[10];

Такого рода запись следует читать справа налево следующим образом:

  • Оператор new выделяет в памяти (heap, куче) место под хранение десяти значений типа int
  • Затем он возвращает ссылку (будет храниться в стеке) на начало области памяти (совпадает с первым элементом), выделенной под массив
  • Ссылка помещается в переменную array того же типа, что и массив

На картинке схематично в памяти изображен массив int размерностью 10, заполненный числами:

Следует помнить, что после создания массива его размер (длину) изменить нельзя.

Еще пример, но уже не с примитивами, а со ссылочным типом String:


String[] strings = new String[4];

это то же самое, что и 
String[] strings;
strings = new String[4];

Первый вариант предпочтительней, т. к. не стоит без явной причины объявлять переменную и создавать массив на разных строках — это и больше кода, и подобная запись всегда вызовет у опытного программиста недоумение: «А нафига так было делать, если можно в одну строку?».

Как написано в документации, массив является объектом: «An object is a class instance or an array». Но наблюдательный читатель, возможно, заметил, что хоть он и является таковым, но при этом не имеет класса, который описывал бы его. Мы просто используем массив, как есть. Но это «как есть» хранит в себе множество скрытых процессов и тайн, которые мы по возможности приоткроем.

Хоть тип массива и не является классом, например int[], но все же имеет ассоциируемый с ним класс, который автоматически создает виртуальная машина (Java Virtual Machine, JVM). При этом данный класс неявно наследуется от java.lang.Object, что делает доступным все его методы (кроме clone) и интерфейсы Cloneable и Serializable. Но у программиста нет доступа к его коду, его нельзя посмотреть глазами.

Ассоциируемые классы создаются для каждого типа хранимой в массиве информации, например, для boolean[], или Player[], или String и т. д. И мы можем узнать, как эти классы называются. Они-то и являются реальными типами массивов. Чтобы увидеть их названия, необходимо воспользоваться Java-магией (рефлексией), которая позволит узнать настоящий тип массива, его суперкласс (от которого он наследуется) и список доступных методов.

Создадим массив нулевой длины (пустой) и отобразим нужную нам информацию (не забудьте сделать импорт java.lang.reflect.Method):


int[] arr = {};
System.out.println("Тип массива - " + arr.getClass());
System.out.println("Суперкласс типа массива - " + arr.getClass().getSuperclass());

System.out.println("Доступные методы:");
for (Method m : arr.getClass().getMethods()) {
    System.out.println(m.getName());
}

  • [I — это сигнатура типа (класса, который JVM создает во время выполнения) для объекта «массив с элементами типа int». Это и есть настоящий тип данных массива, как объекта
  • [ говорит, что это одномерный массив
  • I, что он содержит целые числа
  • Имя суперкласса, записанного с помощью его полного имени — java.lang.Object

Все возможные сигнатуры типов имеют следующий формат:


[B - byte
[C - char
[D - double
[F - float
[I - int
[J - long
[S - short
[Z - boolean
[L - любой объект

Можно сделать вывод, что тип массива и тип хранимых им значений — это формально разные типы. В нашем примере типом массива является тип [I, а типом хранимых значений — int.

Разберем еще одно доказательство того, что Object является суперклассом для массивов:


Object obj = new int[]{3, 6, 9};
int[] arr = (int[]) obj;
System.out.println(obj);
System.out.println(arr);

В первой строке объявляется и инициализируется массив, ссылка на который присваивается переменной типа Object. И при этом никакой ошибки не возникнет. Во второй строке происходит приведение Object к int[]. В итоге обе переменные (их ссылки) указывают на один и тот же массив.

Написанный выше код отобразит следующий результат:

Как известно, если попытаться вывести, например, в println значение объекта, просто записав его имя в метод в качестве аргумента, то неявно будет вызван метод toString(). А так как массивы его не переопределяют, т. е. у них нет своей реализации этого метода, то используется реализация по умолчанию, записанная в классе Object.

Как написано в документации, данный метод возвращает строку, получаемую с помощью следующего кода:


getClass().getName() + '@' + Integer.toHexString(hashCode())

В итоге она состоит из имени класса, в нашем случае — [I, разделителя в виде @ и шестнадцатеричного представления хеш-кода объекта. Для человека эта информация не несет никакой полезной нагрузки. Решение этой проблемы обсуждается во второй части статьи.

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

И на закуску немного сумасбродства и неочевидных вещей — создадим пустой массив с нулевой длиной:


String[] array1 = {};
char[] array2 = new char[0];

Как вы думаете, как в памяти представляются эти массивы?

Массив с нулевым размером представляет собой объект, у которого есть заголовок объекта (Object header) и размер, но нет места в памяти, выделенного для его элементов. При этом ссылка на такой массив является рабочей и сохраняется в переменную.

Массив нулевой длины не равен null:

null — это указатель в никуда, который является маркером отсутствия указателя на объект.

В спецификации написано: «Поле length является public final (общедоступным и неизменяемым) и содержит в себе количество элементов массива (длина может быть положительной или нулевой)».

Это поле вычисляется один раз при создании массива, т. к. его размер никогда не меняется.

Вызов этого поля часто путают с вызовом метода length() получения длины String. Но length — не метод, а поле. Доступ к нему можно получить напрямую, поскольку оно является общедоступным и неизменяемым (хотя тут, возможно, что это просто плохое архитектурное решение из далекого прошлого).

Т. к. данное поле является частью объекта и не меняется, то это позволяет JVM не пересчитывать количество элементов массива всякий раз, когда в коде используется его длина — она просто берет его из заголовка объекта, когда это требуется.

Чтобы вас окончательно запутать, сошлюсь на документацию, в которой написано: «Длина массива не является частью его типа». Значит length не хранится в ассоциируемом классе!

«Да, это какой-то вынос мозга», — скажете вы: класса нет, но массив — это объект. При этом он наследуется от Object. А length — вроде бы, поле, но не совсем.

А где тогда хранится длина массива?

Она размещается в заголовке объекта. Что такое заголовок? Это часть любого объекта, содержащая метаинформацию о нем. Давайте взглянем на этот заголовок, используя утилиту Java Object Layout (JOL).

Чтобы программа ниже у вас заработала, необходимо в IDEA нажать Ctrl + Alt + Shift + S, выбрать Modules, а затем в Dependencies нажать + → Library… → From Maven… В строке поиска ввести org.openjdk.jol.


import org.openjdk.jol.info.ClassLayout;

public class JOLArray {

    public static void main(String[] args) throws Exception {
        System.out.println(ClassLayout.parseInstance(new int[10]).toPrintable());
    }
}

В итоге на консоль будет выведена следующая метаинформация из заголовка объекта:

Из всего вывода нас интересует строка: 12 4 (array length) 10.

Это и есть длина созданного массива new int[10], которая имеет размер 4 байта. Поле length является особенным в том смысле, что оно находится в заголовке объекта массива, а для получения его длины используется специальный байт-код.

Больше о заголовке объекта можно узнать в видео Алексея Шипилева.

Так же следует заметить, что в наборе инструкций JVM все объекты создаются с использованием одних и тех же байт-кодов, за исключением массивов — они обрабатываются специальными командами.


public class ByteCodeArray {

    public static void main(String[] args) {
        int[] nums = new int[5];
        int len = nums.length;
    }
}

Отобразим байт-код этого класса с помощью javap:


javap -c ByteCodeArray.class

Code:
       0: iconst_5
       1: newarray       int
       3: astore_1
       4: aload_1
       5: arraylength
       6: istore_2
       7: return

Нас в нем интересуют две строки: newarray int, которая создает массив int-ов и arraylength, которая получает длину массива. Таким образом, доступ к нему не осуществляется, как если бы это было обычное поле. Этого поля просто не существует в типе массива. Для работы с ним у JVM есть отдельная инструкция, которая берет его из заголовка объекта.

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

5.1. Сокращенная форма создания и инициализации

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


String[] names = new String[]{"Max", "Grigoriy", "Java"};

// та же запись, но короче
String[] names = {"Max", "Grigoriy", "Java"};

Длина массива, объявленного таким образом, зависит от количества перечисленных элементов. Во втором варианте тип массива определяется автоматически, исходя из хранимых данных.

Исходя из примеров выше следует отметить, что в Java в массивах хранятся не сами объекты, а ссылки на них, которые, в свою очередь, указывают на место в куче (heap), где находится соответствующий объект.

Схематично это можно изобразить так:


float[] partsExpression = {1.83, 1.67, 1.75, 1.50};

Resume[] resumes = {new Resume("uuid1"), new Resume("uuid2")};

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

5.2. Ручная инициализация по индексу

Элементы массива начинают храниться с нулевого индекса: самая первая ячейка находится под индексом 0, а не 1. Это может показаться непривычным, но на то есть причина.

На самом деле, индекс в Java является ничем иным, как смещением памяти относительно начала массива (расстоянием от его начала до любого элемента). А т. к. начальный адрес совпадает с адресом первого элемента, то смещение будет равно 0, а значит и индекс тоже.

Адрес любой ячейки массива рассчитывается по следующей формуле:


адрес начала массива + индекс * количество памяти, выделенное на один элемент

Например, есть массив int[] nums = {3, 2, 1};

Предположим, что nums хранит адрес 0xFF00. Тогда ячейки массива будут иметь следующие адреса (с учетом того, что на каждое значение int выделяется 4 байта):


nums[0] → 0xFF00;
nums[1] → 0xFF04;
nums[2] → 0xFF08;

Более научное объяснение того, почему индексация начинается с 0, а не с 1, можно прочитать в следующей статье.

С индексацией разобрались. Скажем теперь пару слов про то, чему равно количество индексов в массиве. Оно всегда равно length — 1. Это связано с тем, что размер массива (его длина) всегда больше на единицу самого последнего индекса из-за того, что индексация начинается 0.

Количественно размер массива и число индексов равно, но в числовом представлении оно отличается на 1 в меньшую сторону, если считать индексы по порядку. Таким образом, в приведенном ниже примере с массивом из 2 элементов индексы идут от 0 до 1, а длина массива равна 2.

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


int[] nums = new int[2];
nums[0] = 3;
nums[1] = 7;
int num = nums[0];
int num1 = nums[1];
System.out.println(num);
System.out.println(num1);

// или можно сразу вывести значение без создания переменной
System.out.println("Под индексом 0 хранится значение " + nums[0]);
System.out.println("Под индексом 1 хранится значение " + nums[1]);

В этом примере в первом случае сначала в ячейки массива под индексами 0 и 1 сохраняются числа 3 и 7. Затем они же считываются из него и размещаются в переменные num и num1. Далее их значения выводятся на консоль.

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

В консоли в обоих случаях отобразятся числа 3 и 7, взятые из массива nums по индексам 0 и 1.

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

Данный способ все же не совсем подходит для автоматической инициализации массива. Но для понимания того, как обращаться к значениям массива по индексу, он очень показателен.

Приведем для примера «странный» код:


System.out.println((new int[]{3, 6, 9})[1]);

В итоге в консоли отобразится число 6, находящееся под индексом 1.

Данный код позволил «подключиться» к массиву без использования переменной. Подобный способ может показаться не совсем очевидным, но, как видим, он работает. Пользы от него немного, но как демонстрация того, что к массиву можно обращаться и без переменной, а сразу через «голую» ссылку, вполне подходит. В реальном проекте вы, скорее всего, не будете использовать подобные выкрутасы. Они нужны лишь для понимания работы тонкостей массива.

5.3. Инициализация и доступ к элементам в цикле

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

При использовании цикла необходимо знать следующие параметры:

  • начальное значение индекса (откуда стартует итерация)
  • значение, ограничивающее количество итераций (обычно используется длина массива или 0 — если итерация стартует с конца массива)
  • конечное значение индекса (для завершения числа итераций)

Для работы с массивами с учетом вышеописанных требований удобнее всего использовать цикл for. Как мы знаем, он состоит из трех секций: инициализация счетчика (начальное значение индекса), условие выполнения (число итераций) и изменение счетчика (для достижения конечного значения индекса).

В качестве типа данных индекса массива можно использовать int, short, byte или char. Использование типа long приведет к ошибке компиляции, т. к. индексы массива в Java преобразуются в int-значения (4 байта). А т. к. под long выделяется больше памяти (8 байт), то преобразование к int потенциально может привести к потерям данных, о чем и сообщит компилятор.

Приведем пример такого кода:


int[] ints = new int[5];
for (long lng = 0L; lng < ints.length; lng++) {
    System.out.println(ints[lng]);
}

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


System.out.println((int) ints[lng]);

Закончив это небольшое отступление, продолжим разбираться с циклом for.

Начальное значение индекса — это значение, с которого будет начинаться доступ к ячейкам массива. Обычно начинают с самого начала, т. е. с 0 (с первой ячейки). Но не обязательно. Есть ряд задач, в которых удобнее начинать с конца (длина массива — 1).

Значение, ограничивающее количество итераций, позволяет не выйти за правую границу массива, когда индекс >= длине массива. Если цикл реализован так, что проход по массиву осуществляется с конца к началу, то тут все наоборот: длина — 1 будет началом, а условие index >= 0 будет защищать от выхода за его левую границу.

Цикл прерывается, когда конечное значение индекса совпадает с его длиной или оно < 0.

Пример работы циклов по массиву слева направо:


String[] strings = new String[4];
 
for(int i = 0; i < strings.length; i++) {
    strings[i] = "Строка по индексу " + i;
}
 
for(int i = 0; i < strings.length; i++) {
    System.out.println(strings[i]);
}

В этом примере создается массив строк размерностью 4.

В первом цикле в массив сохраняется сконкатенированный (склеенный) текст с номерами индексов.

Второй цикл выводит на консоль значения каждой ячейки. Число в квадратных скобках — это конкретная позиция массива, к которой мы хотим получить доступ.

В обоих циклах переменная i используется в качестве счетчика для обозначения индекса. Она имеет начальное значение 0, которое в процессе работы циклов меняется на единицу (инкрементируется) после каждой итерации (одного прохода цикла). Как только условие i < strings.length перестает выполняться, т. е. проверка вернет false, то цикл прекращается.

Вы можете спросить, почему я использовал идентификатор «i»? Разве это не «плохое» имя для переменной? Да, обычно для имен переменных выбираются имена, глядя на которые сразу бывает понятно, что они хранят. Но в данном случае действует негласное соглашение, о котором можно прочитать тут.

Если в двух словах, то счетчики циклов принято именовать с помощью i, j и k, где i — находится во внешнем цикле, j — во вложенном в него цикле и т. д.

Считается, что этот стиль возник в языке программирования Фортран, где имена переменных, начинающиеся с букв I по Q, по умолчанию считались целыми, остальные были действительными. А еще раньше это появилось в математике, где индексы для сумм и умножений именуются как i, j, k.

Приведем еще один пример работы с массивом в цикле, но уже в обратном порядке:


char[] chars = new char[32];
int i = 0; 
for(char ch = 'Я'; ch >= 'А'; ch--) {
    chars[i++] = ch;
}

for(i = chars.length - 1; i >= 0; i--) {
    System.out.print(chars[i]);
}

В первом цикле массив chars заполняется буквами от А до Я. Он работает до тех пор, пока выполняется условие ch >= ‘А’. Во втором цикле все буквы выводятся на консоль.

Что будет, если вывести массив без инициализации?

Проверим эту идею, создав массивы размерностью 1 всех примитивных типов и String. Отобразим их значения в консоль без инициализации:


System.out.println("Значение по умолчанию для byte " + (new byte[1])[0]);
System.out.println("Значение по умолчанию для short " + (new short[1])[0]);
System.out.println("Значение по умолчанию для int " + (new int[1])[0]);
System.out.println("Значение по умолчанию для long " + (new long[1])[0]);
System.out.println("Значение по умолчанию для float " + (new float[1])[0]);
System.out.println("Значение по умолчанию для double " + (new double[1])[0]);
System.out.println("Значение по умолчанию для char " + (new char[1])[0]);
System.out.println("Значение по умолчанию для boolean " + (new boolean[1])[0]);

System.out.println("Значение по умолчанию для String " + (new String[1])[0]);

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

Значение переменной char не отображается (не имеет никакого представления), т. к. соответствует коду ‘u0000’, являющимся пустым символом.

Известно, что локальные переменные по умолчанию не инициализируются, но с массивом, как мы видим, все иначе. Спецификация (1, 2) языка требует его инициализации значениями по умолчанию, что фактически мы и наблюдали в примере.

Что будет, если выйти за границы массива?

За границу массива мы можем выйти с двух сторон: слева (когда индекс отрицательный) и справа (когда он >= длине массива). В обоих случаях произойдет ошибка (исключительная ситуация) и вылетит исключение java.lang.ArrayIndexOutOfBoundsException.

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


int[] nums = new int[4];
 
for(int i = 0; i <= nums.length; i++) {
    nums[i] = i + 1;
}

Из-за того, что условие i <= nums.length при i = 4 вернуло true, в строке nums[i] = i + 1; возникла ошибка связанная с тем, что в массиве нет ячейки под индексом 4. Ситуации nums[4] = 4 + 1 быть не должно.


String[] str = {"A", "B", "C"};

for(int i = str.length - 1; i >= 0; i--) {
    System.out.println(str[i - 1]);
}

В коде ошибка произошла из-за того, что в какой-то момент в строке str[i — 1] индекс стал равен str[0 — 1]. Информация в консоли сообщает, что индекс не может быть -1, т. к. он вне пределов длины 3.

Для работы с массивами цикл for является более предпочтительным, чем while, но и он не идеален, т. к. имеет массу мест, где можно совершить ошибку: не так инициализировать счетчик, неверно написать условие работы цикла, перепутать название счетчика и т. д.

Чтобы как-то минимизировать количество ошибок, упростить работу с массивами и коллекциями (далее будут упоминаться только массивы) и сделать код более лаконичным, начиная с JDK 5, была внедрена упрощенная версия цикла for под названием for-each.

Код, записанный в традиционном стиле:


int[] nums = new int[10];

for (int i = 0; i < nums.length; i++) {
    System.out.print(nums[i]);
}

Тот же самый код, но с использованием for-each:


int[] nums = new int[10];

for (int num : nums) {
    System.out.print(num);
}

Цикл for-each состоит из двух секций, отделенных друг от друга двоеточием (при этом перед и после него обычно ставят пробел): в правой части размещается имя массива, а в левой создается переменная того же типа, что и элементы массива. Элементы по порядку берутся из массива и помещаются в эту переменную, значение из которой в каждой итерации выводится на консоль.

Данный вид цикла является так называемым «синтаксическим сахаром», который отличается от традиционного цикла for только внешне, но для JVM в них нет никаких различий.

  • Отсутствие счетчика индекса — все ячейки перебираются по порядку, начиная с нулевой
  • Отсутствие условия работы цикла — это действие выполняется автоматически и скрыто от программиста

Цикл for-each позволяет получить доступ к элементам массива, но не дает возможности использовать индексы (к ним банально нет доступа) или обращаться к значениям в отличном от последовательного доступа порядке. Кроме того, он не позволяет менять или удалять значения массива. В основном, его используют для вывода элементов массива на консоль. Если вам нужно больше возможностей, то используйте обычный цикл for.

Цикл for-each используется, когда:

  • необходимо вывести значения массива по порядку
  • не нужно изменять массив
  • не нужны индексы

char[] chars = {'q', 'w'};
 
for(char symbol : chars) {
    System.out.println(symbol);
}

Вывод:
q
w

Цикл for-each для работы с массивами предоставляет массу преимуществ и удобств, нежели for и, тем более, while и do-while. Старайтесь его использовать везде, где это возможно.

7. Удаление элементов из массива

Помимо сохранения данных в массив, очень часто приходится их удалять.

Под удалением не имеется в виду, что массив станет меньше из-за того, что ячейка со значением исчезнет или есть какая-то специальная команда, которая выполняет эту операцию. Удаление в массиве — это всего лишь перезапись ячейки любым значением, отличным от удаляемого.


float[] nums = {1.5f, 0.22f, 1.0f};

System.out.println(nums[1]);
nums[1] = 3.31f;
System.out.println(nums[1]);

Вывод:
0.22
3.31

В этом примере создается массив из float. Затем выводится начальное значение по индексу 1. Далее по этому индексу устанавливается новое значение, которое фактически удаляет (перезаписывает) старое. И новое значение отображается в консоли.

Рассмотрим другой пример. Пусть имеется массив целых чисел размерностью 5. Необходимо сдвинуть все его значения на одну позицию вправо, а затем отобразить результат.

Для решения этой задачи запишем следующий код:


int[] nums = {0, 1, 2, 3, 4};

for(int i = nums.length - 1; i > 0; i--) {
    nums[i] = nums[i - 1];
}

for(int num : nums) {
    System.out.print(num);
}

В консоли отобразятся следующие значения: 123. Число 4 было удалено значением 3, которое в цикле переместилось на его место. В этом примере все значения цикла поменяли свои позиции — сдвинулись вправо на одну ячейку.

8. Скорость работы массива

Чтобы понять, насколько массив является быстрой (но не всегда) структурой данных, необходимо определиться, хотя бы вкратце, с теоретической частью вычисления этой скорости. Для этого необходимо сказать пару слов про сложность алгоритмов (Big O Notation).

Big O Notation можно перевести как О большое. Это способ (из теории алгоритмов) обозначения сложности алгоритма.

Любой алгоритм характеризуется двумя параметрами: временем выполнения (Time Complexity) и расходом памяти (Space Complexity). Например, чем длиннее массив, тем больше нужно памяти и времени на его заполнение.

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

Например, Time Complexity для поиска числа в массиве будет обозначаться, как O(n), где n — это число ячеек в массиве. Чем их больше, тем дольше работает алгоритм (выполняется большее количество операций (итераций массива), где n — их максимальное число). Т. к. поиск происходит линейно, то ячейки перебираются одна за другой по порядку. Соответственно, такой алгоритм называется линейным.

Элементы массива в памяти размещаются в едином блоке. Это сделано для более эффективного и быстрого доступа к ним.

Если индекс ячейки известен, то алгоритм имеет константное время (постоянное, не зависящее ни от чего) и обозначается O(1), т. е. доступ к ячейкам массива происходит мгновенно и не зависит от его размера.

Если массив отсортирован по возрастанию и для поиска значений используется алгоритм под названием двоичный поиск (1, 2), то количество операций, необходимых алгоритму для поиска числа будет O(log(n)).

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

А дорого ли вычислять каждый раз длину массива?

Как мы выяснили, длина массива — это фиксированное значение, которое создается в момент создания массива и хранится в заголовке массива. JVM знает, что это значение никогда не изменится, а, значит, оно никогда не вычисляется, а просто берется из заголовка. Этот тип операции чтения очень быстрый и выполняется за O(1), т. е. за константное время.

Оцените статью, если она вам понравилась!

Добавить комментарий