본문 바로가기

Programing/JVM(Java, Kotlin)

[Java] 배열 in 자바

자바에서는 배열이 객체이다.

이것은 자바 언어 명세에 적혀있다. JLS 4.3.1

An object is a class instance or an array.
오브젝트는 클래스의 인스턴스이거나 배열이다.

C/C++ 의 배열

즉 C/C++의 배열과 달리 자바의 배열은 객체라는 큰 차이가 생긴다.

C언어에서는 sizeof 라는 명령으로 자료구조의 크기를 구할 수 있다.

#include <stdio.h>

int main(int argc, const char * argv[]) {
    int num = 1;
    int arr[2] = { 1, 2 };
    
    printf("%lu\n", sizeof(num));
    printf("%lu\n", sizeof(arr));
    
    return 0;
}

C언어의 데이터 타입의 크기는 플랫폼(시스템)에 따라 다를 수 있는데 C표준에서 이야기 하고 있는 수준은 아래와 같다.

sizeof(int) <= sizeof(long int) <= sizeof(long long int)

내가 수행했을 때 4와 8이 콘솔에 출력이 되었다.

앞에 찍힌 4라는 값은 시스템에 따라 바뀔 수 있지만 뒤에 출력된 값이 2배가 된다라는 사실은 동일하다.

왜냐하면 배열이란 동일한 타입을 두 개를 묶은 개념은 바뀌지 않기 때문이다.

자바의 배열

위에 언급했듯이 자바에서 배열은 객체이다.

자바에서 객체를 만들 때 처럼 new 라는 연산자를 이용한다.

public class SingleArrayInt {
    public static void main(String[] args) {
        int[] array = new int[2];
        if (array instanceof Object) {
            System.out.println("Yes!");
        }
}

위의 코드는 int 타입의 배열을 생성해서 Object 타입인지 확인하고 있다.

명세와 마찬가지로 array 변수의 타입은 객체이므로 Yes! 라는 출력이 된다.

바이트코드 관점

바이트 코드 관점에서는 배열 관련해서는 크게 3가지의 opcode가 있다.

자바에서는 new로 동일하게 만들지만 문맥에 따라서 아래 3가지로 바뀌게 된다.

opcode (hexa value) operand(s) 설명
NEWARRAY (0xBC) atype operand stack에서 길이를 꺼내서(pop) atype이 나타내는 primitive 타입의 새로운 배열을 할당한다. 새로운 배열은 objectref를 operand stack에 넣는다.(push)
ANEWARRAY (0xBD) indexbyte1, indexbyte2 위와 동일하지만 클래스의 객체에 대해 수행하는 것이 다르다.
MULTIANEWARRAY (0xC5) indexbyte1, indexbyte2, dimensions 다차원배열을 만들 때 사용한다. operand stack에서는 각 차원의 길이를 획득하고 operand들에는 만들 타입과 크기를 이용한다.

NEWARRAY

int[] array = new int[2];

위의 자바코드는 아래의 바이트코드로 바뀐다. (상수방식이나 지역변수 번호는 자바 컴파일러에 따라 문맥에 따라 바뀔 수 있다.)

0x05, 0xBC, 0x0A, 0x4C

이 바이트코드는 사람이 쉽게 이해를 하기 어려우므로 기호로 치환하면 아래와 같다.

hexa value INSTRUCTION SET 설명 참고
0x05 ICONST_2 상수 2를 operand stack에 push한다. -1: iconst_m1 = 2
0: iconst_0 = 3
1 : iconst_1 = 4
2: iconst_2 = 5
3: iconst_3 = 6
4: iconst_4 = 7
5: iconst_5 = 8
6 ~ 127: bipush + byte ~ = 16 (0x10)
128 ~ 32767: sipush + byte1 + byte2 ~ = 17 (0x11)
~ 2147483647 : 
ldc + index = 18 (0x12)
0xBC, 0x0A NEWARRAY T_INT 현재 operand stack에 있는 값(2)을 pop해서 int 타입의 배열을 생성하여 operand stack에 push한다. 배열 타입 코드들

T_BOOLEAN = 4
T_CHAR = 5
T_FLOAT = 6
T_DOUBLE = 7
T_BYTE = 8 (0x8)
T_SHORT = 9 (0x9)
T_INT = 10 (0xA)
T_LONG = 11 (0xB)


 

0x4C ASTORE 1 현재 operand stack에 있는 레퍼런스를 pop해서 local variable 1번에 store한다. astore = 58 (0x3A)
astore_0 = 75 (0x4B)
astore_1 = 76 (0x4C)
astore_2 = 77 (0x4D)
astore_3 = 78 (0x4E)

 

 

ANEWARRAY

Object[] object = new Object[6];

위의 자바코드는 아래의 바이트코드로 바뀐다. (상수방식이나 지역변수 번호는 자바 컴파일러에 따라 문맥에 따라 바뀔 수 있다.)

0x10, 0x06, 0xBD, 0x00, 0x02, 0x4C

풀어쓰면 아래와 같다.

hexa value INSTRUCTION SET
0x10, 0x06 BIPUSH 6
0xBD, 0x00, 0x02 ANEWARRAY java/lang/Object
0x4C ASTORE 1


MULTIANEWARRAY

int[][] multipleArray = new int[2][3];

위의 자바코드는 아래의 바이트코드로 바뀐다. (상수방식이나 지역변수 번호는 자바 컴파일러에 따라 문맥에 따라 바뀔 수 있다.)

0x05, 0x06, 0xC5, 0x00, 0x02, 0x02, 0x4C

풀어쓰면 아래와 같다.

hexa value INSTRUCTION SET 참고
0x05 ICONST_2  
0x06 ICONST_3  
0xC5, 0x00, 0x02, 0x02 MULTIANEWARRAY [[I 2 B: byte
C: char
D: double
F: float
I: int
J: long
L ClassName ;: reference
S: short
Z: boolean
[: reference
eg) doube[][][] => [[[D
0x4C ASTORE 1  

 

www.baeldung.com/java-size-of-object