[CS] 자바의 정석 독서 #22 - Arrays로 배열 다루기

2025. 11. 28. 07:43·언어공부/Java | Kotlin

어쩌다보니 프로그래밍 언어와 CS 지식도 쓰리트랙으로 나눠서 배우게 되었다. 자바, 자바스크립트, C 계열언어.. 특히 자바는 자바의 정석과 JVM 구동방식을 나눠서 배우다보니 정작 자바에 쏟을 시간은

줄어들게된건가...?

 

https://dev-dx2d2y-log.tistory.com/131

 

[CS] 자바의 정석 독서 #21 - 이터레이터

리스트의 메서드를 살펴보다보면 ListIterator라는 자료구조가 등장하는데, 이는 Iterator의 성능을 향상시킨 버전이다.이터레이터는 컬렉션의 상위클래스이며, 구버전으로는 Enumeration이 있다. 즉,

dev-dx2d2y-log.tistory.com

암튼 저번에는 컬렉션, 그 중에서도 이터레이터에 대해서 알아봤다. 이번에는 컬렉션 말고 배열에 대해 알아보려한다.

 

오늘 나올 Arrays 클래스는 컬렉션에는 적용시킬 수 없다. 배열에 적용시키는 대상이다. 다만 fill()과 asList()를 제외하면 컬렉션 유틸리티 클래스 Collections에서 다룰 수 있다. Collections는 11장 끝부분에서 다룰 예정이다.


Arrays

List<> 등 컬렉션의 메서드는 배열과는 호환되지 않는데, 배열에 적용시킬 수 있는 메서드들이 정의되어있는 클래스이다. 기본적인 배열은 toString이 없지만 Arrays에는 toString이 타입별로 오버로딩 되어있다.


복사 - copyOf(), copyOfRange()

int[] arr = {1,2,3,4,5};
int[] arr2 = Arrays.copyOf(arr, arr.length);	//{1,2,3,4,5}
int[] arr3 = Arrays.copyOfRange(arr,3);			//{1,2,3}
int[] arr4 = Arrays.copyOfRange(arr, 2, 4)		//{3, 4}

copyOf()는 배열의 전체를 복사하고, copyOfRange는 일부만 복사한다.

자바에서는 파이썬의 메서드 인덱싱이 없기 때문에 배열복사를 통해서 인덱싱을 진행해야한다.

 

또한 나중에 배열을 사용하다보면 '방어적 복사'를 해야할 때가 있는데, 이 때도 사용하게된다.


채우기 - fill(), setAll()

int[] arr = {1,2,3,4,5};
Arrays.setAll(arr,i->i*i);

System.out.println(Arrays.toString(arr));		//{ 0, 1, 4, 9, 16 }
int[] arr = {1,2,3,4,5};
Arrays.fill(arr,0);

System.out.println(Arrays.toString(arr));	//{ 0, 0, 0, 0, 0 }

fill()은 배열을 지정된 값으로 모두 채운다. setAll()은 배열을 채우는데 필요한 사용할 함수형 인터페이스를 매개로 받아 배열을 어떤 패턴으로 채울지 람다식으로 표현할 수 있다. 물론 함수형 인터페이스의 구현체를 매개변수로 건네주어도 된다.

 

람다는 나중에 나온다.


정렬, 탐색 -  sort(), binarySearch()

sort는 배열을 정렬하는데 사용된다.

 

https://dev-dx2d2y-log.tistory.com/45

 

[2025백엔드] 헤드퍼스트자바 독서 #8 - 12장. 람다와 스트림

와! 몰랐던거 두 개! 람다와 스트림!가장 배우고 싶었던 것이다. 파이썬 때도 람다는 몰라서 근데 가만 생각해보니 나 파이썬으로 왜이렇게 뭔가를 안했지 암튼람다1 - forEach기존 for문은 for 반복

dev-dx2d2y-log.tistory.com

