본문 바로가기

Java

Java- Arrays 클래스

배열의 복사


 새로운 배열 생성 후 반환

  - type[ ] copyOf(type[ ] original, int newLength)

  original에 전달된 배열을 첫번째 요소부터 newLength의 길이만큼 복사.

여러 자료형으로 오버라이딩 되어있음.

 

  - type[ ] copyOfRange(type[ ] original, int from, int to)

  original 배열의 인덱스 [from, to)의 내용을 가진 배열을 새로 생성해서 반환한다.

 

 기존 배열에 내용 복사

 - void arrayCopy(Object src, int srcPos, Object dest, int destPos, int length)

 배열 src의 srcPos 에서 배열 dest의 destPos로 length 만큼 복사.

 

배열의 비교


 - Arrays.equals(type[ ] a, type[ ] b)

 기본 자료형에서의 Arrays.equals(a, b)

import java.util.Arrays;

public class ArraysObjEquals2 {
    public static void main(String[] args) {
        int []arr1 = {1,2,3,4,5};
        int []arr2 = Arrays.copyOf(arr1,arr1.length);

        if(Arrays.equals(arr1,arr2))
            System.out.println("same");
        else
            System.out.println("different");
    }
}

//same

정상적으로 same이 나온다.

 

사용자 정의 클래스에서의 Arrays.equals(a,b)

import java.util.Arrays;

class Point{
    private int xpos;
    private int ypos;

    Point(int xpos, int ypos) {
        this.xpos = xpos;
        this.ypos = ypos;
    }
	
    @Override
    public String toString(){
        return "(" + xpos + "," + ypos + ")";
    }
}


public class ArraysObjEquals {
    public static void main(String[] args) {
        Point[] arr1 = new Point[3];
        Point[] arr2 = new Point[3];

        arr1[0]=new Point(1,1); arr2[0]=new Point(1,1);
        arr1[1]=new Point(1,1); arr2[1]=new Point(1,1);
        arr1[2]=new Point(1,1); arr2[2]=new Point(1,1);

        if(Arrays.equals(arr1, arr2)
        	System.out.println("same");
        else
        	System.out.println("different");
    }
}


//different

equals는 주소가 아닌 값을 비교하는 함수라서 new를 했다고 하더라도 same이 나와야 할 것 같은데 different나 나온다. 이는 Arrays.equals() 함수를 보면 알 수 있다.

 

Arrays.equals 함수중 인자가 Object로 오버로딩된 메소드

아래의 노란 o1.equals(o2)는 Object 클래스의 equals 메소드이다. 그리고 Object 클래스의 equals(Object obj)는 다음과 같이 정의되어 있다. 

 

Object 클래스의 equals 함수

 이게 문제인 것이다. Object 클래스의 equals 함수는 클래스의 내부 멤버 변수 값을 비교하는 것이 아니라 두 객체의 참조값을 비교하기 때문에 Arrays.equals(arr1, arr2)가 false가 나온 것이다.

 따라서 Point 클래스 내부에서 오버라이딩을 통해서 문제를 해결할 수 있다.

import java.util.Arrays;

class Point{
    	.
    	.
   	.
    @Override  //Arrays.equals()가 아니라 Object의 equals()를 오버라이딩
    // Object의 equals 메소드는 return (this == obj);라서 값을 비교하고 싶다면 이처럼 오버라이딩이 필요
    public boolean equals(Object obj){
        return (this.xpos == ((Point)obj).xpos &&
                this.ypos == ((Point)obj).ypos);
    }
}

public class ArraysObjEquals {
    public static void main(String[] args) {
        Point[] arr1 = new Point[3];
        Point[] arr2 = new Point[3];

        arr1[0]=new Point(1,1); arr2[0]=new Point(1,1);
        arr1[1]=new Point(1,1); arr2[1]=new Point(1,1);
        arr1[2]=new Point(1,1); arr2[2]=new Point(1,1);

        if(Arrays.equals(arr1, arr2)
        	System.out.println("same");
        else
        	System.out.println("different");
    }
}


//same

오버라이딩을 진행했더니 정상적으로 same이 나옴을 확인 가능하다.

 

배열의 정렬


