회고록 블로그

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

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

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

김간장 2021. 12. 3. 21:06

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

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

 

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

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

cafe.naver.com


1.Object 클래스의 finalize 메소드

- 프로그래머는 잘 쓰지 않는 메소드이고 JVM이 많이 사용하는 메소드임

   → 가비지 컬렉션될 때 자동으로 호출되는 메소드임

   → 좀 더 쉽게 말하면 인스턴스 소멸 시 자동으로 호출되는 메소드임

 

- 따라서 finalize 메소드를 자식클래스에서 오버라이딩해서 [인스턴스 소멸 시에 수행하고 싶은 코드]를 담아놓을 수도 있음

 

# 가비지 컬렉션의 과정 복습

- JVM이 가비지 컬렉션을 자주하면 힙 영역에 사용할 수 있는 공간이 널널해짐

- 다만 가비지 컬렉션을 자주하면 프로그램의 속도가 느려지게 됨

   → 따라서 가비지 컬렉션은 [적당히] 하는 것이 좋음

   → 그리고 JVM이 적당한 알고리즘을 통해 가비지 컬렉션을 적당히해줌

   → 여기에서 "적당히"란, 힙 공간이 견딜 수 있고 + 프로그램의 성능에 큰 영향을 주지 않는 정도를 말함

 

- 가비지 컬렉션은 아래와 같은 과정을 거침

   → 일단 JVM이 힙 영역을 쭉 훑으며 가비지 컬렉션 대상이 있는지 찾음

   → 대상을 찾게 되면 표식(체크 등)을 남겨놓음

   → 만약 프로그램 실행에 있어서 여유가 없다면

        가비지 컬렉션 작업은 여기에서 잠시 멈춰두고, 프로그램을 먼저 이어서 실행시킴(프로그램 실행하는데 CPU를 양보함)

   → 중간에 여유가 좀 생기면 체크 해놓은 대상들을 삭제해줌

 

- 따라서 가비지 컬렉션 과정은 두 단계로 나뉠 수도 있음

   → 여유가 있다면 1)대상을 찾아 체크하기, 2)체크된 대상 삭제하기를 연결해서 처리하겠지만

   → 여유가 없다면 1)번만 먼저 처리해놓고 여유가 생겼을 때 2)번을 처리함

   → 왜냐하면 가비지 컬렉션을 실행하기 위해서는 JVM이 관리하는 프로그램들의 실행을 멈춰야하기 때문

        (사실, 메모리의 저장된 많은 객체들이 스캔+삭제되어야하니 프로그램의 실행을 멈추는건 당연함)

##

 

- finalize 메소드는 "1)가비지 컬렉션 대상을 찾아 체크할 때" 호출되는 것이 아니라 "2)체크된 대상을 삭제할 때" 호출된다는 점 유의

   → 그래서 정확하게 finalize 메소드가 호출되는 시점을 유추하기 어려움

        (JVM이 언제 가비지 컬렉션을 수행하는지 정확하게 알기 어렵기 때문)

   → finalize 메소드가 호출되지 않고 프로그램이 종료될 수도 있음

        * 만약 힙 영역의 공간이 널널한 상태에서 프로그램이 종료된다면

           JVM은 굳이 가비지 컬렉션을 수행한 후 프로그램을 종료하지 않음 (프로그램이 종료되면 힙의 공간이 통째로 비워지기 때문)

   → 그래서 프로그래머 입장에서 이 메소드를 적극적으로 사용하기가 곤란함

        (확신할 수 없는 메소드를 얼마나 적극적으로 사용할 수 있겠는가..)

 

# 참고사항으로 알아둘 점

- 임의의 메소드를 자식클래스에서 오버라이딩해서 사용한다고 가정(finalize 메소드 등)

- 이때 부모클래스의 해당 메소드에 (예상치 못한) 어떤 중요한 코드가 포함되어 있을 수 있음

- 그러므로 오버라이딩 할 땐 부모클래스의 메소드 코드를 함부로 무시해서는 안됨

 

- 더구나 Object 클래스 같은 경우 모든 객체의 부모클래스로 중요한 코드가 있을 수 있음

 

- 부모클래스의 메소드 코드를 읽었을 때, 정체를 잘 모르겠지만 어쨌든 메소드 오버라이딩을 반드시 해야하는 상황이라면

   super 키워드를 통해 부모클래스의 메소드를 호출하는것도 괜찮은 방법일 수 있음

...
@Override
protected void finalize() {
	super.finalize();
    ...
}

##

 

2. 가비지 컬렉션 수행 요청 코드