과거 Comparator와 Comparable을 통해 배열을 정렬하는 법에 대해서 다뤘는데, 이처럼 배열을 특정 기준에 따라서 정렬하는데 사용한다.


Comparator와 Comparable

sort하면 Comparator와 Comparable을 빼놓을 수 없는데, 두 개 모두 인터페이스로, Arrays.sort() 메서드의 정렬기준을 잡아주는 역할을 한다.

 

public interface Comparator<T> {
    int compare(T o1, T o2);
}
public interface Comparable<T> {
    public int compareTo(T o);
}

이렇게 Compartator와 Comparable 인터페이스에는 요소를 서로 비교할 수 있는 메서드들이 선언되어있다.

 

compare와 compareTo의 메서드 간 큰 차이는 없다. 두 메서드 모두 두 객체의 크기비교가 목적이기 때문이다. 반환값이 int인 이유는 두 객체가 같으면 0, 비교하는 값이 더 크면 음수, 작으면 양수를 반환한다. 

 

public final class Integer extends Number
        implements Comparable<Integer>, Constable, ConstantDesc {
	public int compareTo(Integer anotherInteger) {
            return compare(this.value, anotherInteger.value);
    }
    
    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
}

대표적으로 Integer 클래스 내부에서 Comparable 인터페이스를 구현해 compareTo() 메서드를 실행시킬 수 있다.

 

같은 정렬인데 왜 굳이 두 개의 함수를 사용하냐면..

int[] arr = {3, 1, 7, 8, 9};
Arrays.sort(arr);

System.out.println(Arrays.toString(arr));	//[ 1, 3, 7, 8, 9 ]

배열이나 컬렉션에 들어가는 객체에서 '특정한 기본 정렬 기준'을 맞추고 싶다면 Comparable을 구현하여 compareTo 메서드를 작성시켜놓으면 위와같이 정렬이 필요할 때 알아서 정렬이 진행된다.

 

Arrays.sort() 메서드는 인자로 배열만 전해졌을 경우 배열에 저장된 객체의 compareTo() 메서드를 참고하여 배열을 정렬한다.

public class Main {
    public static void main(String[] args) {
        MyNumber[] nums =  new MyNumber[10];
        for (int i = 1; i < nums.length+1; i++) {
            nums[i-1] = new MyNumber(31 % i);
        }

        Arrays.sort(nums);		//여기서 에러
        System.out.println(Arrays.toString(nums));
    }
}

class MyNumber {
    int number;

    public MyNumber(int number) {
        this.number = number;
    }

    public String toString() {
        return String.valueOf(number);
    }
}

그래서 위와같이 Comparable의 구현체를 넘겨주지 않으면 에러가 발생한다.

 

public class Main {
    public static void main(String[] args) {
        MyNumber[] nums =  new MyNumber[10];
        for (int i = 1; i < nums.length+1; i++) {
            nums[i-1] = new MyNumber(31 % i);
        }

        Arrays.sort(nums);
        System.out.println(Arrays.toString(nums));		//[0, 1, 1, 1, 1, 1, 3, 3, 4, 7]
    }
}

class MyNumber implements Comparable<MyNumber> {
    int number;

    public int compareTo(MyNumber o) {
        return number - o.number;
    }

    public MyNumber(int number) {
        this.number = number;
    }

    public String toString() {
        return String.valueOf(number);
    }
}

그래서 정렬을 원하는 객체가 Comparable을 구현하여 compareTo() 메서드를 오버라이딩하면, 그 객체에 아무런 설정도 하지 않았을 때의 기본 정렬기준이 되는 것이다.


만약, 기본정렬기준이 없거나 기본정렬기준과 다르게 정렬하고 싶다면 Comparator를 사용하면 된다. Comparable은 객체 내부에서 정렬 기준을 선언했지만 Comparator를 사용하면 Comparator을 구현한 외부 클래스를 넣어주면 된다.

 

