7-4. 제어자

Hyun Jun·2022년 1월 22일
0

자바의 정석

목록 보기
29/52
post-thumbnail
post-custom-banner

제어자 (modifier)

개념

클래스, 변수, 메서드의 선언부에 사용하여 부가적인 의미를 부여.

분류종류
접근 제어자public, protected, default, private
그 외static, final, abstract, native, transient, synchronized, volatile, strictfp

접근 제어자는 하나의 대상에 하나만 사용 가능. (그 외는 여러가지를 조합하여 사용 가능)

제어자의 순서는 자유지만, 일반적으로 접근 제어자를 가장 왼쪽에 둠.

 

static

static은 "클래스의" 또는 "공통적인"이라는 의미로 쓰임.

static이 붙은 멤버 변수와 메서드, 초기화 블럭은 클래스 관련 내용이기 때문에 인스턴스의 생성 없이도 사용 가능.

 

final

final은 "최종적인", "변경될 수 없는"의 의미로 쓰임.

final 클래스 변경될 수 없는 클래스
확장될 수 없는 클래스 (자손 X)
메서드 변경될 수 없는 메서드
오버라이딩 불가
멤버 변수 상수 (값 변경 불가)
지역 변수

 

생성자를 이용한 final 멤버 변수 초기화

상수는 일반적으로 선언과 초기화를 동시에 하지만, 인스턴스 변수는 생성자로 초기화를 따로 해줄 수 있음

class Card {
    final int NUMBER;
    final String KIND;

    Card(int number, String kind) {
        NUMBER = number; // 매개변수로 넘어온 값을 상수에 할당하여 초기화 (이제 변경 불가)
        KIND = kind;
    }
}

 

abstract

abstract는 "미완성의"라는 의미를 가짐.

선언부만 작성하고 수행 내용은 구현하지 않은 추상 메서드 선언에 사용.

클래스에 사용하여 클래스 내에 추상 메서드가 있다는 표시로 쓰기도 함. (추상 클래스)

 

abstract가 붙은 추상 클래스는 "미완성 설계도"이므로 인스턴스 생성 불가.

abstract class AbstractClass {
    abstract void abstractMethod(); // 추상 메서드
} // 추상 클래스

 

접근 제어자 (access modifier)

멤버 또는 클래스에 접근 제어자를 붙여 외부에서 접근할 수 있는 권한을 달리할 수 있음.

접근 제어자가 없으면 default 이므로 따로 명시하지 않아도 됨.

구분접근성
private같은 클래스 내에서만 접근 가능
(default)같은 패키지 내에서만 접근 가능
protected같은 패키지 내의 클래스, 또는 다른 패키지 내에 있는 해당 클래스의 자손 클래스에서만 접근 가능
public접근 제한 없음

 

대상에 따라 사용할 수 있는 접근 제어자도 다름.

  • 클래스: public, (default)

  • 메서드 & 멤버 변수: public, protected, (default), private

  • 지역 변수: 없음

 

접근 제어자를 이용한 캡슐화

주로 멤버에 접근 제어자를 사용하게 되는데, 이유는

  1. 클래스 내부에 선언된 데이터를 외부로부터 보호하기 위함

    데이터 감추기 (data hiding)

  2. 내부적으로만 사용될 부분은 보여질 필요가 없으므로 감추기 위함

    외부에서 굳이 접근할 필요가 없는 멤버들은 private으로 지정해 노출하지 않음

→ 둘 모두 객체지향의 캡슐화(encapsulation)에 해당하는 내용

 

예시)

public class Time {
    public int hour;
    public int minute;
    public int second;
}

Time 클래스와 인스턴스 변수들은 public으로 어디서든 접근할 수 있음

Time t = new Time();
t.hour = 28;

인스턴스 변수 hour는 0 이상 ~ 23 이하의 값을 가져야하지만, 범위를 초과한 값 설정을 막을 방법이 없음

이럴 경우 멤버 변수들을 private 혹은 protected로 제한하고 public 메서드를 하나를 정의하여 이 메서드를 통해서만 값을 변경할 수 있게 하는 것이 바람직함.

