회고록 블로그

[공부 필기] Java 기본 공부하기 (31) 본문

2. 프로그래밍 언어 공부/Java

[공부 필기] Java 기본 공부하기 (31)

김간장 2021. 12. 14. 22:45

공부 중인 강의 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의.

링크 : https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com

 

※ 강의 청강 중 필요한 내용만 필기함

※ 틀린 필기가 있을 수 있음..

 


1. 배열의 정렬 : Arrays의 sort 메소드

- sort 메소드는 배열을 인자로 전달하면, 인자를 정렬해줌

   → 단, [오름차순]으로 정렬함

- 오버로딩이 잘 되어 있기 때문에 double형 배열, int형 배열 등 기본 자료형의 배열은 정렬 가능함

 

- 만약, 기본 자료형의 배열이 아니라 인스턴스가 요소로 저장된 배열을 오름차순으로 정렬해야한다면?

   → 숫자는 오름차순이라는 [정렬 기준]이 명확함

   → 하지만 인스턴스는?

         * 프로그래머가 [정렬 기준]을 명확하게 세워줄 필요가 있음

         * 몸무게가 많이 나가는 순으로 오름차순 정렬할 것인지, 키가 큰 순으로 오름차순 정렬할 것인지 등

- 이때 사용하는 메소드가 'compareTo' 메소드

   → Comparable 인터페이스에 유일하게 하나 있는 추상메소드임

[그림1] Comparable 인터페이스의 compareTo 추상 메소드

   → A보다 인자로 전달된 값 B가 더 작다면 양의 정수 반환

        인자로 전달된 값 B가 더 크다면 음의 정수 반환

        인자로 전달된 값 B와 동일하다면 0을 반환

A.compareTo(B);

 

- compareTo 추상 메소드를 정의하는 방법

   → Comparable 인터페이스를 구현

[그림2]

   → 사실 위의 if문을 아래와 같이 코드 한 줄로 구현할 수도 있음 (보통 아래와 같이 많이 구현함)

public class Gugudan implements Comparable {
	public int dan = 0;
...
	public int compareTo(Object obj) {
		Gugudan d2 = (Gugudan)obj;
		
        return this.dan - d2.dan; // this.dan이 더 크면 양의 정수 반환, 더 작으면 음의 정수 반환	
	}
}

 

 

- 그렇다면, 배열에 저장된 인스턴스를 정렬해보자

   → Arrays의 sort 메소드를 사용해서 오름차순 정렬을 할 수 있음

   → 하지만, 기본적으로 sort 메소드는 기본 자료형을 대상으로 오름차순 정렬을 해줌 (그림3 참고)

[그림3]

   → sort 메소드의 인자로 인스턴스가 저장된 배열을 전달하면 에러가 발생함 (그림4 참고)

         * ClassCastExcpetion 런타임 에러

[그림4]

   → 즉, 인스턴스가 저장된 배열을 오름차순 정렬하려면 이 에러를 해결해야하고

        이 에러의 해결방법은 앞서 학습한 Comparable 인터페이스와 compareTo 메소드에 있음

        * 앞서 학습한 것처럼 인스턴스가 저장된 배열은 [기준 정렬]이 명확하지 않아서 compareTo 메소드를 통해 [기준 정렬]을 정립하는 작업이 필요

 

 

- 인스턴스가 저장된 배열을 정렬하려면 아래와 같이 코드가 구현되어야함

   → Comparable 인터페이스 구현하고

   → compareTo 메소드를 정의해서 [기준 정렬]을 만듦

         * 여기에서는 year(연도)를 기준으로 내림차순 정렬

   → 그리고 toString 메소드를 통해서 정렬한대로 값을 출력함

[그림5] 예시

 

- 왜 compareTo 추상메소드를 정의해야 하는걸까

   → 왜냐하면 sort 메소드의 인자로 Object(객체)를 받으려면 Comparable 인터페이스가 구현되어 있어야 한다고

        Java API 문서에 기재되어 있기 때문

 

# 참고사항

나중에 디버깅하면서 Arrays의 sort(Object[] a) 메소드의 코드를 따라가봤다.

Arrays 클래스

ComparableTimSort의 sort 메소드로 가라고 한다.

ComparableTimSort 클래스

코드를 한줄씩 실행하다가 countRunAndMakeAscending 메소드로 가라고 한다.

ComparableTimSort 클래스

가봤더니 Comparable 인터페이스를 참조타입으로 둔 a 참조변수가 있었고

compareTo 메소드를 실행하도록 되어있었다.

그래서 쭉쭉 따라가보니 오버라이딩(Overriding)한 compareTo 메소드로 갔음.

그렇게 계속 메소드들을 호출하며 한줄씩 실행을 완료하더니

다시 ComparableTimSort의 sort 메소드로 돌아가서 뒤의 남아있던 코드를 실행했다.

binarySort 메소드까지 실행을 다 마친 후

for-each 코드 부분에서 System.out.println 메소드를 실행하니까 PrintStream 클래스의 println 메소드를 실행하게 됐고

PrintStream 클래스

String의 valueOf 메소드에 의해서 객체의 toString 메소드로 가게 되고..

사용자가 오버라이딩한 toString 메소드를 호출하게 됐다.

 

즉, compareTo 추상메소드를 정의한 이유는 Arrays의 sort 메소드에서 코드를 실행하고, 실행하다보면 compareTo 메소드를 호출 해야하기 때문이고

(모든 코드를 다 해석하지는 못해서 정확하지는 않지만.. 아마 인자로 받은 값을 하나씩 바이너리로 뜯어서 정렬하는 듯 하고

이때 [정렬 기준]이 있어야 하는데, 그 기준을 체크하기 위한 코드 부분에서 compareTo 메소드를 호출하는 듯 하다)

 

toString 메소드를 오버라이딩한 이유는 원하는 모양으로 출력하기 위해서였다.

(보통 println 메소드의 인자로 인스턴스를 전달하면 Object 클래스의 toString 메소드가 호출되기 때문에)

 

"인스턴스가 저장된 배열을 정렬"할 때 compareTo 메소드는 반드시 정의해야하지만

toString 메소드는 반드시 오버라이딩할 필요가 없었다...

##

 

 

Comments