배열안에 담겨있는 값(VO)들을 특정 기준으로 비교하여 순서를 정렬하기 위한 방법을 알아보자.
1. Car 객체
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package comparator;
public class Car {
private String name;
private int price;
public Car (String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
|
cs |
2. Car 객체 정렬 및 실행을 위한 Main 클래스
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package comparator;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Car c1 = new Car("K5", 2000);
Car c2 = new Car("A6", 8000);
Car c3 = new Car("BMW3", 4000);
Car[] cars = {c1, c2, c3};
Arrays.sort(cars);
for(Car tmp : cars) {
System.out.println(tmp.getName()+" ");
}
}
}
|
cs |
'정렬기준이 없는데?' 라고 생각 들 수 있겠지만 일단 실행시켜보자.
역시나 에러가 발생한다.
comparator.Car 가 java.lang.Comparable 로 캐스팅 될 수 없다는 캐스팅 에러.
Arrays.sort 내에서 comparator, comparable 을 사용하다 에러가 발생했다.
그럼 이제 Arrays.sort 를 탐구해보자.
※ Arrays.sort
아래는 java.util.Arrays 의 정적메소드 sort.
정확한 파악은 힘들지만 대충 살펴보았을 때 2번째 인자인 Comparator c 값의 유무에 따라 사용되는 메소드가 분기처리 되는 듯 하다.
1) 은 인자가 한개인경우 호출되는 메소드,
2) 는 인자가 두개인 경우 호출되는 메소드
1) Arrays.sort(배열) 일 경우 사용되는 method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
private static void mergeSort(Object[] src,
Object[] dest,
int low,
int high,
int off) {
int length = high - low;
// Insertion sort on smallest arrays
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low &&
((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
// Recursively sort halves of dest into src
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
mergeSort(dest, src, low, mid, -off);
mergeSort(dest, src, mid, high, -off);
// If list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
// Merge sorted halves (now in src) into dest
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
|
cs |
내부적으로 객체를 Comparable 로 형변환을 한 후 compareTo 메소드를 호출하여 값을 비교(정렬) 하고 있다.
첫번째 인자로 넘겨준 Car 객체는 Comparable(인터페이스) 를 구현하고 있지 않으므로 Comparable 객체로 형변환시 cast exception이 발생한 것이다.
그럼 Car 객체가 Comparable 인터페이스를 구현하도록 Car Class 를 아래와 같이 수정해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
package comparator;
public class Car implements Comparable<Car> {
private String name;
private int price;
public Car (String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public int compareTo(Car c) {
int comPrice = c.getPrice();
return this.price-comPrice;
}
}
|
cs |
다시 한 번 2번의 Main 클래스를 실행해보자
실행 결과는 아래와 같이 성공이다.
※ Car 객체의 compareTo 메소드의 return 부분(30 line : this.price-comPrice)
을 comPrice-this.price 와 같이 반대로 바꾸면 정렬 기준이 바뀐다(오름차순/내림차순).
위와 같이 VO 클래스를 Comparable interface 를 구현하도록 수정 후 compareTo 를 overriding 하면 원하는 방식으로 정렬을 시킬 수 있다.
VO 클래스를 이와 같이 매번 구현하여 사용하긴 번거로운데, 다른 방법은 없을까?
Arrays.sort 를 다시 한 번 들여다 보자.
2) Arrays.sort(배열, Comparator ?) 일 경우 사용되는 method가 아래와 같이 구현되어 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
private static void mergeSort(Object[] src,
Object[] dest,
int low, int high, int off,
Comparator c) {
int length = high - low;
// Insertion sort on smallest arrays
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
// Recursively sort halves of dest into src
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
mergeSort(dest, src, low, mid, -off, c);
mergeSort(dest, src, mid, high, -off, c);
// If list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
if (c.compare(src[mid-1], src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
// Merge sorted halves (now in src) into dest
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
|
cs |
내부적으로 인자값으로 넘어온 Comparator의 compare 메소드를 호출하여 값을 비교(정렬) 하고 있다.
Comparable 을 구현한 Car 객체는 원복 시킨 후, Main 클래스를 아래와 같이 수정해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package comparator;
import java.util.Arrays;
import java.util.Comparator;
public class Main {
public static void main(String[] args) {
Car c1 = new Car("K5", 2000);
Car c2 = new Car("A6", 8000);
Car c3 = new Car("BMW3", 4000);
Car[] cars = {c1, c2, c3};
System.out.println("sort start!");
Arrays.sort(cars, new Comparator<Car>(){
@Override
public int compare(Car c1, Car c2) {
//return c1.getPrice() - c2.getPrice();
return c2.getPrice() - c1.getPrice();
}
});
for(Car tmp : cars) {
System.out.println(tmp.getName()+" ");
}
}
}
|
cs |
Arrays.sort 의 두번째 인자값으로 Comparator 를 넘겨주었다. (익명클래스로 구현)
실행시 결과는 아래와 같다.
※ 사족 : Comparable, Comparator를 통해 바라본 인터페이스에 대해..
Arrays.sort 메소드는 내부적으로 파라미터 값으로 받은 객체의 compareTo 메소드 및 Comparable interface 의 compare 메소드를 사용하고 있다.
어떤 자료형의 파라미터 값이 넘어올지 Arrays 의 sort 메소드는 알 수 없지만 파라미터로 넘겨받은 객체 내에 compareTo 가 존재하리라 가정하고 소스가 짜여져 있다.
이처럼 인터페이스는 구현을 강제하며(Car 클래스의 compareTo 메소드) 소스간 결합도(Arrays.sort 와 Car클래스)를 약하게 한다. 또한 내공이 필요 하겠으나, 개발자들은 이를 활용하여 다양한 디자인 패턴의 개발을 할 수 있다..
'back > java' 카테고리의 다른 글
[Java] Compile (0) | 2019.12.22 |
---|---|
[Java] Collection Framework (0) | 2019.12.21 |
깊은복사(Deep Copy)와 얕은복사(Shallow Copy) (3) | 2019.08.31 |
LocalHost IP 가져오기 (0) | 2019.05.28 |
자바 컴파일 버전 Exception (Unsupported major.minor version 52.0) (0) | 2019.05.20 |