본문 바로가기

JAVA

[이것이 자바다] 11 기본 API 클래스 (1) 객체비교 compare, 오름차순까지

* 본 포스팅은 제가 국비지원교육을 받으며 노션에 정리한 내용을 옮겨놓은 것입니다. 발전을 위한 피드백과 지적은 언제나 환영합니다.

11.2 java.lang과 java.util 패키지

11.2.1 java.lang 패키지

  • Object
  • System
  • Class
  • String
  • StringBuffer, StringBuilder
  • Math
  • Wrapper (Byte, Short, Charater, Integer, Float, Long, Boolean, Double)

 

11.2.2 java.util 패키지

  • Arrays
  • Calender
  • Date
  • Objects
  • StringTokenizer
  • Random

 

11.3 Object 클래스

11.3.1 객체 비교(equals())

  • 두 객체 비교하여 논리적으로 동등하면 true, 아니면 false
  • 같은 객체이건 다른 객체이건 상관없이 객체가 저장하고 있는 데이터가 동일함을 뜻함.
  • String 객체의 equals는 String 객체의 번지를 비교하는 것이 아니라, 문자열이 동일한지 판단
  • String 클래스가 equals를 재정의했기 때문!

 

equals( ) 메소드 재정의하기

  1. 들어온 값 (매개값) 과 기준 값이 동일한 타입인지확인

    (ex. obj instanceof Student)

  1. 동일하다면 타입변환

    (ex. Student st = (Student) obj)

  1. 동일하지 않다면 false

 

11.3.2 객체 해시코드(hashCode( ))

 

  1. hashCode( ) 메소드 실행해서 리턴된 해시코드 값이 같은지 판단 (똑같은 객체인지 아닌지)
  1. 해시코드 값이 같으면 equals( ) 메소드로 다시 비교
  1. hashCode( ) 에서 true 나와도 equals에서 false나오면 다른 객체

 

 

👉해시코드 재정의 필요성 

◈ 회원 아이디가 같으면 같은 객체이지만, 회원이라는 클래스 내에 캡슐화 되어있다. 
		
  new Member(id, pwd, name) 
  new Member(id, pwd2, name2) 
  ⇒ id 같지만 서로 다른 객체로 인식하게 됨 (객체 자체를 비교하면 다른 아이디로 인식한다) 
        
  ⇒ 해시코드로 분별 
    
◈ 똑같은 클래스를 복사했을지라도, 다른 컴퓨터로 컴파일하면 해시코드 값이 달라진다.
  → 통신이 안 됨.

 

 

해시코드값을 이용해서 객체의 동등성 여부를 판단한다. (p.461 ~462)

 

Key 클래스에 다음과 같은 해시코드 오버라이드 추가
  • 여기서 오버라이딩을 해주지 않으면 해시맵에서 key값으로 value값을 찾을 수 없다. (null이 나옴)
  • 해시코드로 number를 반환

 

정상적으로 "안주현" 출력

 

원래 데이터가 있는 1에 일지매를 넣으면 자동으로 수정됨. (덮어쓰기)

 

👉
결론 객체의 동등 비교를 위해서는 Object의 equals 메소드만 재정의하지 말고 hashCode 메소드도 재정의해서 논리적 동등 객체일 경우 동일한 해시코드가 리턴되도록 해야 한다.

 

 

11.3.3 객체 문자 정보(toString())

  • toString 메소드는 객체의 문자 정보를 리턴한다.
  • 기본적으로 "클래스명@16진수해시코드"로 구성된 문자 정보 ⇒ 실용적으로 쓰기 위해 오버라이딩
  • util 패키지의 Date 클래스도 toString 오버라이딩해서 현재 시스템의 날짜와 시간 리턴 (재정의 안 하면 이상한 코드나옴)

 

toString의 기능을 재정의
  • 재정의하고 나서는 .toString 없이 그냥 객체만 출력해도 알아서 toString메소드 호출해주는 마법!!!

 

부모클래스 호출하면 클래스@해시코드값 출력됨

⇒ 부모클래스 Object 의 toString 출력하면 아무 의미 없음

 

11.3.4 객체 복제(clone())

 

  • 원본 데이터를 복제하여 신뢰하지 않는 영역에 보내 작업해야할 때 복제본을 보냄
  • 데이터를 안전하게 보호하기 위해 존재

 

얕은 복제(thin clone)

 

  • 기본타입 - 값 복사
  • 참조타입 - 객체의 번지 복사
  • 얕은복제 (thin clone) : 단순히 필드값을 복사해서 객체를 복사하는 것

 

  • clone( ) 메소드로 복제를 하려면 원본 객체는 반드시 java.lang.Cloneable 인터페이스를 구현하고 있어야 한다.
  • 설계자가 복제를 허용한다는 의도적인 표시를 하기 위해 (Cloneable 구현되지 않았으면 clone 메소드 호출할때 CloneNotSupportedException 발생)

    ⇒ 예외처리 Cf. IO처리 (입출력), 네트웍, 데이터베이스는 예외처리 필수적으로 함

 

 

getMember 실행하면 오류 → 인터페이스를 구현하지 않았기 때문에

 

 

 

 

인터페이스 구현 후 오류가 나지 않음

 

복사가 됐다
  • Member 타입의 변수를 반환하는 getMember 메소드를 통해 clone을 만들고, original을 통해 getMember 메소드 소환

 

 

배열 값 추가
복제했는데 해시코드 값이 똑같음

 

배열의 실제 값을 출력 (Arrays.toString)

 

실행결과

 