  - Arrays.sort(type[ ] arr)

  사용법은 매우 간단한 sort() 메소드이다. 오름차순 정렬을 해준다.

 

기본 자료형에서의 sort

import java.util.Arrays;

public class ArraySort {
    public static void main(String[] args) {
        int []iArr = {1,4,65,23,12,42,-2,452};
        double []dArr = {42.1,23.2,93.1,-23.4,63.85};

        //sorting
        Arrays.sort(iArr);
        Arrays.sort(dArr);

        //print
        for(int i:iArr){
            System.out.print(i+"\t");
        }
        System.out.println();
        
        for(double i:dArr){
            System.out.print(i+"\t");
        }
    }
}

-2	1	4	12	23	42	65	452	
-23.4	23.2	42.1	63.85	93.1

 숫자 자료형 배열을 오름차순으로 정렬해주고 있다.

 

사용자 정의 클래스에서의 sort

 내가 임의로 정의한 클래스에서 sorting을 진행할 때는 사실 내가 어떤 것을 큰 것으로 둘 지에 따라서 sorting의 기준이 바뀐다. 그렇기에 sorting시 "크고 작음에 대한 판단 기준을 사용자가 직접 결정해야한다."

 예를 들어서 다음과 같은 Person 클래스가 있다고 하자. 그리고 이를 sorting 할 때에는 나이순으로 sorting을 한다.

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

class Person implements Comparable {  //Comparable 인터페이스 구현
    private String name;
    private int age;
    private int height;

    public Person(String name, int age, int height) {
        this.name = name;
        this.age = age;
        this.height = height;
    }

    public String toString(){
        return "-"+name+": "+age+"세, "+height+"cm";
    }

    @Override
    public int compareTo(Object o) {  // 구현부 (sorting 시 크고 작음의 기준)
        // o의 나이가 크면 리턴값 음수
        // o의 나이가 작으면 리턴값 양수
        // 서로의 나이가 같으면 리턴값 0

        int ageComp = this.age - ((Person)o).age;  //나이 비교 값
        return ageComp;
    }
}
public class ArrayObjSort {
    public static void main(String[] args) {
        Person p[] = new Person[4];

        p[0] = new Person("kim",21,171);
        p[1] = new Person("Lee",45,180);
        p[2] = new Person("Park",16,160);
        p[3] = new Person("Choi",21,154);

        Arrays.sort(p);

        for(Person person : p){
            System.out.println(person);
        }
    }
}


-Park: 16세, 160cm
-kim: 21세, 171cm
-Choi: 21세, 154cm
-Lee: 45세, 180cm

 

 지금보면 내가 직접 정의한 클래스 Person이 Comparable 인터페이스를 implements 하고 있음을 볼 수 있다. "Comparable 인터페이스"는 "크고 작음에 대한 판단 기준"을 정의할 때 사용하는 인터페이스이다.

 

 인터페이스 구현부를 보면 다음 추상 메소드를 볼 수 있다.

public int compareTo(Object o)

 

compareTo 추상메소드의 구현방법

 

 추상 메소드 compareTo(Object o)의 구현 방법은 다음과 같다.

  • 인자로 전달된 o가 작다면 양수 반환
  • 인자로 전달된 o가 크다면 음수 반환
  • 인자로 전달된 o와 같다면 0 반환

위의 구현 방법은 매우 중요하니 꼭 알고 있자!

 

 그리고 나는 위의 코드에서 아래과 같이 compareTo 메소드를 구현하였다.

@Override
    public int compareTo(Object o) {  // 구현부 (sorting 시 크고 작음의 기준)
        // o의 나이가 크면 리턴값 음수
        // o의 나이가 작으면 리턴값 양수
        // 서로의 나이가 같으면 리턴값 0

        int ageComp = this.age - ((Person)o).age;  //나이 비교 값
        return ageComp;
    }

사실상 return this.age - ((Person)o).age;로 구성된 메소드이다. 

 

1) o의 age가 this.age 보다 크다면 this.age - ((Person)o).age는 음수이다. 따라서 음수가 반환된다.

2) o의 age가 this.age 보다 작다면 this.age - ((Person)o).age는 양수이다. 그 결과 양수가 반환된다.

