Arrays.sort() 메소드의 작동 원리와 활용 방법

Java에서 배열 정렬은 개발자들이 일상적으로 마주하는 작업 중 하나다. Arrays.sort(T[] array, Comparator<? super T> c) 메소드는 사용자 정의 객체 배열을 정렬할 때 사용하는 강력한 도구다. 이 메소드의 내부 동작 원리와 활용 방식을 살펴보자.

1. 기본 사용법

Comparator 인터페이스를 구현하면 객체 간 비교 로직을 정의할 수 있다. 다음 예제는Animal 클래스를 size 필드를 기준으로 정렬하는 방법을 보여준다.

import java.util.Arrays;
import java.util.Comparator;

class Animal {
    int size;
    
    public Animal(int s) {
        size = s;
    }
}

class SizeComparator implements Comparator<Animal> {
    @Override
    public int compare(Animal a1, Animal a2) {
        return a1.size - a2.size;
    }
}

public class SortExample {
    public static void main(String[] args) {
        Animal a1 = new Animal(5);
        Animal a2 = new Animal(2);
        Animal a3 = new Animal(8);
        
        Animal[] animals = {a1, a2, a3};
        printAnimals(animals);
        
        Arrays.sort(animals, new SizeComparator());
        printAnimals(animals);
    }
    
    public static void printAnimals(Animal[] arr) {
        for (Animal a : arr) {
            System.out.print(a.size + " ");
        }
        System.out.println();
    }
}

실행 결과:

5 2 8
2 5 8

2. 전략 패턴의 적용

전략 패턴은 런타임 시점에 다양한 알고리즘을 선택할 수 있게 해주는 설계 패턴이다. 정렬에서도 다양한 비교 기준을 적용할 수 있다는 점에서 전략 패턴의 적절한 활용 사례다.

예를 들어,Animal 클래스에 weight 필드가 추가된 상황을 가정해보자. size 기준과 weight 기준,两 가지 다른 비교 전략을 사용할 수 있다.

import java.util.Arrays;
import java.util.Comparator;

class Animal {
    int size;
    int weight;
    
    public Animal(int s, int w) {
        size = s;
        weight = w;
    }
}

class SizeComparator implements Comparator<Animal> {
    @Override
    public int compare(Animal a1, Animal a2) {
        return a1.size - a2.size;
    }
}

class WeightComparator implements Comparator<Animal> {
    @Override
    public int compare(Animal a1, Animal a2) {
        return a1.weight - a2.weight;
    }
}

public class StrategyPattern {
    public static void main(String[] args) {
        Animal a1 = new Animal(3, 30);
        Animal a2 = new Animal(1, 50);
        Animal a3 = new Animal(2, 20);
        
        Animal[] animals = {a1, a2, a3};
        
        System.out.println("정렬 전:");
        printAnimals(animals);
        
        Arrays.sort(animals, new SizeComparator());
        System.out.println("size 기준 정렬:");
        printAnimals(animals);
        
        Arrays.sort(animals, new WeightComparator());
        System.out.println("weight 기준 정렬:");
        printAnimals(animals);
    }
    
    public static void printAnimals(Animal[] arr) {
        for (Animal a : arr) {
            System.out.print("size=" + a.size + " weight=" + a.weight + " ");
        }
        System.out.println();
    }
}

실행 결과:

정렬 전:
size=3 weight=30 size=1 weight=50 size=2 weight=20 
size 기준 정렬:
size=1 weight=50 size=2 weight=20 size=3 weight=30 
weight 기준 정렬:
size=2 weight=20 size=3 weight=30 size=1 weight=50

3. 제네릭 타입 파라미터의 'super' 의미

메소드 시그니처에서 Comparator<? super T>를 사용하는 이유에 대해探讨해보자. 여기서 ? super T는 T 또는 T의 조상 타입을 의미한다.

이러한 설계가 유용한 이유는 동일한 Comparator를 여러 서브 클래스에서 재사용할 수 있기 때문이다.Animal을 상속받은 Cat과 Dog가 있을 때, Animal용 Comparator를 그대로 사용할 수 있다.

import java.util.Arrays;
import java.util.Comparator;

class Animal {
    int size;
    
    public Animal(int s) {
        size = s;
    }
}

class Cat extends Animal {
    public Cat(int s) {
        super(s);
    }
}

class Dog extends Animal {
    public Dog(int s) {
        super(s);
    }
}

class AnimalComparator implements Comparator<Animal> {
    @Override
    public int compare(Animal a1, Animal a2) {
        return a1.size - a2.size;
    }
}

public class SuperTypeDemo {
    public static void main(String[] args) {
        Dog d1 = new Dog(4);
        Dog d2 = new Dog(1);
        Dog d3 = new Dog(3);
        
        Dog[] dogs = {d1, d2, d3};
        printAnimals(dogs);
        
        Arrays.sort(dogs, new AnimalComparator());
        printAnimals(dogs);
        
        System.out.println();
        
        Cat c1 = new Cat(4);
        Cat c2 = new Cat(1);
        Cat c3 = new Cat(3);
        
        Cat[] cats = {c1, c2, c3};
        printAnimals(cats);
        
        Arrays.sort(cats, new AnimalComparator());
        printAnimals(cats);
    }
    
    public static void printAnimals(Animal[] arr) {
        for (Animal a : arr) {
            System.out.print("size=" + a.size + " ");
        }
        System.out.println();
    }
}

실행 결과:

size=4 size=1 size=3 
size=1 size=3 size=4 

size=4 size=1 size=3 
size=1 size=3 size=4

4. 핵심 정리

Arrays.sort()를 효과적으로 활용하기 위해 기억해야 할 핵심 포인트:

  • 제네릭 와일드카드: ? super T를 사용하면 상위 타입의 Comparator를 재사용할 수 있어 유연성이 높아진다
  • 전략 패턴: 다양한 비교 알고리즘을 런타임에 선택할 수 있다
  • 알고리즘: Java의 정렬 구현은 병합 정렬 기반이며 O(n log n) 시간 복잡도를 가진다
  • 유사 메소드: Collections.sort(List<T> list, Comparator<? super T> c)도 동일한 원리로 동작한다

태그: java arrays sort comparator generics

6월 17일 18:47에 게시됨