배열 값을 바꾸면 두개가 같이 바뀐다.
  • 얇은 복제 (thin clone) : 기본형은 값을 복사하므로 clone이 바뀌면 원본 그대로. but, 참조형은 (배열) clone 바꾸면 번지만 복사되기 때문에 원본도 같이 변경된 주소를 갖는다.

 

 

깊은 복사로 수정

this.scores ⇒ 오리지널 을 그 길이만큼 복사하라

 

결과 → 오리지널 유지된다

copyOf를 사용하면 새로운 배열을 만들고 그 값을 for문을 이용해 복사한다. → 저장하고 있는 번지수가 다름. 그러므로 복사한 배열 값을 바꾼다고 해서 원본도 바뀌지 않는다.

 

But, copyOf를 사용하지 않으면 번지수만 복사해오기 때문에 복사한 개체가 값을 수정하면, 같은 주소를 참조하는 원본 데이터도 바뀐다.

 

예시2

 

Car 클래스에서 model 매개변수하는 생성자 만들기

 

Member 생성자에서 벤츠 모델의 Car 객체 생성

 

소나타라는 새로운 값을 clone에 대입했을때, 원본도 같이 바뀌는걸 볼수있다(얕은복사)

 

cloned.car = new Car(this.car.model);

자신이 가지고 있는 멤버 car 모델을 가지고 새로운 객체를 만들어서 클론에 대입.

 

이렇게 복제하면 두 값이 다르게 나온다.

 

11.4 Objects 클래스 (java.util.Objects)

  • 객체 비교, 해시코드 생성, null 여부, 객체 문자열 리턴 등의 연산을 수행하는 정적 메소드들로 구성된 Object의 유틸리티 클래스

 

11.4.1 객체 비교 (compare(T a, T b, Comparator<T>c))

  • Objects.compare 메소드는 두 객체를 비교자(Comparator)로비교해서 int값을 리턴한다.

 

Objects 클래스 - Compare

Student 클래스 생성 (sno : 학번)

 

학번 비교하는 클래스 & 메소드 제작

 

compare 오류 발생 → implements 안 해서.

 

구현한뒤 override 해보니 OK!

 

public interface Comparator<T> { int compare(T a, T b); // Comparator 인터페이스 형식 }

 

StudentComp 에서는 비교할 수 있는 타입이 <Student> 타입밖에 없다. 라는 뜻.

Comparator는 compare라는 추상메소드 하나만 가지고 있고, 그걸 재정의한것.

 

왜 재정의할수밖에 없는지?

→ 메소드를 지우면 StudentComp에서는 상속받는 추상메소드 compare를 구현해야된다는 경고창이 뜬다.

(재정의해야된다는 뜻)

 

compare는 외부로부터 두개의 변수를 받아온다

단순히 StudentComp를 생성했을뿐인데 첫번째 매개변수를 첫번째 compare에, 두번째 매개변수를 두번째 compare에 전달해줌.

 

결과화면 (s1에서 s2를 뺀 결과가 나온다)

 

 


선택 정렬(오름차순 정렬)

package h_api; import java.util.Arrays; public class SortExam { // 숫자형 배열값을 오름차순으로 정렬 public void numberSort() { int[] n = { 354, 632, 72, 45, 2, 6443, 5423, 6, 5345, 54, 34, 554, 634 }; System.out.print("정렬 전 : "); System.out.println(Arrays.toString(n)); int temp = 0; for (int i = 0; i < n.length - 1; i++) { // 비교 기준 for (int j = i + 1; j < n.length; j++) { // 비교 대상 if (n[i] > n[j]) { // 앞에 있는 값이 뒤에 있는 값보다 더 크면 자리 바꿔라 (swap logic) temp = n[i]; // front 값을 잠깐 대피시키고 n[i] = n[j]; // back 값을 front로 옮긴 뒤 n[j] = temp; // 대피시켰던 front를 뒤로 } // end of if } // j } // i System.out.print("정렬 후 : "); System.out.println(Arrays.toString(n)); } // 문자열형 배열값을 오름차순으로 정렬 public void strSort() { } public static void main(String[] args) { SortExam se = new SortExam(); se.numberSort(); } }
  • 내림차순은 부등호만 수정하면 됨.

 

 

i는 왜 길이-1까지이고 j는 length까지인지

 

i는 634까지 되면 비교할 대상이 없으므로 전체 길이 -1, j는 끝까지 비교대상이 되니까 전체길이 반복

 

 

문자열 정렬 결과화면 (compareTo 사용 - 문자를 숫자로 반환하여 뺌)

 

 

compare메소드 활용을 할것!

"compare 결과값이 양수면 뒤에 있는 값이 작은것이니 swaping 해라."

 

 

Student 타입으로 Student 배열에 값 집어넣었다

 

출력될 형식 정해주기 (학번 - 이름 - 점수)

 

int result = Objects.compare(n[i], n[j], new StudentComp());

n[i] 와 n[j] 값을 가져와서 new StudentComp 의 방법으로 비교한다.

 

@Override public int compare(Student s1, Student s2) { return s1.sno-s2.sno;

new StudentComp 의 방법 : n[i]에서 n[j]를 빼라

 

  • 뺀 결과값이 양수면 → 뒤에 있는 값이 더 작다는 것
  • 뺀 결과값이 음수면 → 뒤에 있는 값이 더 크다는 것

 

Uploaded by Notion2Tistory v1.1.0

 

Notion2Tistory

 

boltlessengineer.github.io

 

이것이 자바다 (신용권의 Java 프로그래밍 정복)

 

이것이 자바다

『이것이 자바다』은 15년 이상 자바 언어를 교육해온 자바 전문강사의 노하우를 아낌 없이 담아낸 자바 입문서이다. 자바 입문자를 배려한 친절한 설명과 배려로 1장에 풀인원 설치 방법을 제

book.naver.com