public class Main {
    public static void main(String[] args) {
        MyNumber[] nums =  new MyNumber[10];
        for (int i = 1; i < nums.length+1; i++) {
            nums[i-1] = new MyNumber(31 % i);
        }

        Arrays.sort(nums, new CompareMN());
        System.out.println(Arrays.toString(nums));		////[0, 1, 1, 1, 1, 1, 3, 3, 4, 7]
    }
}

class CompareMN implements Comparator<MyNumber> {
    @Override
    public int compare(MyNumber m1,  MyNumber m2) {
        return m1.number - m2.number;
    }
}

class MyNumber{
    int number;

    public MyNumber(int number) {
        this.number = number;
    }

    public String toString() {
        return String.valueOf(number);
    }
}

이렇게 Comparator를 구현한 클래스를 sort() 메서드의 인자로 넣어주면 이걸 참고하여 배열을 정렬한다.

위에서 말했듯이 Comparator 구현체를 넘겨주지 않을 경우에는 배열 속 객체의 compareTo() 메서드를 통해 정렬한다.

 

public class Main {
    public static void main(String[] args) {
        MyNumber[] nums =  new MyNumber[10];
        for (int i = 1; i < nums.length+1; i++) {
            nums[i-1] = new MyNumber(31 % i);
        }

        Arrays.sort(nums, new CompareMN());
        System.out.println(Arrays.toString(nums));		//[7, 4, 3, 3, 1, 1, 1, 1, 1, 0]
    }
}

class CompareMN implements Comparator<MyNumber> {
    @Override
    public int compare(MyNumber m1,  MyNumber m2) {
        return m2.number - m1.number;
    }
}

class MyNumber{
    int number;

    public MyNumber(int number) {
        this.number = number;
    }

    public String toString() {
        return String.valueOf(number);
    }
}

Comparator가 가장 많이 쓰이는 예시가 내림차순 정렬이다.

 

위에서는 코드 재사용을 위해서 MyNumber 클래스를 사용했지만, Integer 클래스를 사용할 때 가장 기본적인 정렬기준은 오름차순 정렬이다. 만약 내림차순으로 정렬하고 싶다면 Integer 클래스의 파일을 수정하거나 상속해서 새로운 Integer 객체를 만들고 거기서 compareTo()를 오버라이딩 해야하는데, 전자는 다른 Integer 객체에 어떤 영향을 미칠지 알 수 없으며, 후자는 원래 Integer가 상속이 불가능하다.

 

따라서 compareTo()를 만지지 않고 정렬기준을 변경하는 법으로 Comparator 클래스라는 정렬기준을 넘겨주어 원하는 방향으로 정렬하면 된다.

 

보통은 자주 쓰이는 정렬기준을 Comparable로 구현해서 넣어두는 편이고, 자주 쓰이지 않거나 기본정렬기준과 다른 정렬기준이 필요할 때만 Comparator를 사용하는 편이다. 뒤에서 나오지만 Comparator는 람다식을 사용할 수 있기 때문에 Comparator가 더 자주 사용되는 편도 있고.


int[] arr = {3, 1, 7, 8, 9};
int idx = Arrays.binarySearch(arr, 1);

System.out.println(idx);	//-1

BinarySearch는 해당 요소가 배열에 어디에 있는지 검사한다.

단순히 1번 요소부터 하나하나 찾는 것이 아닌, (순차검색(linear search)) 이진검색(BinarySearch)를 통하여 요소를 찾는다. 이진탐색을 하면 배열의 중간값이 찾으려는 값보다 큰지 검사해 찾으려는 값이 있는 부분에서 다시 중간값을 검사하고... 이런식으로 검사할 요소를 반 씩 줄여나가며 요소를 찾는다.

 

int[] arr = {3, 1, 7, 8, 9};
int idx = Arrays.binarySearch(arr, 1);
System.out.println(idx);		//-1

Arrays.sort(arr);
idx = Arrays.binarySearch(arr, 1);

System.out.println(idx);		//0

이진검색이 순차검색보다 좀 더 빠른 편이지만, 정렬이 된 경우에서만 사용할 수 있다. 위에서처럼 엉뚱한 인덱스 값이 출력되기 때문에 정렬 후에 사용해야한다.