public class Time {
    private int hour;
    private int minute;
    private int second;

    public int getHour() { return hour; } // 멤버 변수의 값을 읽어올 수 있는 메서드
    public void setHour(int hour) {
        if (hour < 0 || hour > 23) return; // 예상 범위 밖의 값이 들어오면 값을 수정하지 못하게 막음
        this.hour = hour; // 앞의 조건문에 걸리지 않는 경우에만 안전하게 멤버변수의 값을 초기화(변경)할 수 있음.
    }
    ... // minute과 second도 마찬가지의 원리로 세팅
}

멤버 변수들을 private으로 돌렸음 (확장하여 자손 클래스에서 접근이 가능하게 하려면 protected로)

외부에서는 직접 접근이 불가능하고, 멤버 변수에 접근하도록 세팅한 public 메서드를 통해서만 가능

이처럼 get으로 시작하는 getter와 set으로 시작하는 setter 메서드를 설정하여 값을 읽거나 변경할 수 있게 하는 것이 암묵적인 규칙으로 존재함.

Time(int hour, int minute, int second) {
    setHour(hour);
    setMinute(minute);
    setSecond(second);
}

이렇게 생성자 안에 setter 메서드들을 넣어줌으로써 생성자 호출을 통한 안전한 초기화도 가능해짐

 

생성자의 접근 제어자

인스턴스의 생성을 제한하기 위해 생성자에 접근 제어자를 붙일 수 있음

class Singleton {
    private static Singleton s = new Singleton(); // 아래의 생성자가 외부로부터 차단되어 있으므로 클래스 내에 대표 인스턴스 하나 생성

    private Singleton() {
        ...
    } // 외부에서 생성자에 접근할 수 없으므로 외부에서 인스턴스 생성 불가능.

    public static Singleton getInstance() {
        return s;
    } // 미리 생성되어있던 인스턴스를 반환하기만 함 (외부에서는 결국 모두 유일무이한 이 인스턴스를 받게 됨)
}

싱글톤 패턴(Singleton Pattern)

인스턴스를 오직 1개만 사용하는 패턴. 애플리케이션 시작 시 어떤 클래스가 최초 1회만 메모리를 할당하고, 그 메모리에 오직 하나의 인스턴스를 만들어 사용함.

 

싱글톤 패턴으로 구현한 Singleton 클래스 안에 s라는 이름의 인스턴스를 생성

getInstance 메서드에서 사용할 수 있도록 static을 붙여 미리 생성되게끔 함

외부에서는 getInstance 메서드를 통해서만 유일한 인스턴스인 s에 접근 가능

인스턴스 생성 없이 사용 가능해야 하므로 static 메서드로 정의

 

이와 같이 생성자가 private인 클래스는 자손을 가질 수 없음

자손 클래스에서 인스턴스를 생성할 때는 조상 클래스의 생성자를 호출해야 하는데, private이라 호출이 안되기 때문

 

제어자의 조합

조합 시 주의사항

  1. 메서드에 staticabstract 함께 사용 불가

    abstract 메서드는 구현부가 없는 반면, static 메서드는 구현부가 있어야하기 때문

 

  1. 클래스에 abstractfinal 함께 사용 불가

    final은 클래스 확장이 불가능하게 만드는 제어자인데, abstract는 상속을 통해 완성되는 추상적인 클래스이기 때문에 상충됨.

 

  1. abstract 메서드의 접근 제어자는 private일 수 없음

    abstract 메서드는 상속 받은 자손 클래스에서 구현해야 하는데 private이면 접근할 수 없기 때문

 

  1. 메서드에 privatefinal을 함께 사용할 필요 없음

    private 메서드는 어차피 상속, 접근이 불가하므로 오버라이딩 될 일이 없음. 따라서 오버라이딩 방지를 위한 final을 붙여줄 필요 없음

profile
Back-end Engineer 👨‍💻
post-custom-banner

0개의 댓글