Java

배열(Array) - 배열(Array)이란?

제주니어 2022. 8. 20. 22:00

배열(array)

1. 배열(array)이란?

같은 타입의 여러 변수를 하나의 묶음으로 다루는 것.

2. 배열의 선언과 생성

원하는 타입의 변수를 선언하고 변수 또는 타입의 배열임을 의미하는 대괄호[]를 붙이면 된다.

1) 배열의 선언

타입 [] 변수이름;
타입 변수이름[];

2) 배열의 생성

배열을 선언하는 것은 생성된 배열을 다루기 위한 참조변수를 위한 공간이다.

배열을 생성해야만 값을 저장할 수 있는 공간이 만들어진다.

new 타입[배열 크기];

 

배열의 선언과 생성을 동시에 진행

타입[] 변수이름 = new 타입[배열 크기];
타입 변수이름[] = new 타입[배열 크기];

 

변수 선언과 배열 선언

// 변수 선언
int num; // 메모리(Stack)에 자료형 만큼의 크기로 값을 (직접) 담을 수 있는 공간이 할당된다. 

// 배열 선언
int[] iArray1; // 메모리(Stack)에 정수형 배열의 주소를 보관할 공간이 할당된다. (참조 변수)
int iArray2[]; // 메모리(Stack)에 정수형 배열의 주소를 보관할 공간이 할당된다. (참조 변수)
double[] dArray1; // 메모리(Stack)에 실수형 배열의 주소를 보관할 공간이 할당된다. (참조 변수)
double dArray2[]; // 메모리(Stack)에 실수형 배열의 주소를 보관할 공간이 할당된다. (참조 변수)

 

public void method3() {
		int[] iArray = new int[5];
		
		iArray[0] = 2;
		iArray[1] = 4;
		iArray[2] = 6;
		iArray[3] = 8;
		iArray[4] = 10;
//		iArray[5] = 12; // ArrayIndexOutOfBoundsException이 발생한다. 
		
		for (int i = 0; i < iArray.length; i++) {
			System.out.println(iArray[i]);
		}
		
		// hashCode() : 자바에서 해시 코드는 객체(클래스, 배열)를 식별하는 하나의 정수값을 말한다. 
		// 				(기본적으로 객체의 주소값(10진수)을 리턴한다.)
		System.out.println();
		System.out.println(iArray.length);
		System.out.println(iArray); // 주소값 출력
		System.out.println(iArray.hashCode()); // 10진수로 출력

		iArray = new int[6]; 
		
		System.out.println();
		System.out.println(iArray.length);
		System.out.println(iArray); // 주소값 출력
		System.out.println(iArray.hashCode()); // 10진수로 출력
		
		// 참조 변수는 Heap 영역의 객체(클래스, 배열)를 참조하지 않는다는 뜻으로 null 값을 가질 수 있다.
		iArray = null; 
		System.out.println(iArray); // null 출력
		
		// null 값을 가지고 있는 참조 변수를 사용하면 NullPointerException이 발생한다. 
		System.out.println(iArray.length); 
		System.out.println(iArray.hashCode());
	}

3) 배열의 저장 구조

  • 배열 변수는 참조 변수이다. 배열 변수는 Stack 영역에 생성된다.
  • new 자료형[배열 크기] 구문을 실행하면 Heap 영역에 배열을 생성하고, 배열의 시작 주소를 반환한다.
  • new 자료형[] {값, 값, 값, ... } 또는 {값, 값, 값, ... } 구문을 실행하면 주어진 값들을 요소로 가지는 배열을 Heap 영역에 생성하고, 배열의 시작 주소를 반환한다.

3. 배열의 길이와 인덱스

  • 생성된 배열의 각 저장공간을 ‘배열의 요소’라고 한다.
  • 인덱스(index)는 배열의 요소마다 붙여진 일련번호이며, 범위는 0부터 ‘배열길이-1’까지이다.
  • 유효한 범위를 벗어난 값은 index로 사용하면 실행 시에 에러(ArrayIndexOutOfBoundsException)가 발생한다.

