프로그래밍/java

[자바JAVA] 다차원 배열 (2차원 배열) & 얇은복사와 깊은복사

pupu91 2022. 7. 7. 16:15
반응형

2차원 배열

자료형이 같은 1차원 배열들의 묶음

2차원 배열은 할당 된 공간 마다 인덱스 번호 두개 부여 (앞 번호는 , 뒷 번호는 )

 

 

 

 

 


 

 

 

   2차원 배열 선언과 할당

 

배열 선언  배열 할당 배열의 선언과 할당


자료형[][] 배열명;
자료형 배열명[][];
자료형[]배열명[];


자료형[][]배열명 = new 자료형[행크기][열크기] 자료형[][] 배열명 = new 자료형[행크기][열크기]
자료형 배열명[][]; = new 자료형[행크기][열크기]
자료형[]배열명[]; = new 자료형[행크기][열크기]

 

 

 

 2차원 배열의 저장구조

 

 

 


2차원 배열의 사용 방법

 


 

 

1 .  배열의 주소를 보관할 레퍼런스 변수 선언(stack)

int[][] iarr1;
int iarr2[][];
int[] iarr3[];

 

 

 

 

 

 

2. 여러 개의 1차원 배열의 주소를 관리하는 배열을 생성(heap)

 

배열의 주소를 관리하는 배열의 길이는 앞 부분에 
정수형으로 표기하며 반드시 크기를 지정해줘야 한다.
iarr1 = new int[3][];

(x)iarr1 = new int[][]; 크기를 지정하지 않으면 에러 발생함
(x)iarr1 = new int[][4]; 주소를 묶어서 관리할 배열의 크기를 지정하지 않으면 에러 발생함

 

 

 

 

 

3. 주소를 관리하는 배열의 인덱스마다 배열을 할당(heep)

iarr1[0] = new int[5];
iarr1[1] = new int[5];
iarr1[2] = new int[5];
위에서 진행한 2,3번을 동시에 진행할 수도 있다. 앞 부분 정수는 주소를 관리하는 배열의 크기, 뒷 부분 정수는 각 인덱스에 할당하는 배열의 길이이다.  관리하는 여러개의 배열의 길이가 동일한 경우 아래와 같이 한 번에 할당할 수도 있다.
하지만 여러 개의 배열의 길이가 각각 다른 경우에는 위에서 했던 방식처럼 인덱스별로 배열을 따로 할당해 주어야 한다.
서로 같은 길이의 여러 개 배열을 하나로 묶어 관리하는 2차원 배열을 "정변 배열"이라고 하며, 서로 길이가 같지 않은 여러 개의 배열을 하나로 묶어 관리하는 2차원 배열을 "가변 배열"이라고 한다.

 

 

 

 

 

 

4. 각 배열의 인덱스에 차례로 접근해서 값 출력

 

(1) 배열 하나씩 접근해서 출력하기

0번 인덱스의 배열 값 출력   
for(int i = 0; i < iarr1[0].length; i++) {
	System.out.print(iarr1[0][i] + " ");
}
1번 인덱스의 배열 값 출력
for(int i = 0; i < iarr1[1].length; i++) {
	System.out.print(iarr1[1][i] + " ");
}

2번 인덱스의 배열 값 출력 */
for(int i = 0; i < iarr1[2].length; i++) {
	System.out.print(iarr1[2][i] + " ");
}