3) o의 age가 this.age와 같다면 this.age - ((Person)o).age는 0이다. 그 결과 0이 반환된다.

 

다른 compareTo의 추상메소드를 구현할 때에도 위와 같은 방식으로 구현하면 if else로 구현안하고 편하게 구현이 가능하다.

 

내림차순으로 구현

사실 이건 겁나 쉬운데 오름차순이 o가 크면 음수 반환, o가 작으면 양수, 같으면 0을 반환한다 했으니 이를 반대로 뒤집으면 내림차순으로 구현이 가능하다.

@Override
    public int compareTo(Object o) {
        /* 기존 오름차순 */
        // o의 나이가 크면 리턴값 음수
        // o의 나이가 작으면 리턴값 양수
        // 서로의 나이가 같으면 리턴값 0
        
        /* 내림차순 구현 */
        //위의 반대로 구현

        int ageComp = ((Person)o).age - this.age;  //기존과 반대로 뒤집음
        return ageComp;
    }

 

배열의 탐색


  -Arrays.binarySearch(type[ ] a, type key)

 binarySearch(a, key) 메소드는 배열 a에서 key라는 값을 가지는 인덱스를 반환하는 메소드이다.

그런데 이진탐색을 통해서  탐색을 진행하기 때문에 배열이 정렬이 먼저 되어있어야 한다.

 

 그리고 이 메소드가 key와 동일한 인스턴스를 찾았다고 판단하는 기준은 방금 전에 배운 compareTo 메소드의 반환값이 0이 되는지 여부이다. 따라서 이 메소드를 사용하기 위해선 compareTo 메소드가 상황에 맞게 오버라이딩 되어 있어야한다. 

 근데 웬만하면 예를 들어, 위 처럼 나이에 대해서 binarySearch() 메소드를 사용한다고 가정하자. 그러면 이미 나이에 대해서 정렬을 해야하니까 compareTo가 나이에 대해서 오버라이딩 되어 있을것이다. 그렇기에 웬만한 상황에서는 sorting 후 binarySearch() 사용일테니 오버라이딩을 크게 걱정할 필요는 없을 듯 하다. 

 

import java.util.Arrays;

class Person implements Comparable {  //Comparable 인터페이스 구현
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String toString(){
        return "-"+name+": "+age+"세";
    }

    @Override
    public int compareTo(Object o) {  // 구현부 (sorting 시 크고 작음의 기준)
        // o의 이름의 길이가 크면 리턴값 음수
        // o의 이름의 길이가 작으면 리턴값 양수
        // 서로의 이름의 길이가 같으면 리턴값 0

        return this.age - ((Person)o).age;  //이름 길이 비교 값
    }
}
public class ArrayObjSort {
    public static void main(String[] args) {
        Person p[] = new Person[5];

        p[0] = new Person("kim",21);
        p[1] = new Person("Lee",45);
        p[2] = new Person("Park",16);
        p[3] = new Person("Choi",21);
        p[4] = new Person("Jeon",23);

        //정렬 진행
        Arrays.sort(p);

        for(int i=0;i<p.length;i++){
            System.out.println((i)+"번 "+p[i]);
        }
        System.out.println();
		
        //21살인 사람의 인덱스 반환
        System.out.println(Arrays.binarySearch(p,new Person("who's age is 21",21)));  
    }
}

0번 -Park: 16세
1번 -kim: 21세
2번 -Choi: 21세
3번 -Jeon: 23세
4번 -Lee: 45세

2

'Java' 카테고리의 다른 글

Java- 제네릭(2)  (0) 2023.01.27
Java- 제네릭(1)  (0) 2023.01.07
Java- Random 클래스, 난수 생성  (0) 2023.01.06
Java- BigInteger, BigDecimal 클래스  (0) 2023.01.03
Java- 래퍼 클래스  (0) 2023.01.03