1) 배열의 길이

  • int 범위의 양의 정수(0도 포함)이어야 한다.
타입[] 변수이름 = new 타입[길이];
int[] arr = new int[0] // 길이가 0인 배열도 생성이 가능하다

 

배열에서 한번 지정한 크기는 변경이 불가능하다. → ArrayIndexOutOfBoundsException 발생

  • 따라서 크기를 변경하려면 다시 배열 크기를 지정해서 새로 생성해야 한다.
  • 기존에 있던 것을 늘리는 것이 아니라 새로운 것을 만든다. 
public void method3() {
		int[] iArray = new int[5];
		
		iArray[0] = 2;
		iArray[1] = 4;
		iArray[2] = 6;
		iArray[3] = 8;
		iArray[4] = 10;
//		iArray[5] = 12; // ArrayIndexOutOfBoundsException이 발생한다. 
		
		for (int i = 0; i < iArray.length; i++) {
			System.out.println(iArray[i]);
		}
		
		// hashCode() : 자바에서 해시 코드는 객체(클래스, 배열)를 식별하는 하나의 정수값을 말한다. 
		// 				(기본적으로 객체의 주소값(10진수)을 리턴한다.)
		System.out.println();
		System.out.println(iArray.length);
		System.out.println(iArray); // 주소값 출력
		System.out.println(iArray.hashCode()); // 10진수로 출력

		iArray = new int[6]; 
		
		System.out.println();
		System.out.println(iArray.length);
		System.out.println(iArray); // 주소값 출력
		System.out.println(iArray.hashCode()); // 10진수로 출력
		
		// 참조 변수는 Heap 영역의 객체(클래스, 배열)를 참조하지 않는다는 뜻으로 null 값을 가질 수 있다.
		iArray = null; 
		System.out.println(iArray); // null 출력
		
		// null 값을 가지고 있는 참조 변수를 사용하면 NullPointerException이 발생한다. 
		System.out.println(iArray.length); 
		System.out.println(iArray.hashCode());
	}

2) 배열이름.length

배열은 한번 생성하면 길이를 변경할 수 없기 때문에, 이미 생성된 배열의 길이는 변하지 않는다.

따라서 ‘배열이름.length’는 상수다.

즉, 값을 읽을 수만 있을 뿐 변경할 수 없다.

3) 배열의 길이 변경하기

① 더 큰 배열을 새로 생성한다.

② 기존 배열의 내용을 새로운 배열에 복사한다.

4. 배열의 초기화

  • new 타입[]을 생략할 수 있지만 배열의 선언과 생성을 따로 하는 경우에는 생략할 수 없다.
  • 괄호 {} 안에 아무 것도 넣지 않으면, 길이가 0인 배열이 생성된다.

 

  • 참조변수의 기본 값은 null이지만, 배열을 가리키는 참조변수는 null대신 길이가 0인 배열로 초기화하기도 한다.
  • 배열은 따로 초기화하지 않는다면, JVM이 지정한 기본 값으로 배열을 초기화한다.
정수형 : 0, 실수형 : 0.0, 문자형 : '\u0000', 논리형 : false, 참조형 : null

 

타입[ ] 변수이름 = new 타입[ ] {값, 값, 값, ...};
타입 변수이름 [ ] = new 타입[ ] {값, 값, 값, ...};
타입[ ] 변수이름= {값, 값, 값, ...};
타입 변수이름[ ] = {값, 값, 값, ...};

 

  • 배열의 길이가 큰 경우에는 하나하나에 값을 지정하기 보다는 for문을 사용하는 것이 좋다.
int[] score = new int[]; 
for (int i = 0; i <score.length; i++) { 
	score[i] = i * 10 + 50
    }

 

  • 참조변수의 값을 바로 출력하면 ‘타입@주소’의 형식으로 출력된다.

 

실습 문제

