객체와 배열

Under The Hood 의 다른 버전에 오신 것을 환영합니다 . 이 칼럼은 Java의 기본 기술에 중점을 둡니다. 개발자에게 Java 프로그램을 실행하는 메커니즘을 엿볼 수 있도록하는 것이 목표입니다. 이번 달 기사에서는 객체와 배열을 다루는 바이트 코드를 살펴 봅니다.

객체 지향 기계

JVM (Java Virtual Machine)은 객체, 객체 참조 및 기본 유형의 세 가지 형태로 데이터와 함께 작동합니다. 개체는 가비지 수집 된 힙에 있습니다. 객체 참조 및 기본 유형은 로컬 변수로 Java 스택에, 객체의 인스턴스 변수로 힙에 또는 클래스 변수로 메서드 영역에 있습니다.

Java 가상 머신에서 메모리는 가비지 수집 된 힙에 객체로만 할당됩니다. 객체의 일부를 제외하고는 힙의 기본 유형에 대한 메모리를 할당 할 수있는 방법이 없습니다. Object참조가 필요한 기본 유형을 사용 하려면 java.lang패키지 에서 유형에 대한 래퍼 객체를 할당 할 수 있습니다 . 예를 들어, 유형을 객체로 Integer감싸는 클래스가 int있습니다. 객체 참조 및 기본 유형 만 Java 스택에 로컬 변수로 상주 할 수 있습니다. 객체는 Java 스택에 상주 할 수 없습니다.

JVM에서 객체와 기본 유형의 구조적 분리는 객체를 지역 변수로 선언 할 수없는 Java 프로그래밍 언어에 반영됩니다. 객체 참조 만 그렇게 선언 할 수 있습니다. 선언시 객체 참조는 아무것도 참조하지 않습니다. 참조가 기존 객체에 대한 참조 또는 호출을 통해 명시 적으로 초기화 된 후에 만 ​​참조가 new실제 객체를 참조합니다.

JVM 명령어 세트에서 모든 객체는 배열을 제외하고 동일한 opcode 세트로 인스턴스화되고 액세스됩니다. Java에서 배열은 본격적인 객체이며 Java 프로그램의 다른 객체와 마찬가지로 동적으로 생성됩니다. 배열 참조는 유형에 대한 참조 Object가 호출 되는 모든 곳에서 사용할 수 있으며 배열에서의 모든 메서드를 Object호출 할 수 있습니다. 그러나 Java 가상 머신에서 어레이는 특수 바이트 코드로 처리됩니다.

다른 객체와 마찬가지로 배열은 지역 변수로 선언 할 수 없습니다. 배열 참조 만 가능합니다. 배열 객체 자체에는 항상 기본 유형의 배열이나 객체 참조의 배열이 포함됩니다. 객체 배열을 선언하면 객체 참조 배열이 생성됩니다. 객체 자체는 명시 적으로 생성되고 new배열 요소에 할당되어야합니다.

객체에 대한 Opcode

새 개체의 인스턴스화는

new

opcode. 두 개의 1 바이트 피연산자가

new

opcode. 이 두 바이트가 결합되어 상수 풀에 16 비트 인덱스를 형성합니다. 지정된 오프셋의 상수 풀 요소는 새 개체의 클래스에 대한 정보를 제공합니다. JVM은 다음과 같이 힙에 객체의 새 인스턴스를 만들고 새 객체에 대한 참조를 스택에 푸시합니다.

개체 생성
Opcode 피연산자 기술
new indexbyte1, indexbyte2 힙에 새 개체를 만들고 참조를 푸시합니다.

다음 표는 객체 필드를 넣고 가져 오는 opcode를 보여줍니다. 이러한 opcode, putfield 및 getfield는 인스턴스 변수 인 필드에서만 작동합니다. 정적 변수는 나중에 설명하는 putstatic 및 getstatic에 의해 액세스됩니다. putfield 및 getfield 명령어는 각각 2 개의 1 바이트 피연산자를 사용합니다. 피연산자는 결합되어 상수 풀에 16 비트 인덱스를 형성합니다. 해당 인덱스의 상수 풀 항목에는 필드의 유형, 크기 및 오프셋에 대한 정보가 포함됩니다. 객체 참조는 putfield 및 getfield 명령어의 스택에서 가져옵니다. putfield 명령어는 스택에서 인스턴스 변수 값을 가져오고 getfield 명령어는 검색된 인스턴스 변수 값을 스택에 푸시합니다.

