Java

[Java] 배열(심화)

인생은단짠단짠 2022. 10. 5. 15:44

 

일차원 배열

 

  • 변수는 한 개의 데이터만 저장할 수 있음
  • 동일한 데이터 타입을 여러 개 저장하고 싶을 경우 배열 사용
    • 인덱스는 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