
일차원 배열
- 변수는 한 개의 데이터만 저장할 수 있음
- 동일한 데이터 타입을 여러 개 저장하고 싶을 경우 배열 사용
- 인덱스는 0부터 시작
- 배열 원소 사이에는 순서가 존재
- 하나의 배열 이름을 공유할 수 있기 때문에 나중에 for문과 같이 사용
선언 방법
- 배열 선언시 저장할 원소 개수만 알고 있는 경우
- 데이터타입[] 배열변수이름 = new 데이터타입[데이터 개수];
- 배열 선언시 원소값을 알고 있는 경우
- 데이터타입[] 배열변수이름 = {...,...,...,...,...,};
- 배열 객체가 없다면 null 초기화 가능
- 데이터타입[] 배열변수이름 = null;
메모리
원소가 원시타입인 경우
int[] nums = {10, 20, 30, 40, 50};

원소가 참조 타입인 경우
String[] names = {"Sally", "John", "Jacob", "Kelly", "Minna"};

배열 변수에는 첫번째 원소 주소만 저장됩니다.
이차원 배열
- 행과 열을 가진 테이블 형태의 데이터 저장할 경우 이차원 배열 사용
- 사실상 이차원 배열이라는 개념은 물리적으로 존재하지 않음 → 일차원 배열로 저장
선언방법
- 배열 선언시 저장할 행과 열의 개수만 알고 있는 경우
- 데이터타입[][] 배열변수이름 = new 데이터타입[행의 크기][열의 크기];
- 배열 선언시 원소값을 알고 있는 경우
- 데이터타입[][] 배열변수이름 = {{...,....,....,},{...,...,...,}};
- 배열 객체가 없다면 null 초기화 가능
- 데이터타입[] 배열변수이름 = null;
row-major order 🆚 column-major order