- 보통 JVM이 자동으로 가비지 컬레션 작업을 수행하지만 프로그래머가 JVM에게 가비지 컬렉션을 요청(?)할 수도 있음

- 코드는 아래와 같음

   → 하지만 보통 프로그래머가 가비지 컬렉션 요청을 호출하는 경우는 별로 없다고 함

System.gc(); // 가비지 컬렉션 대상을 찾아 체크(mark)해달라는 요청
System.runFinalization(); // 체크(mark)한 대상을 삭제해달라는 요청

- 코드를 넣었다고 하더라도 그 코드를 읽은 순간에 100% 가비지 컬렉션을 수행한다고 보장할 수는 없음

   → [요청]일 뿐이지 수행 [명령]이 아니기 때문

 

 

3. equals 메소드

- equals와 "=="의 차이

   → equals 메소드와 == 연산자는 모두 참조값을 비교한다는 공통점이 있음

   → 다른 점이 있다면, equals 메소드는 오버라이딩해서 사용할 수 있음

 

- 예시 코드

   → "[obj1]은 [obj2]와 동일한가"에 대해서 묻는 코드

   → 결과는 "False"

         * obj1과 obj2가 가리키는 인스턴스가 다르기 때문

           (두 객체에 저장되어 있는 값이 동일하더라도 각각 인스턴스를 생성했기 때문에 다른 참조값 가리킴)

Object obj1 = new Object();
Object obj2 = new Object();

if(obj1.equals(obj2))
	System.out.println("Same");
else
	System.out.println("Not Same");

 

- equals 메소드 오버라이딩 예시

 

- String 클래스의 equals 메소드

   → String 역시 Object의 자식클래스이기 때문에 equals 메소드를 사용하고 있음

   → 다만 String 클래스 내부에서 equals 메소드를 오버라이딩 이미 해놓음

   → String 클래스의 equals 메소드는 "두 인스턴스의 내용을 비교하도록" 오버라이딩이 되어있음

String 클래스의 equals 메소드 자료 (출처 : Java SE 16 API Documentation)

 

- String 인스턴스의 equals 메소드 예시

 

4. clone 메소드

- 역시나 Object 클래스에 정의되어 있는 메소드임

- 일단 하는 기능은 "대상과 (완전히) 똑같은 인스턴스를 복사"하는 기능을 함

- 임의의 클래스를 복사하기 때문에 clone 메소드의 반환형은 Object임

Object obj1 = new Object();
Ojbect obj2 = obj1.clone(); // 이 자리에는 "복사된 인스턴스의 참조값"이 반환됨

 

- 사실 인스턴스를 복사하는 것은 조금 주의가 필요함

 

- 그렇기 때문에 Java에서는 clone 메소드 호출을 허용하려면 프로그래머가 "Cloneable 인터페이스"를 구현해야함

   → Cloneable 인터페이스를 구현한다는 것은 "clone 메소드 호출을 허용한다"는 의미를 담고 있음

   → [주의] Cloneable 인터페이스에 clone 메소드가 선언되어 있다는 의미가 아님

         * Cloneable 인터페이스는 마커 인터페이스임(추상 메소드/몸체가 없는 인터페이스)

   → [주의] Cloneable 인터페이스를 구현하지 않는다고해서 clone 메소드가 메모리에 없다는 뜻도 아님

        (모든 객체는 Object 클래스를 상속하며, clone 메소드는 Object 클래스의 메소드이기 때문)

   → 다만 clone 메소드를 호출하려면 Cloneable 인터페이스를 구현해야함

 

- 코드 예시

   → clone 메소드의 접근수준 지시자는 기본적으로 protected인데, 그대로 두면 외부에서 사용할 수가 없음

   → 따라서 오버라이딩 해야함

- 반환형이 Object이기 때문에 참조타입을 Fish형으로 하는 경우 형변환이 필요함

 

# 참고사항. 메소드 오버라이딩

- [오버라이딩]은 반드시 '동작 방법'을 변경/수정해야만 사용할 수 있는 것은 아님

- 접근수준 지시자를 넓힐 때도 사용할 수 있음

- 예시

...
	@Override
	public Object clone() throws CloneNotSupportedException {
    // protected인 접근수준 지시자를 public으로 넓히고 있음
		return super.clone(); // 부모클래스의 clone 기능을 그대로 return할 뿐 변경된 사항은 없음
	}
...

- 다만, public을 private으로 변경하는 것은 불가능하고(=좁히는 것은 불가능)

   private을 public으로 변경하는 것은 가능함(=넓히는 것은 가능)

##

 

Comments