자바 배열, 자바 배열이란, java array, java 배열, 자바 배열 선언, 자바 배열 크기 미지정, 자바 배열 크기, 깊은복사, 얕은복사, 자바 배열 복사
자바 배열이란 (Java Array)
배열(Array)은 각 값에 대해 별도의 변수를 선언하는 대신 여러 값을 하나의 변수에 저장하는 데 사용됩니다.
배열을 선언하려면 대괄호로 변수 유형을 정의합니다.
배열은 연관된 데이터를 저장하기 위한 변수의 선언을 줄여주며, 반복문 등을 이용하여 계산과 같은 과정을 쉽게 처리할 수 있습니다.
배열은 고정된 갯수의 데이터를 저장하는데 사용되는 자료구조이며, 배열의 길이는 배열이 생성될때 설정이 됩니다.
배열의 각 항목을 요소라고 하며, 각 요소는 숫자 인덱스에 의해 접근을 할 수 있습니다.
맨 첫번째 요소는 0부터 시작하게 됩니다.
아래 예시는 int a[] = new int[10]; 에 대한 예시 그림입니다.
추가적인 자바 배열에 대한 사용예제는 다음과 같습니다.
// 아래와 같이 변수를 여러개 쓰는 대신...
int a = 1, int a2 = 2, int a3 = 3,...
// 배열을 쓰면 아래와 같이 a변수 하나에 여러개의 값을 저장할 수 있습니다!
int[] a = {1, 2, 3};
자바 배열 선언, 자바 배열 크기 미지정 선언
자바 배열 선언 방식에는 여러 방법이 있습니다.
바로 아래와 같은 코드 예제를 살펴보겠습니다.
// 자료형[] 변수명 = {데이터1, 데이터2, 데이터3,...} 과 같이 사용할 수 있습니다.
// 단, {}는 변수선언과 동시에 쓰여져야 합니다.
int[] a = {1, 2, 3};
// 선언을 먼저하고, 나중에 {}로 여러 값을 넣는것은 불가능합니다.
int[] a;
a = {1, 2, 3};//Array constants can only be used in initializers 에러 발생
// 선언을 먼저하고, 나중에 값을 지정해주고 싶을때에는 아래와 같이 배열의 크기를 지정해주고, 나중에 값을 수정해주어야 합니다.
int[] a = new int[3];
a[0] = 1;
a[1] = 2;
자바 배열 요소 접근하기
자바 배열에서 각각의 요소를 접근하는 방법은 위에서 이미 설명하였듯이,
변수명[인덱스] 로 접근할 수 있습니다.
단, 여기서 주의해야할 점은 인덱스는 0부터 시작한다는 점입니다.
int[] a= {1, 2, 3};
// 출력결과 : 2가 출력됨.
System.out.println(a[1]);
자바 배열 요소 수정하기
변수명[인덱스] 로 접근하여, 해당 하는 요소에 값을 대입해주면 됩니다.
int[] a= {1, 2, 3};
a[2] = 4;
// 출력결과 : 4가 출력됨.
System.out.println(a[2]);
자바 배열 모든 요소 출력하기
배열의 모든 요소 출력하는 방법은 아래와 같습니다.
int[] a= {1, 2, 3};
for(int t : a){ // for(자료형 임시변수: 배열변수명)
System.out.println(t);
}
//물론 일반적인 for문을 써서 아래와 같이도 사용할 수 있습니다.
for(int i=0;i<3;i++){
System.out.println(a[i]);
}
자바 배열 크기 확인하기
자바 배열크기는 아래와 같이 length 변수를 사용하면 됩니다.
자바에서 배열(array)을 사용하면 어떠한 변수더라도 해당 변수가 자동으로 생기기에 쉽게 사용할 수 있습니다.
int[] a= {1, 2, 3};
System.out.println(a.length); //결과값 : 3
자바 배열 복사하기
자바 배열을 복사하기 위해 아래 메소드를 사용할 수 있습니다.
System.arraycopy(src, srcPos, dest, destPos, length);
해당 메소드는 지정된 위치에서 시작하여 지정된 소스 배열에서 대상 배열의 지정된 위치로 배열을 복사하는 메소드입니다.
복사된 요소 수는 길이 인수값과 동일합니다.
예시코드는 아래와 같습니다.
int[] a = {1, 2, 3}, b = new int[3];
System.arraycopy(a, 0, b, 0, 3);
또 다른 방식으로는 아래와 같은 방식으로도 가능합니다.
바로 for loop를 돌면서 일일이 하니씩 값을 복사해주는것이지요.
for(int i=0;i<a.length;i++){
b[i] = a[i];
}
하지만 System.arrayCopy 방식을 쓰는게 성능상 이점이 있습니다.
arraycopy의 메소드 선언부를 보면 다음과 같이 되어 있습니다.
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
특이하게 native라는 키워드가 보이는데요, 이는 Java가 아닌 C 등의 언어들로 작성된 라이브러리들을 호출하는 메소드로,
자바보다 더 성능이 좋은 방식으로 array를 copy해줍니다.
내부적인 코드는 메모리를 한번에 복사해주는 방식이므로, 배열의 길이에 따라 반복문을 도는것보다는 훨씬 성능이 좋은 방법입니다.
자바 배열 복사하기 - 오브젝트 배열 복사
reference형 자료 (object)를 갖고 있는 배열의 경우에는 유의해야할 사항이 있습니다.
아래와 같은 코드를 실행해보겠습니다.
// 클래스 선언
public class TestClass {
public int id;
public String name;
public TestClass(int id, String name) {
this.id = id;
this.name = name;
}
}
//테스트코드
public class Main {
public static void main(String[] args) {
TestClass a = new TestClass(1, "test1");
TestClass b = new TestClass(2, "test2");
TestClass[] arr = {a, b};
TestClass[] targetArr = new TestClass[2];
System.arraycopy(arr, 0, targetArr, 0, arr.length);
targetArr[0].id = 3;
System.out.println(arr[0].id);
}
}
// 결과는 3이 출력됩니다.
테스트 코드의 내용은 arr의 내용을 targetArr로 복사하고,
targetArr[0]을 바꾼 뒤에,
arr[0]의 데이터를 확인하는 코드입니다.
내가 바꾼것은 targetArr[0]을 바꾸었지만, arr[0]의 값이 바뀌어져있습니다.
왜그럴까요? 이는, arr에 저장된 값은 a, b가 아닌 a, b의 주소값이 저장이 되며,
arraycopy를 사용하여 targetArr로 복사를 하는것은 주소값을 그대로 복사하는것이기 때문입니다.
주소값을 확인하기 위해, 아래와 같이 targetArr[0], arr[0] 값을 추가하여 아래와 같이 코드를 작성해보겠습니다.
public class Main {
public static void main(String[] args) {
TestClass a = new TestClass(1, "test1");
TestClass b = new TestClass(2, "test2");
TestClass[] arr = {a, b};
TestClass[] targetArr = new TestClass[2];
System.arraycopy(arr, 0, targetArr, 0, arr.length);
targetArr[0].id = 3;
System.out.println(arr[0].id);
System.out.println(targetArr[0]);
System.out.println(arr[0]);
System.out.println(targetArr[1]);
System.out.println(arr[1]);
}
}
그러면 결과값을 아래와 같이 나오게 됩니다.
3
TestClass@2a139a55
TestClass@2a139a55
TestClass@15db9742
TestClass@15db9742
여기서 2a139a55과 15db9742가 주소값이라 볼 수 있습니다.
그림으로 도식화 해보면 다음과 같습니다.
그렇다면 객체를 완전히 복사하여, 복사된 객체를 변경하여도 원본객체가 변경되지 않도록 하려면 어떻게 해야할까요?
바로 객체를 일일이 생성하고 각 객체에 저장되어있는 값을 복사해주어야 합니다.
코드로 작성하면 아래와 같은 방식이 되겠습니다.
public class Main {
public static void main(String[] args) {
TestClass a = new TestClass(1, "test1");
TestClass b = new TestClass(2, "test2");
TestClass[] arr = {a, b};
TestClass[] targetArr = new TestClass[2];
for(int i=0;i<arr.length;i++) {
TestClass tmp = new TestClass(arr[i].id, arr[i].name);
targetArr[i] = tmp;
}
// 이제 복사된 객체에서 값을 바꿔도 원본 객체의 필드는 변경되지 않스니다.
targetArr[0].id = 3;
System.out.println(arr[0].id);
// 이제 targetArr과 arr이 가리키는 객체 주소값은 서로 다르게 표시됩니다.
System.out.println(targetArr[0]);
System.out.println(arr[0]);
System.out.println(targetArr[1]);
System.out.println(arr[1]);
}
}
제가 실행한 환경에서는 이 코드의 실행한 결과는 아래와 같이 나왔습니다.
복사된 객체에서 값을 바꿔도 원본객체의 필드값은 바뀌지 않았으며,
객체의 주소값은 서로 다르게 표시되었습니다.
1
TestClass@2a139a55
TestClass@15db9742
TestClass@6d06d69c
TestClass@7852e922
이를 깊은 복사(Deep copy) 라고 하며,
앞서 주소만 복사된 것을 얕은 복사(shallow copy)라고도 표현합니다.
자바에서는 이를 유의해서 값 복사를 잘해야 겠습니다.
얼핏보면 당연하게 보이지만, 규모가 큰 프로젝트에서는 종종 헷갈려서 큰 문제를 야기하기도 합니다.
이 개념은 java에서 뿐만이 아니라 다른 여러 언어에서도 확인되는 개념이기에, 평소에도 잘 유의하여 개발할 필요가 있겠습니다.
총평
자바 배열에 대해 간단히 알아보았는데,
자료를 찾아보니 자바 배열만 해도 다뤄야할 주제는 무궁무진한것 같습니다.
다음에 기회가 되면 배열 관련된 이것저것에 대해 추가적으로 다뤄보겠습니다.
자바 배열, 자바 배열이란, java array, java 배열, 자바 배열 선언, 자바 배열 크기 미지정, 자바 배열 크기, 깊은복사, 얕은복사
#자바,#배열,#크기,#미지정,#복사,#깊은복사,#얕은복사,#java,#array,#size,#shallow,#shallowcopy,#deepcopy,#deep,#copy
댓글