Java

[Java] 09. 객체 생성과 제거

Joo.v7 2024. 8. 30. 19:32

Chapter 1: 생성자

  • 객체 생성
  • 기본 생성자 사용
  • 생성자 오버라이딩
  • 생성자 오버로딩

Chapter 2: 데이터 초기화

  • 초기화 목록
  • 상수 선언
  • private 생성자
  • static 생성자

Lab 9-1 객체 생성

Chapter 3: 객체와 메모리

  • 객체 생명주기
  • 객체와 범위
  • 가비지 컬렉션

Chapter 1: 생성자

 생성자: 객체 생성시에 객체를 초기화하는데 사용되는 메소드.

 메소드 종료 2가지: 모든 statement 실행, return

객체 생성

  1. 메모리 할당: new 키워드를 사용하여 Heap 영역에 메모리 할당.
  2. 생성자를 사용하여 객체 초기화: 클래스 이름과 괄호 사용.
Date now = new Date();

 

기본 생성자 사용

  • 클래스에 생성자를 명시적으로 작성하지 않으면 컴파일러가 기본 생성자가 제공한다.
  • 생성자 구문
    • public
    • 클래스와 이름 동일
    • return 타입이 아예 없다. (void 아님)
    • 파라미터가 없다.
    • 모든 필드는 기본 값으로 초기화: 숫자형(int, float...) 필드 -> 0, boolean -> false, 참조 타입 -> null
class Date {
    public Date() { … }
}

class Date {
    private int year, month, day;
}

/* 컴파일러가 기본 생성자를 제공. */
class Test {
    public static void main(String[] args) {
        Date today = new Date();
    }
}

 

생성자 오버라이딩

  • 기본 생성자를 직접 작성
  • 생성자에서 초기화하지 않은 필드는 기본 값으로 초기화됨.

 

생성자 오버로딩

  • 오버로딩: 시그니처(메소드 이름, 파라미터 타입/개수)에 따라 다른 메소드 호출하는 것.
  • 생성자는 메소드이므로, 오버로딩 가능
    • 같은 범위, 같은 이름, 다른 파라미터를 사용하의 정의
    • 객체가 다른 방법으로 초기화 되는 것을 허용
  • 주의: 생성자를 정의하면, 컴파일러는 기본 생성자를 정의하지 않는다.
public class Date {
    private int year, month, day;
    
    public Date() {
        this(1998,12,18); // 초기화 목록 사용.
    }

    public Date(int year, int month, int day) { // 생성자 오버로딩
        this.year=year;
        this.month=month;
        this.day=day;
    }

    public String toString() {
        return this.year + "-" + this.month + "-" + this.day;
    }
}

class Test {
    public static void main(String[] args) {
        Date date = new Date();
        System.out.println(date.toString());

        Date date2 = new Date(1993, 1, 1);
        System.out.println(date2.toString());
    }
}

 

실행 결과

1998-12-18
1993-1-1

 

 

 

Chapter 2: 데이터 초기화

초기화 목록

  • 오버로드 된 생성자는 같은 코드를 포함할 가능성이 높다.
    • 생성자를 서로 호출하도록 리팩토링.
    • this 키워드를 사용하여 초기화 목록을 호출.
class Date {
    private int year, month, day;
    public Date() {
        this(1971, 04, 28);
    }

    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
}

 

  • 제한 사항
    1. this 키워드를 사용해서 생성자를 호출하는 것은 생성자에서만 할 수 있다.
    2. 초기화 목록에서 자신을 호출할 수 없다.
    3. this를 파라미터로 사용할 수 없다.
/* 제한사항 - 1 */
class Date {
    public Date(int year, int month, int day) { … }
    void init(int year, int month, int day) {
        this(year, month, day);	// 컴파일 시 오류
    }
}

/* 제한사항 - 2 */
class Date {
    public Date(int year, int month, int day) {
            this(int year, int month, int day);	// 컴파일 시 오류
    }
}

/* 제한사항 - 3 */
class Date {
    private int year, month, day;
    public Date() {
        this(this(1971, 04, 28));
    }
}

 

상수 선언

  • 상수는 컴파일시에 초기화.
  • final 키워드를 사용하여 선언.
/* 상수(final) 사용 예시 */
public class Calculator {
    final double pi = 3.14;
    final double tau = pi * 2;

    public double getAreaOfCircle(double radius) {
        return radius * radius * pi;
    }

    public double getCircumference(double radius) {
        return radius * tau;
    }
}

 

private 생성자

  • private 생성자는 직접 생성을 원하지 않는 객체 생성을 막아준다.
    • 인스턴스 메소드 호출을 막는 경우의 클래스.
    • static 메소드의 호출만을 위한 클래스.
    • 공유 객체를 위한 데이터를 저장하는 클래스
  • 절차적 기능을 공유하는 유용한 방법.
class Math {
    public static double Cos(double x) { ... }
    public static double Sin(double x) { ... }
    private Math() { ... }
}

 

설명)

더보기

Cos나 Sin은 C언어에서 전역 함수로 쓰면 편하다. 하지만 Java에서 전역 함수는 허용되지 않고 무조건 클래스 내부에 선언되어야 한다. 클래스 내부에 함수를 배치하는 방식의 단점은 Sin과 Cos가 함수가 아닌 instance method가 된다는 것이다. 따라서 이 경우 Sin과 Cos를 사용하기 위해서 Math 클래스의 instance를 생성하고 instance 메소드로 Sin과 Cos를 호출해야 한다. 

/* instance method가 된 Sin과 Cos */
class Test {
    public static void main(String[] args) {
        Math math = new Math();
        double result = math.Cos(28);
        result = new Math().Sin(28);
    }
}

 