인스턴스 변수에 액세스
Opcode 피연산자 기술
putfield indexbyte1, indexbyte2 객체의 인덱스로 표시된 필드를 값으로 설정 (둘 다 스택에서 가져옴)
getfield indexbyte1, indexbyte2 객체 (스택에서 가져옴)의 인덱스로 표시된 필드를 푸시합니다.

클래스 변수는 아래 표와 같이 getstatic 및 putstatic opcode를 통해 액세스됩니다. getstatic과 putstatic은 둘 다 2 개의 1 바이트 피연산자를 취하며, 이는 JVM에 의해 결합되어 16 비트 부호없는 오프셋을 상수 풀로 형성합니다. 해당 위치의 상수 풀 항목은 클래스의 하나의 정적 필드에 대한 정보를 제공합니다. 정적 필드와 관련된 특정 객체가 없기 때문에 getstatic 또는 putstatic에서 사용하는 객체 참조가 없습니다. putstatic 명령어는 스택에서 할당 할 값을받습니다. getstatic 명령어는 검색된 값을 스택으로 푸시합니다.

클래스 변수에 액세스
Opcode 피연산자 기술
putstatic indexbyte1, indexbyte2 객체의 인덱스로 표시된 필드를 값으로 설정 (둘 다 스택에서 가져옴)
getstatic indexbyte1, indexbyte2 객체 (스택에서 가져옴)의 인덱스로 표시된 필드를 푸시합니다.

다음 opcode는 스택 맨 위에있는 개체 참조가 opcode 다음의 피연산자에 의해 인덱싱 된 클래스 또는 인터페이스의 인스턴스를 참조하는지 확인합니다. 체크 캐스트 명령 CheckCastException은 객체가 지정된 클래스 또는 인터페이스의 인스턴스가 아닌 경우 발생합니다. 그렇지 않으면 checkcast는 아무것도하지 않습니다. 객체 참조는 스택에 남아 있으며 다음 명령어에서 실행이 계속됩니다. 이 명령은 캐스트가 런타임에 안전한지 확인하고 JVM 보안 블랭킷의 일부를 형성합니다.

instanceof 명령어는 스택 맨 위에서 객체 참조를 팝하고 true 또는 false를 푸시합니다. 객체가 실제로 지정된 클래스 또는 인터페이스의 인스턴스이면 true가 스택에 푸시되고, 그렇지 않으면 false가 스택에 푸시됩니다. instanceof 명령어는 instanceof프로그래머가 객체가 특정 클래스 또는 인터페이스의 인스턴스인지 테스트 할 수있는 Java 키워드 를 구현하는 데 사용됩니다 .

유형 검사
Opcode 피연산자 기술
checkcast indexbyte1, indexbyte2 스택의 objectref를 인덱스의 클래스로 캐스트 할 수없는 경우 ClassCastException 발생
instanceof indexbyte1, indexbyte2 스택의 objectref가 인덱스의 instanceof 클래스이면 true를 푸시하고, 그렇지 않으면 false를 푸시합니다.

어레 이용 Opcode

새로운 어레이의 인스턴스화는 newarray, anewarray 및 multianewarray opcode를 통해 수행됩니다. newarray opcode는 객체 참조가 아닌 기본 유형의 배열을 만드는 데 사용됩니다. 특정 기본 유형은 newarray opcode 다음에 오는 단일 1 바이트 피연산자로 지정됩니다. newarray 명령어는 byte, short, char, int, long, float, double 또는 boolean에 대한 배열을 만들 수 있습니다.

anewarray 명령어는 객체 참조 배열을 만듭니다. 두 개의 1 바이트 피연산자는 anewarray opcode를 따르며 결합되어 상수 풀에 16 비트 인덱스를 형성합니다. 배열이 생성 될 객체의 클래스에 대한 설명은 지정된 인덱스의 상수 풀에서 찾을 수 있습니다. 이 명령어는 개체 참조 배열에 공간을 할당하고 참조를 null로 초기화합니다.