/*
	 * 실습 문제 1
	 * 
	 * 사용자가 입력하는 정수값으로 배열의 길이는 지정하여 배열을 생성하고 
	 * 생성된 배열의 크기만큼 반복문을 실행하여 랜덤값을 (1 ~ 100) 배열에 저장하고 출력한다. 
	 * 
	 * 예시) 
	 * 정수값을 입력해 주세요 > 3
	 * 
	 * numbers[0] : 77
	 * numbers[1] : 88
	 * numbers[2] : 6
	 */
	
	public void practice1() {
		int size = 0;
		int[] numbers = null;
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("정수값을 입력해 주세요 > ");
		size = scanner.nextInt();
		System.out.println();
		numbers = new int[size];
		
		for (int i = 0; i < numbers.length; i++) {
			numbers[i] = (int) (Math.random()*100+1);
			System.out.printf("numbers[%d] : %d\\n", i, numbers[i]);
		}
		scanner.close();

	}

	/*
	 * 실습 문제 2
	 * 
	 * 사용자에게 3명의 키를 입력받아 배열에 저장하고
	 * 반복문을 통해 3명의 키의 총합, 평균값을 구하시오.
	 * 
	 * 예시)
	 * 키 입력 > 180.0
	 * 키 입력 > 177.3
	 * 키 입력 > 168.2
	 * 
	 * 총 합 : 525.5
	 * 평 균 : 175.2
	 */
	
	public void practice2() {
		double sum = 0;
		double avg = 0;
		double[] array = new double[3];
			
		Scanner scanner = new Scanner(System.in);
		
		for (int i = 0; i < array.length; i++) {
			System.out.print("키 입력 > ");
			array[i] = scanner.nextDouble();
		}
		for (int i = 0; i < array.length; i++) {
			sum += array[i];
		}
		avg = sum / array.length;
		
		System.out.println();   
		System.out.println("총합 : " + sum);
		System.out.printf("평균 : %.1f",avg);
		scanner.close();
		
		
	}

5. 배열의 복사

1) for문 이용한 배열의 복사

int [] arr = new int [5];
...
int [] tmp = new int[arr.length*2] // 기존 배열보다 길이가 2배인 배열 생성
for(int i = 0; i < arr.length; i++) {
	tmp[i] = arr[i]; // arr[i]의 값을 tmp[i]에 저장
	}
arr = tmp; // 참조변수 arr이 새로운 배열을 가리키게 한다.
  • 새로운 배열을 생성하여 반복문을 통해 실제 값을 복사하는 방법
  • 배열은 참조변수를 통해서만 접근할 수 있기 때문에, 자신을 가리키는 참조변수가 없는 배열은 사용할 수 없다.
  • 쓸모없게 된 배열은 JVM의 가비지 컬렉터에 의해서 자동적으로 메모리에서 제거된다.
public void method2() {
		int origin[] = {6,7,8,9,10};
		int copy[] = new int[10];
		
		// 반복문을 통해서 origin에 있는 값들을 copy에 대입한다. 
		for (int i = 0; i < origin.length; i++) {
			copy[i] = origin[i];
		}
		
		// 원본 배열 출력
		for (int i = 0; i < origin.length; i++) {
			System.out.print(origin[i] + " "); // 6 7 8 9 10
		}
		
		System.out.println();
		
		// 복사본 배열 출력
		for (int i = 0; i < copy.length; i++) {
			System.out.print(copy[i] + " "); // 6 7 8 9 10 0 0 0 0 0
		}
		
		copy[2] = 88;
		System.out.println();
		
		// 원본 배열 출력
		for (int i = 0; i < origin.length; i++) {
			System.out.print(origin[i] + " "); // 6 7 8 9 10
		}
		
		System.out.println();
		
		// 복사본 배열 출력
		for (int i = 0; i < copy.length; i++) {
			System.out.print(copy[i] + " "); // 6 7 88 9 10 0 0 0 0 0
		}
		
		System.out.println();
		System.out.println(origin.hashCode()); // 1910163204
		System.out.println(copy.hashCode()); // 305623748
		System.out.println(origin.equals(copy)); // false
	}

