배열(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
}
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
}
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));
}
'Java' 카테고리의 다른 글
객체(Object) - 객체 지향 언어 (0) | 2022.08.22 |
---|---|
배열(Array) - 다차원 배열 (0) | 2022.08.21 |
조건문(conditional statements) - if & switch (0) | 2022.08.19 |
반복문(iteration statements) - for & while & do-while (0) | 2022.08.19 |
연산자(Operator) - 논리 연산자 & 그 외의 연산자 (0) | 2022.08.18 |