비교 및 출력 - equals() | toString() | compare() | mismatch()

toString은 Object 클래스의 그 메서드이다. 배열의 모든 요소를 문자열로 출력한다. 단, 일차원 배열에서만 사용가능하고 다차원배열에서는 deepToString() 을 사용해야 toString()을 구현할 수 있다.

 

public class Main {
    public static void main(String[] args) {
        MyNumber[] nums =  new MyNumber[10];
        for (int i = 1; i < nums.length+1; i++) {
            nums[i-1] = new MyNumber(31 % i);
        }

        System.out.println(Arrays.toString(nums));
        //[MyNumber@776ec8df, MyNumber@4eec7777, MyNumber@3b07d329,
        MyNumber@41629346, MyNumber@404b9385, MyNumber@6d311334,
        MyNumber@682a0b20, MyNumber@3d075dc0, MyNumber@214c265e, MyNumber@448139f0]

    }
}

class MyNumber {
    int number;

    public MyNumber(int number) {
        this.number = number;
    }
}

Arrays.toString()은 배열 내 객체의 toString() 메서드를 호출시키는 방향으로 동작한다.

그래서 객체가 toString()을 오버라이드 하지 않고 그대로 배열에 넣은 다음 이 메서드를 호출하면 가장 기본적인 출력방식인 클래스명@16진수 해시코드 값을 뱉는다.

 

equals는 두 배열의 요소를 검사해 같으면 true, 다르면 false를 반환하나 다차원배열에서는 deepEquals()를 사용해야한다.배열을 돌면서 배열 내 요소마다 .equals() 메서드를 호출하기 때문에 이를 오버라이딩하지 않거나 다차원배열에서는 인스턴스 변수나 요소의 값이 동일하더라도 주소값이 같은지 조사하기 때문에 false가 반환될 수 있다.

 

compare는 두 배열의 크기를 비교한다. 뒤에 요소가 더 크면 -1, 앞에 요소가 더 크면 1, 같으면 0을 반환한다. 위에서 한 것과 크게 다르지 않다.

 

mismatch()는 두 배열의 값이 일치하지 않는 첫 번째 인덱스 주소를 반환한다. 다 다르면 -1을 반환한다.


List로 변환 - asList()

배열을 List로 변환한다. 인자로 배열을 넣어도 상관없고, List로 만들고 싶은 값들을 ,로 구분해서 넣어주어도 된다. 단 값이 한 개만 들어가면 에러가 발생한다.

 

또 중요한 점은 asList()를 통해 생성한 List<>는 오직 읽기만 가능하다. 값을 수정하거나 삭제할 수 없다.


https://dev-dx2d2y-log.tistory.com/127

 

[CS] 자바의정석 독서 #18 - 컬렉션은 무엇인가?

이전까지는 String, StringBuffer, StringBuilder를 읽어봤고, 원래 그 다음은 내용은 Math 클래스와 BigInteger, BigDecimal, 포맷팅, 날짜형식 등이 있었는데, 솔직히 좀 속성으로 자바에 대해 알아보고 싶기도하

dev-dx2d2y-log.tistory.com

https://dev-dx2d2y-log.tistory.com/128

 

[CS] 자바의정석 독서 #19 - ArrayList, Vector, LinkedList

보통 개발유튜브 같은 곳에서 "프로젝트는 어떻게 진행해야할까요? 뭐부터 시작해야할까요? 그냥 완벽히 공부하고 시작하면 안될까요?"라는 질문에 대해서 "그냥 시작해라"라고하는데, 그래서

dev-dx2d2y-log.tistory.com

https://dev-dx2d2y-log.tistory.com/130

 

[CS] 자바의 정석 독서 #20 - 스택과 큐 in Java

앞으로 스택과 큐에 대해서 다뤄볼 건데,스택과 큐는 '특정 조건을 만족하기만하면 스택 또는 큐이다.'라는 것이다. 큐의 구현체로는 LinkedList가 있는데, LinkedList는 큐의 '가장 처음 저장한 데이