copy의 공간은 10개, origin으로 채워진 나머지는 기본값인 0으로 채워진다.

 

origin의 주소; copy의 주소

2) System.arraycopy()를 이용한 배열의 복사

System.arraycopy(원본 배열, 복사 시작 인덱스, 복사본 배열, 복사 시작위치, 복사할 길이)

복사하고자 하는 배열의 인덱스와 개수를 지정하고 싶을 때 사용한다.

복사되는 배열을 미리 생성해서 전달해야 한다.

 

for문 대신 System클래스의 arraycopy()를 사용하면 보다 간단하고 빠르게 배열을 복사할 수 있다.

for문은 배열의 요소 하나하나에 접근해서 복사하지만, arraycopy()는 지정된 범위의 값들을 한 번에 통째로 복사한다.

이때 복사하려는 배열의 위치가 적절하지 못하여 복사하려는 내용보다 여유 공간이 적으면 에러(ArrayIndexOutOfBoundException)가 발생한다.

for(int i = 0; i < num.length; i++) {newNum[i] = num[i];}
-> 
System.arraycopy(num, 0, newNum, 0, num.length); 
// num[0]에서 newNum[0]으로 num.length개의 데이터를 복사

int origin[] = {6,7,8,9,10};
int copy[] = new int[10];

System.arraycopy(origin, 0, copy, 2, origin.length);

// 원본 배열 출력
for (int i = 0; i < origin.length; i++) {
    System.out.print(origin[i] + " "); // 6 7 8 9 10
}

System.out.println();

// 복사본 배열 출력 
for (int i = 0; i < copy.length; i++) {
    System.out.print(copy[i] + " "); // 0 0 6 7 8 9 10 0 0 0
}

System.out.println();
System.out.println(origin.hashCode()); // 1910163204
System.out.println(origin.length); // 5
System.out.println(copy.hashCode()); // 305623748
System.out.println(copy.length); // 10
System.out.println(origin.equals(copy)); // false
}

 

public void method3() {
		String str1 = new String("java");
		String str2 = "java";
		String str3 = "java";
		String str4 = new String("java");
		
		System.out.println(str1 == str2); // false
		System.out.println(str2 == str3); // true
		System.out.println(str1 == str4); // false
	}

 

method3

3) Array 클래스에 제공하는 copyOf() 메소드를 이용한 배열의 복사

Arrays.copyOf(원본배열, 복사할 길이)

복사하고자 하는 배열의 크기를 다시 지정해서 복사하고 싶을 때 사용한다.

복사되는 배열을 미리 생성하지 않고 메소드에 배열의 크기를 전달해서 생성한다.

public void method4() {
		int[] origin = {1, 2, 3, 4, 5};
		int[] copy = null; // 참조변수만 생성
		
		copy = Arrays.copyOf(origin, 10);
		
		// 향상된 for문 이용 (for each)
		// for(타입 변수 : 배열 or 컬렉션){ }
		// 원본 배열 출력
		for(int value : origin) {
			System.out.print(value + " "); // 1 2 3 4 5 
		}
		
		System.out.println();
		
		// 복사본 배열 출력
		for (int value : copy) {
			System.out.print(value + " "); // 1 2 3 4 5 0 0 0 0 0 
		}
		System.out.println();
		System.out.println(origin.hashCode()); // 1910163204
		System.out.println(origin.length); //5
		System.out.println(copy.hashCode()); // 305623748
		System.out.println(copy.length); //10
	}

4) clone() 메소드를 이용한 배열의 복사

  • 원본 배열을 통째로 복사해서 새로운 배열을 생성한다.
  • 시작 인덱스를 지정할 수 없고 복사본 배열의 크기로 지정할 수 없다.