- *row-major: C/*C++, Pascal, and Python)
- column-major: Fortran, **Julia, R and Matlab
배열을 rowmajor배열로 만들기, colmajor배열로 만들기
import java.util.Arrays;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Array2dMajorExample {
public static void main(String[] args) {
final int ROW_NUM = 3;
final int COL_NUM = 5;
int[][] arr2d = new int[ROW_NUM][COL_NUM];
for (int i = 0; i < arr2d.length; i++) {
for (int j = 0; j < arr2d[i].length; j++) {
arr2d[i][j] = (i + 1) * (j + 1);
}
}
int[][] rowMajor = InitializeRowMajor(arr2d);
int[][] colMajor = InitializeColumnMajor(arr2d);
System.out.println(Arrays.deepToString(rowMajor));
System.out.println(Arrays.deepToString(colMajor));
System.out.println(Arrays.deepToString(transposeMatrix(rowMajor)));
}
public static int[][] InitializeRowMajor(int[][] original) {
int[][] rowMajor = new int[original.length][original[0].length];
for (int i = 0; i < rowMajor.length; i++) {
for (int j = 0; j < rowMajor[i].length; j++) {
rowMajor[i][j] = original[i][j];
}
}
return rowMajor;
}
public static int[][] InitializeColumnMajor(int[][] original) {
int[][] colMajor = new int[original[0].length][original.length];
for (int i = 0; i < colMajor.length; i++) {
for (int j = 0; j < colMajor[i].length; j++) {
colMajor[i][j] = original[j][i];
}
}
return colMajor;
}
public static int[][] transposeMatrix(int[][] original) {
return IntStream.range(0, original[0].length)
.mapToObj(i -> Stream.of(original).mapToInt(row -> row[i]).toArray())
.toArray(int[][]::new);
}
}
메모리
원소가 원시 타입인 경우
int[][] nums2d = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

- 배열 변수에는 첫번째 원소 주소만 저장됨
- int[] nums2d에는 실제 데이터의 주소가 배열로 저장되어 있음
원소가 참조타입인 경우
String[][] names2d = {{"a", "b", "c"}, {"d", "e", "f"}, {"g", "h", "i"}};

일차원 배열 ↔️ 이차원 배열
- 일차원 배열 -> 이차원 배열
- 이차원 배열 -> 일차원 배열
public class Array1dtoArray2dExample {
public static void main(String[] args) {
final int ROW_NUM = 3;
final int COL_NUM = 5;
final int NUM = ROW_NUM * COL_NUM;
int[] arr1d = new int[NUM];
for (int i = 0; i < arr1d.length; i++) {
arr1d[i] = i + 1;
}
for (int element: arr1d) {
System.out.printf("%2d ", element);
}
System.out.println("\n");
int[][] arr2d = new int[ROW_NUM][COL_NUM];
for (int i = 0; i < arr2d.length; i++) {
for (int j = 0; j < arr2d[i].length; j++) {
arr2d[i][j] = arr1d[i * COL_NUM + j];
}
}
for (int i = 0; i < arr2d.length; i++) {
for (int j = 0; j < arr2d[i].length; j++) {
System.out.printf("%2d ", arr2d[i][j]);
}
System.out.println();
}
System.out.println("\n");
int[] arr1dRevert = new int[ROW_NUM * COL_NUM];
for (int i = 0; i < arr2d.length; i++) {
for (int j = 0; j < arr2d[i].length; j++) {
arr1dRevert[i * COL_NUM + j] = arr2d[i][j];
}
}
for (int element: arr1dRevert) {
System.out.printf("%2d ", element);
}
}
}
new 연산자를 통해 배열 생성하면 힙 메모리에 다음과 같이 초기화
정수: 0
실수: 0.0f / 0.0
논리: false
문자: \0, \u0000
문자열: null
배열 출력
1. Array.toString / Arrays.deepToString 으로 출력할 수 있습니다.
2. Arrays.stream(배열이름).forEach((i) -> System.out.print(i+" ")); 로 출력할 수 있습니다.
import java.util.Arrays;
public class ArraysToStringExample {
public static void main(String[] args) {
// 일차원 배열 출력
int[] arr1d = {1, 2, 3, 4, 5};
String[] strArr1d = {"Java", "JSP", "Servlet", "Spring"};
System.out.println(Arrays.toString(arr1d));
System.out.println(Arrays.toString(strArr1d));
Arrays.stream(arr1d).forEach((i) -> System.out.print(i + " "));
Arrays.stream(strArr1d).forEach((i) -> System.out.print(i + " "));
System.out.println("\n");
// 이차원 배열 출력
int[][] arr2d = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
String[][] strArr2d = {{"a", "ab", "abc"}, {"1", "12", "123"}, {"a1", "b2", "c3"}};
System.out.println(Arrays.deepToString(arr2d));
System.out.println(Arrays.deepToString(strArr2d));
Arrays.stream(arr2d).forEach((i) -> {
Arrays.stream(i).forEach((j) -> System.out.print(j + " "));
System.out.println();
});
Arrays.stream(strArr2d).forEach((i) -> {
Arrays.stream(i).forEach((j) -> System.out.print(j + " "));
System.out.println();
});
}
}
배열 비교
배열 이름이 아닌 배열 원소를 반복하면서 비교해야 합니다.
Equals
주소값 비교와 원소값 비교를 혼동하지 않아야 합니다.
Arrays.equals / Arrays.deepEquals 를 사용하여 배열이 같은지 비교할 수 있습니다.
import java.util.Arrays;
public class ArraysEqualsExample {
public static void main(String[] args) {
// 일차원 배열 비교
int[] arr1d = {1, 2, 3, 4, 5, 6};
int[] arr1dCompare = {1, 2, 3, 4, 5, 6, 7};
String[] strArr1d = {"Java", "JSP", "Servlet", "Spring"};
String[] strArr1dCompare = {"Java", "JSP", "Servlet", "Spring"};
System.out.println(arr1d == arr1dCompare); // 주소값 비교
System.out.println(arr1d.equals(arr1dCompare)); // 주소값 비교
System.out.println(strArr1d == strArr1dCompare); // 주소값 비교
System.out.println(strArr1d.equals(strArr1dCompare)); // 주소값 비교
System.out.println(Arrays.equals(arr1d, arr1dCompare)); // 원소값 비교
System.out.println(Arrays.equals(strArr1d, strArr1dCompare)); // 원소값 비교
System.out.println();
// 이차원 배열 비교
int[][] arr2d = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int[][] arr2dCompare = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
String[][] strArr2d = {{"a", "ab", "abc"}, {"1", "12", "123"}, {"a1", "b2", "c3"}};
String[][] strArr2dCompare = {{"a", "ab", "abc"}, {"1", "12", "123"}, {"a1", "b2", "c3"}};
System.out.println(arr2d == arr2dCompare); // 주소값 비교
System.out.println(strArr2d == strArr2dCompare); // 주소값 비교
System.out.println(arr2d.equals(arr2dCompare)); // 주소값 비교
System.out.println(strArr2d == strArr2dCompare); // 주소값 비교
for (int i = 0; i < arr2d.length; i++) {
System.out.println(arr2d[i] == arr2dCompare[i]); // 주소값 비교
System.out.println(strArr2d[i] == strArr2dCompare[i]); // 주소값 비교
System.out.println(arr2d[i].equals(arr2dCompare[i])); // 주소값 비교
System.out.println(strArr2d[i] != null && strArr2d[i].equals(strArr2dCompare[i])); // 주소값 비교
}
System.out.println(Arrays.deepEquals(arr2d, arr2dCompare)); // 원소값 비교
System.out.println(Arrays.deepEquals(strArr2d, strArr2dCompare)); // 원소값 비교
System.out.println();
}
}
Array.equals 구현 (이렇게 구현되어 있을 것이다)
public static boolean isEquals(int[] a, int[] b) {
if (a.length != b.length) return false;
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) return false;
}
return true;
}
public static boolean isEquals(String[] a, String[] b) {
if (a.length != b.length) return false;
for (int i = 0; i < a.length; i++) {
if (a[i] != null && !a[i].equals(b[i])) return false;
}
return true;
}
Arrays.deepEquals 구현
public static boolean isDeepEquals(int[][] a, int[][] b) {
if (a.length != b.length) return false;
if (a[0].length != b[0].length) return false;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[0].length; j++) {
if (a[i][j] != b[i][j]) return false;
}
}
return true;
}
public static boolean isDeepEquals(String[][] a, String[][] b) {
if (a.length != b.length) return false;
if (a[0].length != b[0].length) return false;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[0].length; j++) {
if (a[i][j] != null && !a[i][j].equals(b[i][j])) return false;
}
}
return true;
}
Compare
Arrays.compare 를 사용하여 배열 비교할 수 있습니다.
import java.util.Arrays;
public class ArraysCompareExample {
public static void main(String[] args) {
int[] arr1d = {1, 2, 3, 4, 5, 6};
int[] arr1dCompare = {1, 2, 3, 4, 5, 6, 7};
String[] strArr1d = {"Java", "JSP", "Servlet", "Spring"};
String[] strArr1dCompare = {"Javp", "JSP", "Servlet", "Spring", "Python"};
System.out.println(Arrays.compare(arr1d, arr1dCompare)); // 원소값 비교
System.out.println(Arrays.compare(strArr1d, strArr1dCompare)); // 원소값 비교
System.out.println();
}
}
Arrays.compare 함수 구현
public static int compare(int[] a, int[] b) {
int minLength = Math.min(a.length, b.length);
for (int i = 0; i < minLength; i++) {
if (a[i] != b[i]) {
return Integer.compare(a[i], b[i]);
}
}
if (a.length < b.length) return -1;
else if (a.length > b.length) return 1;
else return 0;
}
public static int compare(String[] a, String[] b) {
int minLength = Math.min(a.length, b.length);
for (int i = 0; i < minLength; i++) {
if (a[i] != null && !a[i].equals(b[i])) {
return a[i].compareTo(b[i]);
}
}
if (a.length < b.length) return -1;
else if (a.length > b.length) return 1;
else return 0;
}
배열 복사
배열 이름이 아닌 배열 원소를 반복하면서 복사해야합니다.
import java.util.Arrays;
public class ArraysCopyExample {
public static void main(String[] args) {
// 일차원 배열 복사
int[] arr1d = {1, 2, 3, 4, 5, 6};
int[] arr1dCopy = arr1d; // 주소값 대입
String[] strArr1d = {"Java", "JSP", "Servlet", "Spring"};
String[] strArr1dCopy = strArr1d; // 주소값 대입
final int NEW_LEN = 7;
arr1dCopy = Arrays.copyOf(arr1d, NEW_LEN); // 배열 원소값 복사
strArr1dCopy = Arrays.copyOf(strArr1d, NEW_LEN); // 배열 원소값 복사
//[1, 2, 3, 4, 5, 6, 0]
//[Java, JSP, Servlet, Spring, null, null, null]
System.out.println(arr1d == arr1dCopy); // false
System.out.println(Arrays.equals(arr1d, arr1dCopy)); // false
System.out.println(strArr1d == strArr1dCopy); // false
System.out.println(Arrays.equals(strArr1d, strArr1dCopy)); // false
// 이차원 배열 복사
int[][] arr2d = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int[][] arr2dCopy = arr2d; // 주소값 대입
String[][] strArr2d = {{"a", "ab", "abc"}, {"1", "12", "123"}, {"a1", "b2", "c3"}};
String[][] strArr2dCopy = strArr2d; // 주소값 대입
final int NEW_ROW = 3;
final int NEW_COL = 5;
arr2dCopy = deepCopy(arr2d, NEW_ROW, NEW_COL);
strArr2dCopy = deepCopy(strArr2d, NEW_ROW, NEW_COL);
System.out.println(arr2d == arr2dCopy); // false
System.out.println(Arrays.deepEquals(arr2d, arr2dCopy)); // false
System.out.println(strArr2d == strArr2dCopy); // false
System.out.println(Arrays.deepEquals(strArr2d, strArr2dCopy)); // false
arr2dCopy = deepCopyWithStream(arr2d);
strArr2dCopy = deepCopyWithStream(strArr2d);
System.out.println(Arrays.deepToString(arr2dCopy));
System.out.println(Arrays.deepToString(strArr2dCopy));
System.out.println(arr2d == arr2dCopy); // false
System.out.println(Arrays.deepEquals(arr2d, arr2dCopy)); // true
System.out.println(strArr2d == strArr2dCopy); // false
System.out.println(Arrays.deepEquals(strArr2d, strArr2dCopy)); // true
}
public static int[] copy(int[] original, int newLength) {
int[] copied = new int[newLength];
for (int i = 0; i < original.length; i++) {
copied[i] = original[i];
}
return copied;
}
public static String[] copy(String[] original, int newLength) {
String[] copied = new String[newLength];
for (int i = 0; i < original.length; i++) {
if (original[i] != null) {
copied[i] = original[i];
}
}
return copied;
}
public static int[][] deepCopy(int[][] original, int newRow, int newColumn) {
int[][] copied = new int[newRow][newColumn];
for (int i = 0; i < original.length; i++) {
for (int j = 0; j < original[i].length; j++) {
copied[i][j] = original[i][j];
}
}
return copied;
}
public static String[][] deepCopy(String[][] original, int newRow, int newColumn) {
String[][] copied = new String[newRow][newColumn];
for (int i = 0; i < original.length; i++) {
for (int j = 0; j < original[i].length; j++) {
if (original[i][j] != null) {
copied[i][j] = original[i][j];
}
}
}
return copied;
}
public static int[][] deepCopyWithStream(int[][] original) {
return Arrays.stream(original).map(r -> Arrays.copyOf(r, r.length)).toArray(int[][]::new);
}
public static String[][] deepCopyWithStream(String[][] original) {
return Arrays.stream(original).map(r -> Arrays.copyOf(r, r.length)).toArray(String[][]::new);
}
}
자바 배열 복사 방법
- Object.clone()
- 배열도 객체이므로 이 메서드를 사용하여 전체 배열 복사를 수행할 수 있음
- 배열 일부 복사할 수 없음
- 객체 복사는 Cloneable이라는 인터페이스의 clone 함수 재정의 가능
- System.arraycopy(src, srcPos, dest, destPos, length) ✨
- 시스템 클래스를 통해 배열 부분 복사하는 가장 좋은 방법
- 복사할 총 요소 수와 원본 및 대상 배열 인덱스 위치 지정가능
- System.arraycopy(src, 3, dest 2, 5)
- src의 3번째 인덱스부터 dest의 2번째 인덱스까지 5개의 요소를 src에서 dest로 복사
- Arrays.copyOf(original, newLength)
- 배열의 처음 몇 개 요소 복사 가능
- 배열의 전체 복사 가능
- 가독성이 좋고 사용하기 쉬움
- System.arraycopy()을 wrapping == 내부적으로 System.arraycopy() 호출
- Arrays.copyOfRange(original, from, to)
- 시작 인덱스가 0이 아닌 일부 배열 원소 복사 가능
'Java' 카테고리의 다른 글
| 토이프로젝트 후 느낀점 (0) | 2022.10.29 |
|---|---|
| [Java] 컬렉션 프레임워크 활용 (0) | 2022.10.20 |
| [Java] 자바 입출력 (0) | 2022.10.02 |
| [Java] 예외 처리 (0) | 2022.10.02 |
| [Java] 자바의 유용한 클래스 (0) | 2022.10.01 |