dev-dx2d2y-log.tistory.com

https://dev-dx2d2y-log.tistory.com/131

 

[CS] 자바의 정석 독서 #21 - 이터레이터

리스트의 메서드를 살펴보다보면 ListIterator라는 자료구조가 등장하는데, 이는 Iterator의 성능을 향상시킨 버전이다.이터레이터는 컬렉션의 상위클래스이며, 구버전으로는 Enumeration이 있다. 즉,

dev-dx2d2y-log.tistory.com

이렇게 컬렉션 프레임웍에 대해서 알아보고,

컬렉션 프레임웍에 해당하는 List에 대해서 알아보았다.

 

이제 세 가지 컬렉션의 하위 클래스들인 List, Set 중에서 하나를 끝냈다. 이제는 Set을 하고, 몇 가지 컬렉션에 적용할 수 있는 메서드들이 있는 클래스에 대해서 알아보고 11장이 끝날 예정이다. 컬렉션은 중요한데 좀 잘 알아두자.

 

발화는 컬렉션을 다루긴할텐데 너무 딥하게 들어가면 좀 루즈해질 수도 있는데 좀 고려해보기로

'언어공부 > Java | Kotlin' 카테고리의 다른 글

[Java] 자바의 정석 독서 #24 - 해싱과 해싱함수  (0) 2025.12.03
[Java] 자바의 정석 독서 #23 - HashSet과 HashMap  (0) 2025.12.01
[CS] 자바의 정석 독서 #21 - 이터레이터  (1) 2025.11.22
[CS] 자바의 정석 독서 #20 - 스택과 큐 in Java  (0) 2025.11.22
[CS] 자바의정석 독서 #19 - ArrayList, Vector, LinkedList  (1) 2025.11.21
'언어공부/Java | Kotlin' 카테고리의 다른 글
  • [Java] 자바의 정석 독서 #24 - 해싱과 해싱함수
  • [Java] 자바의 정석 독서 #23 - HashSet과 HashMap
  • [CS] 자바의 정석 독서 #21 - 이터레이터
  • [CS] 자바의 정석 독서 #20 - 스택과 큐 in Java
Radiata
Radiata
개발을 합니다.
  • Radiata
    DDD
    Radiata
  • 전체
    오늘
    어제
    • 분류 전체보기 (211)
      • 신년사 (3)
        • 2025년 (2)
        • 2026년 (1)
      • CS (59)
        • JVM (12)
        • 백엔드 (20)
        • 언어구현 (1)
        • 객체지향 (1)
        • 논리회로 (5)
        • 컴퓨터구조 (9)
        • 데이터베이스 (1)
        • 컴퓨터 네트워크 (10)
      • 언어공부 (64)
        • Java | Kotlin (48)
        • JavaScript | TypeScript (9)
        • C | C++ (6)
      • 개인 프로젝트 (11)
        • [2025] Happy2SendingMails (3)
        • [2026] 골든리포트! (8)
        • [2026] 순수자바로 개발하기 (0)
        • 기타 이것저것 (0)
      • 팀 프로젝트 (29)
        • [2025][GDG]홍대 맛집 아카이빙 프로젝트 (29)
      • 알고리즘 (13)
        • 백준풀이기록 (11)
      • 놀이터 (0)
      • 에러 수정일지 (2)
      • 고찰 (24)
        • CEOS 23기 회고록 (2)
  • 블로그 메뉴

    • CS
    • 언어공부
    • 개인 프로젝트
    • 팀 프로젝트
    • 알고리즘
    • 고찰
    • 신년사
    • 컬러잇 개발블로그
  • 링크

    • 컬러잇 개발블로그
  • 공지사항

  • 인기 글

  • 태그

    144
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
Radiata
[CS] 자바의 정석 독서 #22 - Arrays로 배열 다루기
상단으로

티스토리툴바