public void method5() {
		int[] origin = {11, 12, 13, 14, 15};
		int[] copy = origin.clone();
		// 원본 배열 출력
		for(int value : origin) {
			System.out.print(value + " "); // 11 12 13 14 15
		}
		
		System.out.println();
		
		// 복사본 배열 출력
		for (int value : copy) {
			System.out.print(value + " "); // 11 12 13 14 15
		}
		System.out.println();
		System.out.println(origin.hashCode()); // 1910163204
		System.out.println(origin.length); // 5
		System.out.println(copy.hashCode()); // 305623748
		System.out.println(copy.length); // 5

5) 그 외 얕은 복사

  • 주소값만 복사가 된다.
public void method1() {
		int[] origin = {5,6,7};
		int[] copy = origin; // 주소값만 복사가 된다. 
		
		// 원본 배열 출력
		for (int i = 0; i < origin.length; i++) {
			System.out.print(origin[i] + " "); // 5 6 7
		}
		
		System.out.println();
		
		// 복사본 배열 출력 
		for (int i = 0; i < copy.length; i++) {
			System.out.print(copy[i] + " "); // 5 6 7
		}
		
		copy[1] = 66; // 5 66 7
		
		System.out.println();
		
		// 원본 배열 출력
		for (int i = 0; i < origin.length; i++) {
			System.out.print(origin[i] + " "); // 5 66 7
		}
		
		System.out.println();
		
		// 복사본 배열 출력 
		for (int i = 0; i < copy.length; i++) {
			System.out.print(copy[i] + " "); // 5 66 7  
		}
		
		// 두개의 참조변수가 같은 배열을 가리키고 있기 때문에 copy만 바꿨는데 origin도 바뀌는 것이다.
		System.out.println();
		System.out.println(origin.hashCode()); // 1910163204
		System.out.println(copy.hashCode()); // 1910163204
	}

6. 배열의 활용

1) 오름차순 & 내림차순

  • 오름차순 : Arrays.sort 이용
    • 오름차순(Ascending, ASC)은 작은 데이터부터 큰 데이터로 나열하는 방식이다.
  • 내림차순 : Array.sort는 오름차순만 제공한다
    • 내림차순(Descending, DESC)은 큰 데이터부터 작은 데이터로 나열하는 방식이다.
    • for문 사용해서 원본 배열을 오름차순으로 정렬한 다음 값을 반대로 새로운 배열에 대입한다.

 

정렬을 바꿔도 주소값을 동일하다

public void method1() {
		int arr[] = {2, 7, 5, 1, 3};
		
//		for (int value : arr) {
//			System.out.printf("%d ", value);
//		}
		System.out.println(arr.hashCode()); // 1910163204
		System.out.println(Arrays.toString(arr)); // [2, 7, 5, 1, 3]
		
		// 오름차순으로 정렬
		Arrays.sort(arr);
		
		System.out.println(arr.hashCode()); // 1910163204 - 정렬을 바꿔도 주소값을 동일
		System.out.println(Arrays.toString(arr)); // [1, 2, 3, 5, 7]
	
		// 내림차순으로 정렬
		// 오름차순 배열은 위에서 적용했으므로 반대 배열만 적용시키면 된다. 
		int[] copy = new int[5];
		for (int i = 0; i < arr.length; i++) {
			copy[4 -i ] = arr[i];
//			copy[arr.length -i -1] = arr[i];
//			copy[copy.length -i -1] = arr[i];
		}
		
		System.out.println(arr.hashCode()); // 1910163204
		
		// 2. 아래와 같이 작성하는 방법이 있다. (추후 설명)
		Integer[] iArray = {2, 7, 5, 1, 3};
		
		Arrays.sort(iArray, Collections.reverseOrder());
		
		System.out.println();
		System.out.println(Arrays.toString(iArray)); // [7, 5, 3, 2, 1]
	}

 

public void method2() {
		String[] array = {"메론", "orange", "apeach", "banana", "apple", "레몬"};
		
		// 오름차순 정렬
		Arrays.sort(array);
		System.out.println(Arrays.toString(array));
		
		// 내림차순 정렬
		Arrays.sort(array, Collections.reverseOrder());
		System.out.println(Arrays.toString(array));
	}