multianewarray 명령어는 단순히 배열의 배열 인 다차원 배열을 할당하는 데 사용되며 anewarray 및 newarray 명령어를 반복적으로 사용하여 할당 할 수 있습니다. multianewarray 명령어는 단순히 다차원 배열을 만드는 데 필요한 바이트 코드를 하나의 명령어로 압축합니다. 2 개의 1 바이트 피연산자는 multianewarray opcode를 따르며 결합되어 상수 풀에 16 비트 인덱스를 형성합니다. 배열이 생성 될 객체의 클래스에 대한 설명은 지정된 인덱스의 상수 풀에서 찾을 수 있습니다. 상수 풀 인덱스를 형성하는 두 개의 1 바이트 피연산자 바로 뒤에는이 다차원 배열의 차원 수를 지정하는 1 바이트 피연산자가 있습니다. 각 차원의 크기가 스택에서 튀어 나옵니다.이 명령어는 다차원 배열을 구현하는 데 필요한 모든 배열에 공간을 할당합니다.

새 어레이 생성
Opcode 피연산자 기술
newarray 유형 길이를 팝하고, 유형이 나타내는 유형의 기본 유형의 새 배열을 할당하고, 새 배열의 objectref를 푸시합니다.
anewarray indexbyte1, indexbyte2 pops 길이, indexbyte1 및 indexbyte2로 표시된 클래스 객체의 새 배열을 할당하고 새 배열의 objectref를 푸시합니다.
multianewarray indexbyte1, indexbyte2, 차원 배열 길이의 차원 수를 팝하고 indexbyte1 및 indexbyte2로 표시된 클래스의 새로운 다차원 배열을 할당하고 새 배열의 objectref를 푸시합니다.

다음 표는 스택 맨 위에서 배열 참조를 팝하고 해당 배열의 길이를 밀어내는 명령어를 보여줍니다.

어레이 길이 얻기
Opcode 피연산자 기술
arraylength (없음) 배열의 objectref를 팝하고 해당 배열의 길이를 푸시합니다.

The following opcodes retrieve an element from an array. The array index and array reference are popped from the stack, and the value at the specified index of the specified array is pushed back onto the stack.

Retrieving an array element
Opcode Operand(s) Description
baload (none) pops index and arrayref of an array of bytes, pushes arrayref[index]
caload (none) pops index and arrayref of an array of chars, pushes arrayref[index]
saload (none) pops index and arrayref of an array of shorts, pushes arrayref[index]
iaload (none) pops index and arrayref of an array of ints, pushes arrayref[index]
laload (none) pops index and arrayref of an array of longs, pushes arrayref[index]
faload (none) pops index and arrayref of an array of floats, pushes arrayref[index]
daload (none) pops index and arrayref of an array of doubles, pushes arrayref[index]
aaload (none) pops index and arrayref of an array of objectrefs, pushes arrayref[index]

The next table shows the opcodes that store a value into an array element. The value, index, and array reference are popped from the top of the stack.

Storing to an array element
Opcode Operand(s) Description
bastore (none) pops value, index, and arrayref of an array of bytes, assigns arrayref[index] = value
castore (none) pops value, index, and arrayref of an array of chars, assigns arrayref[index] = value
sastore (none) pops value, index, and arrayref of an array of shorts, assigns arrayref[index] = value
iastore (none) pops value, index, and arrayref of an array of ints, assigns arrayref[index] = value
lastore (none) pops value, index, and arrayref of an array of longs, assigns arrayref[index] = value
fastore (none) pops value, index, and arrayref of an array of floats, assigns arrayref[index] = value
dastore (none) pops value, index, and arrayref of an array of doubles, assigns arrayref[index] = value
aastore (none) objectrefs 배열의 값, 인덱스 및 arrayref를 팝하고 arrayref [index] = value를 할당합니다.

3 차원 배열 : Java 가상 머신 시뮬레이션

아래 애플릿은 일련의 바이트 코드를 실행하는 Java 가상 머신을 보여줍니다. 시뮬레이션의 바이트 코드 시퀀스는 아래 표시된 클래스 javacinitAnArray()메서드 에 대해 생성되었습니다 .

class ArrayDemo {static void initAnArray () {int [] [] [] threeD = new int [5] [4] [3]; for (int i = 0; i <5; ++ i) {for (int j = 0; j <4; ++ j) {for (int k = 0; k <3; ++ k) {threeD [ i] [j] [k] = i + j + k; }}}}}

javacfor initAnArray()에 의해 생성 된 바이트 코드 는 다음과 같습니다.