하지만 Sin과 Cos를 static method로 선언하면, 이름 공간이 정해진 함수와 유사하게 정의할 수 있다. static method는 정적으로 동작하므로, Class의 instance가 생성될 필요가 없다.

/* static method로 선언된 Sin과 Cos */
class Math {
         public static double Sin(double a) { … }
         public static double Cos(double a) { … }
	   private Math() {}
}

class Test {
    public static void main(String[] args) {
    // Math 클래스의 instance를 생성하지 않고 바로 호출 가능.
        double result = math.Cos(28);
    }
}

 

 

 

static 생성자

 Java는 static 생성자를 지원하지 않는다.

 

 

Singleton 패턴

더보기
  • 목적: 클래스가 단 하나의 instance를 가지도록 보장하고, 이에 대한 전역 access 지점을 제공하는 것.
  • 방법: private 생성자와 static 메소드를 사용하도록 클래스를 선언하는 것이 제안됨.
/* Singleton 예시 */
public class Singleton {
    private static Singleton singleton; // 클래스의 유일한 인스턴스를 저장할 정적 변수다.
    private int number;

    public synchronized int nextNumber() {
        return this.number++;
    }

    private Singleton() {}  // 클래스 이름과 똑같고 return type이 없는 것 : "생성자" 라는 메서드다.

    public static Singleton getSingleton() {    // 클래스의 유일한 인스턴스에 접근하는 방법을 가진 메서드.
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

 

Lab 9-1 객체 생성

2024.08.27 - [코딩 문제] - [코딩 문제] 은행 계좌 문제

 

[코딩 문제] 은행 계좌 문제

문제 1) BankAccount 클래스 캡슐화 - private, getter/setter문제 2) 계좌 번호 생성문제 3) withDraw, deposit 메소드 추가+ 추가) 계좌 이체 메소드 transferFromimport java.math.*;import java.util.*;public class BankAccount { priva

lightningtech.tistory.com

 

 

Chapter 3: 객체와 메모리

객체 생명주기

  • 객체 생성
    1. 메모리 할당: new 키워드를 사용하여 메모리(Heap)에 객체 할당.
    2. 생성자 호출: 생성자를 사용하여 객체 초기화.
  • 객체 사용
    1. In use or reachable(사용중): 객체가 생성되어 다른 객체에 의해 참조되어 있는 경우.
    2. Invisible(사용중이며 접근 불가): reference 되어 있으나 직접 접근할 수 없는 상태.
    3. Unreachable(사용되지 않음): reference가 존재하지 않는 경우이며 Garbage Collection의 후보가 된다.
  • 객체 제거
    1. Collected(Garbage Collector의 대상이 됨): 객체의 finalize가 정의되어 있는지 판단하고 finalize가 있다면 finalizer 큐에 넣고 없으면 다음 단계 진행.
    2. Finalized (제거): 객체 제거.
    3. Deallocated (메모리 해제): 메모리 반환.

설명) Mark & Sweep

더보기

객체는 생성되면 3단계를 거친다. in use -> invisible -> unreachable.

메모리가 부족하면 가비지 컬렉터가 unreachable부터 시작해서 필요한 경우 invisible 까지 걷어간다. 이후 객체 삭제하고 메모리 반환함. finalize라고 마크된 것들은 finalizer 큐에 넣어 놨다가 메모리가 부족 시점에 다 걷어간다.

 

Memory Leak (메모리 누수): 동적으로 할당된 필요 없는 것들이 메모리를 점유하고 있는 현상.

 

Java에서 memory leak은 더 이상 사용하지 않는 객체들이 Heap 영역에 남아 있어 불필요하게 메모리를 점유하고 있는 상황.

JVM의 Garbage Collector가 메모리 영역을 관리해준다.

 

객체와 범위

  • Local value의 수명은 선언된 범위(메소드, for, while문 ...)에 연결됨.
    • 결정론적 생성과 소멸: local value는 선언될 때 생성(stack 영역)되고 선언된 범위의 실행이 종료되면 즉시 소멸.
    • 일반적으로 짧은 수명: 메소드가 종료되며 값을 return하면, 그 값의 복사본이 반환되고 실제 값은 소멸.
  • Dynamic objet의 수명은 해당 범위에 연결되지 않음. (객체는 new 연산자를 통해 Heap 메모리에서 초기화됨)
    • 소멸 시기가 명확히 결정되지 않음: 객체의 생성 시점은 명확하지만, 생성된 범위의 실행이 끝나도 소멸되지 않음. (Java에서는 객체가 소멸되는 시기를 정확히 제어할 수 없다)
    • 더 긴 수명: 객체는 객체를 만드는 메소드에 연결되어 있지 않기 때문에, 단일 메소드 호출이 끝나도 계속 남아있을 수 있다.

 

가비지 컬렉션 (Garbage Collection)

  • 객체는 명시적으로 소멸시킬 수 없다.
  • 가비지 컬렉션이 객체를 제거.
    • 객체를 찾아 자동으로 제거.
    • 사용되지 않는 Heap 메모리를 반환.
    • 일반적으로 메모리가 부족할 때 Garbage Collection 작업 수행.

 


 

 

출처: https://github.com/gikpreet/class-programming_with_java/tree/master

 

GitHub - gikpreet/class-programming_with_java

Contribute to gikpreet/class-programming_with_java development by creating an account on GitHub.

github.com

 

 

'Java' 카테고리의 다른 글

[Java] Singleton 패턴  (0) 2024.08.31
[Java] 10. Java에서의 상속  (0) 2024.08.30
[Java] Getter / Setter 메소드  (0) 2024.08.28
[Java] 08. 참조 타입  (2) 2024.08.28
[Java] 07. 객체지향 프로그래밍 기본  (0) 2024.08.27