(2) 중첩 for문을 이용해서 배열의 값 출력 */
for(int i = 0; i < iarr1.length; i++) {
	for(int j = 0; j < iarr1[i].length; j++) {
		System.out.print(iarr1[i][j] + " ");
}
◇ 실행 결과
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0 
0 0 0 0 0

 

 

 

 

 

 

5 . 선언과 동시에 모든 배열을 할당 후 출력하는 방법

 

(1) 선언과 동시에 배열 할당
int[][] iarr = new int[3][5];

(2) 각 배열의 인덱스에 접근해서 값 대입 후 출력
↓ 배열에 저장하기 위해 하나씩 증가하는 값을 저장할 변수만들기
int value = 1; 
↓ 배열의 갯수만큼 반복적으로 접근하기 위한 용도의 반복문 작성
for(int i = 0; i < iarr.length; i++){
	for(int j = 0; j < iarr.length; j++){
    	iarr[i][j] = value++;
        ↑ 하나의 배열이 0번부터 마지막 인덱스까지 차례로 접근해서
        값을 대입하는 용도의 반복문 작성
        }

(3) 값 출력
for(int i = 0; i < iarr.length; i++){
	for(int j = 0; j < iarr.[i].length; j++){
        System.out.print(iarr[i][j] + " ");
        }
        System.out.println();
     }

◇ 실행 결과
1 2 3 4 5 
6 7 8 9 10 
11 12 13 14 15

 

 

 

 

 

 

6. 가변 배열의 선언 및 할당하고 출력하기

  • 가변 배열의 선언과 동시에 모든 배열을 할당할 배열의 갯수만 지정하고 각 인덱스에 서로 다른 길이의 배열을 따로 할당해야 한다. 
  • 자료형[ ][ ] 변수명 =  new 자료형[할당할 배열의 갯수] [ ] ;
  • 변수명[ 배열 인덱스] = new 자료형[ 배열의 길이];
(1) 주소를 관리하는 배열의 주소를 보관하기 위한 변수 선언
int[][] iarr = new int[3][];

(2) 주소를 관리하는 배열의 각 인덱스마다 배열을 할당하여 주소값 대입
iarr[0] = new int[3];
iarr[1] = new int[2];
iarr[2] = new int[5];

(3) 각 배열의 인덱스마다 접근하여 값 대입 
iarr[0][0] = 1;
iarr[0][1] = 2;
iarr[0][2] = 3;
iarr[1][0] = 4;
iarr[1][1] = 5;
iarr[2][0] = 6;	
iarr[2][1] = 7;
iarr[2][2] = 8;
iarr[2][3] = 9;
iarr[2][4] = 10;

(4) 가변 배열 역시 반목문을 이용해서 값을 대입하고 출력할 수 있음.
for(int i = 0; i < iarr.lenght; i++){
	for(int j = 0; j < iarr[i].length; j++){
    	System.out.print(iarr[i][j] + " ");
        }
      Sustem.out.println();
    }

◇실행 결과
1 2 3 
4 5 
6 7 8 9 10

 

 

 

 

 

 

7. 선언과 할당을 하며 초기화하는 방법

(1) 정변 배열
int[][] iarr = {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15}};

(2) 가변 배열
int[][] iarr2 = {{1, 2, 3}, {4, 5}, {6, 7, 8, 9, 10}};

(3) 미리 할당한 배열을 이용한 방식
int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = {6, 7, 8, 9, 10};
		
int[][] arr3 = {arr1, arr2};

 

 

반응형

배열 복사

 

 


 

1. 얇은 복사(shallow copy)

 

  • 객체 stack의 주소값만 복사한다.(하나의 객체를 두 변수가 참조하는 것)
  • 얇은 복사는 주로 메소드 호출 시 인자로 사용하는 경우와 리턴 값을 동일한 배열을 리턴해주고 싶은 경우에 활용한다.

 

 

  • 두 개의 레퍼런스 변수의 주소값이 동일한지 확인해보기.
(1) 얕은 복사를 확인할 원본 배열 생성하기
	int[] originArr = {1, 2, 3, 4, 5};
		
(2) 원본 배열을 복사 배열에 복사
	int[] copyArr = originArr;
=> originArr에 저장 된 배열의 주소를 copyArr에도 저장
		
(3) hashCode를 출력하여 두 개의 레퍼런스 변수의 주소확인하기
	System.out.println(originArr.hashCode());
	System.out.println(copyArr.hashCode());

◇실행 결과
originArr 주소값 : 1651191114
copyArr 주소값 : 1651191114
=> 두 개의 레퍼런스 변수는 동일한 주소를 갖고 있는 것을 확인할 수 있다.

 

 

  • 원본 배열과 복사본 배열의 값을 출력하여 비교해보기
(4) originArr과 copyArr 배열의 값 출력

for(int i = 0; i < originArr.length; i++) {
	System.out.print(originArr[i] + " ");
    }
    
for(int i = 0; i < copyArr.length; i++) {
			System.out.print(copyArr[i] + " ");
		}
        
◇실행 결과
1 2 3 4 5 
1 2 3 4 5

 

 

  • 복사본 배열을 통해 값 변경 후 출력해보기
copyArr[0] = 99;
		
for(int i = 0; i < originArr.length; i++) {
	System.out.print(originArr[i] + " ");
}
			
for(int i = 0; i < copyArr.length; i++) {
	System.out.print(copyArr[i] + " ");
}
◇ 실행 결과
99 2 3 4 5 
99 2 3 4 5
=> 서로 같은 배열을 가리키고 있기 때문에
  복사본 배열만 변경해도 원본 배열에 영향을 미침을 알 수 있다.

 

 

 


 

 

2. 깊은 복사(deep copy)

 

  • heap에 생성 된 배열이 가지고 있는 값을 또 다른 배열에 복사를 해 놓은 것이다. (새로운 배열 객체 생성 후 기존 배열 복사)
  • 서로 같은 값을 가지고 있지만, 두 배열은 서로 다른 배열이기에 하나의 배열을 변경하더라도 다른 배열에는 영향을 주지 않는다.

 

 

 

 

 2 -1. 깊은 복사를 하는 방법

  • for문을 이용한 동일한 인덱스의 값 복사
  • Object의 clon()을 이용한 복사
  • System의 arraycopy()를 이용한 복사(가장 높은 성능, copyOf()도 arraycopy를 이용한 기능이다 )
  • Arrays의 copyOf()를 이용한 복사 (가장 많이 사용되는 방식,  내부적으로는arraycopy를 쓰고 있는 메소드 )
  • => clon()은 이전 배열과 같은 배열 밖에 만들 수 없고, 그 외 3가지 방법은 복사하는 배열의 길이를 마음대로 조절 할 수 있다.

 

 

 

 

 (1)  for문을 이용한 동일한 인덱스 값 복사

 

◇  print()로 호출하기 위하여 배열을 매개변수로 전달 받아 모든 인덱스에 저장 되어 있는 값을 
   출력하는 기능을 제공하는 메소드 작성

public static void print(int[] iarr) {
 
 전달 받은 배열의 hashCode 출력
System.out.println("iarr의 hashCode : " + iarr.hashCode());
		
 전달 받은 배열의 값 출력
for(int i = 0; i < iarr.length; i++) {
	System.out.print(iarr[i] + " ");
}


public class Application3 {
   public static void main(String[] args) {

(1) 원본 배열 할당 및 초기화 후 별도의 출력 메소드로 호출해서 확인
    int[] originArr = {1, 2, 3, 4, 5};
     
     print(originArr);
  
(2) for문을 이용한 동일한 인덱스 값 복사
    int[] copyArr1 = new int[10];
    for(int i = 0; i < originArr.length; i++) {
			copyArr1[i] = originArr[i];
	 }
(3) 출력 메소드 호출해서 확인하기
     print(copyArr1);
}

◇ 실행 결과
iarr의 hashCode : 1651191114
1 2 3 4 5 
iarr의 hashCode : 1586600255
1 2 3 4 5 0 0 0 0 0 
=> 원본 배열과 복사한 값은 같은 값을 가지고 
   나머지 인덱스는 다른 값, 다른 주소를 가지고 있는 걸 확인 할 수있다.

 

 

 

 

 

(2)  Object의 clone()을 이용한 복사 

 

(1) clone()으로 originArr 복사
int[] copyArr2 = originArr.clone();

(2)별도의 출력 메소드로 호출
print(copyArr2);

◇ 실행 결과
iarr의 hashCode : 1651191114
1 2 3 4 5 
iarr의 hashCode : 474675244
1 2 3 4 5 
=> 동일한 길이, 동일한 값을 가지는 배열이 생성되지만 주소는 다르다.

 

 

 

 

 

(3)  System의 arraycopy()를 이용한 복사

 

(1) 새로운 배열 만들기
int[] copyArr3 = new int[10];

(2)System의 arraycopy()를 이용한 복사하기
 System.arraycopy(originArr, 0, copyArr3, 3, originArr.length);
 arraycopy()의 ()안은
 원본 배열, 복사를 시작할 인덱스, 복사본 배열, 
 복사를 시작할 인덱스, 복사할 길이의 의미를 가진다.
 
 (3) 출력 메소드로 호출해서 확인
 print(copyArr3);
 
 ◇ 실행 결과
iarr의 hashCode : 932583850
0 0 0 1 2 3 4 5 0 0 
=> 복사한 만큼의 값은 같지만 길이도 다르고 주소도 다르다. 
그때그때 다른 형태로 복사가 가능하다는 걸 확인할 수 있다

 

 

 

 

 

 

(4) Arrays의 copyOf()를 이용한 복사

 

int[] originArr = {1, 2, 3, 4, 5};
(1)복사할 배열과 원하는 길이를 정해서 복사하기
int[] copyArr4 = Arrays.copyOf(originArr, 7);
시작 인덱스부터 원하는 길이만큼만 복사해서 사용가능하다. 
(2) 출력 메소드로 호출
print(copyArr4);

◇ 실행 결과
iarr의 hashCode : 212628335
1 2 3 4 5 0 0 
원하는 길이만큼 복사되고 나머지는 초기값 0이나온다. 
깊은 복사이기 떄문에 길이와 주소값은 다른걸 확인할 수 있다.

 

 

 

 

 


향상된  for문으로 인덱스에 접근하는 방법

 


  • 향상 된 for문 (for each문) : 배열 인덱스에 하나씩 차례로 접근해서 담긴 값을 임시로 사용할 변수에 담고 반복문을 실행한다.(값을 변경하는 건 불가능. 출력할 때만 사용)
  • 작성 방법 : for(변수 설정  : 반복의 대상이 되는 배열){   } / 변수는 배열 타입과 동일해야 한다.

 

(1)향상 된 for문으로 값 출력
int[] arr1 = {1, 2, 3, 4, 5};

for(int i : arr2) {
			System.out.print(i + " ");
		}

◇ 실행 결과
1 2 3 4 5 

(2) 향상 된 for문을 이용해 값 증가 시키기
for(int i : arr2) {
			i += 10;
		}
◇ 실행 결과
1 2 3 4 5 
=> 증가되서 출력x, 
인덱스에 접근해서 값을 변경한게 아니고 꺼낸 값을 복사해서 쓴 것이다. 
향상된 for문은 배열에 인덱스에 차례로 접근할 때는 편하게 사용할 수 있지만 값을 변경할 수는 없다.

 

반응형