티스토리 뷰

JAVA

객체 생성을 막을때는 private 생성자

세댕댕이 2022. 7. 15. 23:31

4. 객체 생성을 막을 때는 private 생성자를 사용하라

정적 메소드나 필드를 모아놓고 사용하는 유틸리티 클래스의 경우는 객체를 만들 목적의 클래스가 아니다

- 대표적으로 java.lang.Math, java.util.Arrays, java.util.Collections

 

객체를 만들 생각이 없다고 생성자를 만들지 않으면..  객체 생성을 막을 수 있는 것이 아니라 디폴트 생성자가 만들어진다.

* 디폴트 생성자: 객체가 생성될 때 사용자가 초깃값을 명시하지 않으면 컴파일러가 자동으로 생성해주는 생성자

- NoArgsConstructor와 같음

 

클래스를 abstract추상 클래스로 만든다고 해도 소용없다.

-> 하위 클래스를 정의하면 객체 생성이 가능해지기 때문.

 

그럼 어떻게?

=> private 생성자를 만들어서 외부에서 객체 생성을 못하게 막아버리자

private 생성자를 가지고 있으므로 하위 클래스 상속도 불가능하고, 외부에서 호출도 불가능하다.

 

 

<모범 사례 - java.lang.Math class >

public final class Math {

    private Math() {}

    public static final double E = 2.7182818284590452354;
    ...
    
    public static int max(int a, int b) {
        return (a >= b) ? a : b;
    }
    ....
}

- final class이기 때문에 상속 불가

- private 생성자로 외부에서 생성 불가

- static 변수/메소드로 클래스 레벨에서 공유되어 사용

 

 

(+) final 키워드에 대해..

final 키워드는 값을 한번 할당한 이후에는 변경 불가능(immutable)함을 뜻한다.

 

final 클래스: 상속할 수 없는 클래스

final 메서드: 오버라이딩 불가능한 메소드

final 변수: 수정 불가능한 변수. static final 조합으로 상수로 많이 쓰임

 

"불변함" 이라는 것의 이점이 상당히 많다! 

* final 변수는 변수 선언 시에 or 생성자를 통해서만 할당해줄 수 있다.

* final 클래스라도 내부 변수가 final이 아니라면 setter 등을 통해서 값을 변경해줄 수 있다.

 

 

(++) 익명 클래스 or 람다식 내부에서 참조하는 외부 지역변수는 final 변수 or Effectively final 변수만 가능하다

- effectively final이란 Java 8에서부터 등장한 기능으로, final이 없어도 따로 변경이 없다면 final 변수로 간주해주는 기능

(객체의 경우에는 참조값만 바뀌지 않으면 된다)

- 익명 클래스나 람다식의 경우에는 멀티 스레드 환경에서 동작할 수 있기에, 메소드 종료 시점보다 더 늦게 실행될 가능성이 존재한다. 이 경우, 스택 영역에 저장되어있던 지역변수들이 메소드가 다 종료되면서 사라져 버리기에 람다식이 참조할 값이 없어져버림.

- 인스턴스 변수는 힙 영역에, 클래스 변수(static)는 메서드 영역에 저장되므로 final이 아니라도 접근 가능함.

public void method() {
    int val = 0;
    new Thread(() -> {
        try {
            Thread.sleep(90000);
            System.out.println(val);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
}

(위와 같은 상황을 방지하기 위함)

 

 

(+++) Java의 메모리 구조에 대해.. 

1. Method (= Class)

- 클래스, 인터페이스, 메소드, 클래스 변수(static) 정보가 저장되는 영역.

- 모든 스레드가 공유하여 사용

 

2. Heap

- new를 통해 생성된 인스턴스 객체(인스턴스 변수(전역변수) 포함)들이 저장되는 영역. 

- GC에 의해 회수되기 전까지는 사용되지 않아도 남아있음

- 모든 스레드가 공유하여 사용

 

3. Stack

- 메소드 내에서 사용되는 지역변수, 매개변수, 리턴값이 저장되는 영역.

- 메소드가 호출될 때 생성되고, 메소드가 종료되면 바로 사라짐

- 각 스레드마다 별개로 존재

 

4. PC Register: 현재 수행중인 JVM 명령어 주소 저장

5. Native Method Stack: 자바 외 다른 언어의 동작을 위해 할당된 영역

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함