클래스, 변수, 메서드의 선언부에 사용하여 부가적인 의미를 부여.
분류 | 종류 |
---|---|
접근 제어자 | public , protected , default , private |
그 외 | static , final , abstract , native , transient , synchronized , volatile , strictfp |
접근 제어자는 하나의 대상에 하나만 사용 가능. (그 외는 여러가지를 조합하여 사용 가능)
제어자의 순서는 자유지만, 일반적으로 접근 제어자를 가장 왼쪽에 둠.
static
은 "클래스의" 또는 "공통적인"이라는 의미로 쓰임.
static
이 붙은 멤버 변수와 메서드, 초기화 블럭은 클래스 관련 내용이기 때문에 인스턴스의 생성 없이도 사용 가능.
final
은 "최종적인", "변경될 수 없는"의 의미로 쓰임.
final | 클래스 | 변경될 수 없는 클래스 확장될 수 없는 클래스 (자손 X) |
메서드 | 변경될 수 없는 메서드 오버라이딩 불가 |
|
멤버 변수 | 상수 (값 변경 불가) | |
지역 변수 |
상수는 일반적으로 선언과 초기화를 동시에 하지만, 인스턴스 변수는 생성자로 초기화를 따로 해줄 수 있음
class Card {
final int NUMBER;
final String KIND;
Card(int number, String kind) {
NUMBER = number; // 매개변수로 넘어온 값을 상수에 할당하여 초기화 (이제 변경 불가)
KIND = kind;
}
}
abstract
는 "미완성의"라는 의미를 가짐.
선언부만 작성하고 수행 내용은 구현하지 않은 추상 메서드 선언에 사용.
클래스에 사용하여 클래스 내에 추상 메서드가 있다는 표시로 쓰기도 함. (추상 클래스)
abstract
가 붙은 추상 클래스는 "미완성 설계도"이므로 인스턴스 생성 불가.
abstract class AbstractClass {
abstract void abstractMethod(); // 추상 메서드
} // 추상 클래스
멤버 또는 클래스에 접근 제어자를 붙여 외부에서 접근할 수 있는 권한을 달리할 수 있음.
접근 제어자가 없으면 default 이므로 따로 명시하지 않아도 됨.
구분 | 접근성 |
---|---|
private | 같은 클래스 내에서만 접근 가능 |
(default) | 같은 패키지 내에서만 접근 가능 |
protected | 같은 패키지 내의 클래스, 또는 다른 패키지 내에 있는 해당 클래스의 자손 클래스에서만 접근 가능 |
public | 접근 제한 없음 |
대상에 따라 사용할 수 있는 접근 제어자도 다름.
클래스: public
, (default)
메서드 & 멤버 변수: public
, protected
, (default), private
지역 변수: 없음
주로 멤버에 접근 제어자를 사용하게 되는데, 이유는
클래스 내부에 선언된 데이터를 외부로부터 보호하기 위함
데이터 감추기 (data hiding)
내부적으로만 사용될 부분은 보여질 필요가 없으므로 감추기 위함
외부에서 굳이 접근할 필요가 없는 멤버들은
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
이라 호출이 안되기 때문
메서드에 static
과 abstract
함께 사용 불가
abstract
메서드는 구현부가 없는 반면, static
메서드는 구현부가 있어야하기 때문
클래스에 abstract
와 final
함께 사용 불가
final
은 클래스 확장이 불가능하게 만드는 제어자인데, abstract
는 상속을 통해 완성되는 추상적인 클래스이기 때문에 상충됨.
abstract
메서드의 접근 제어자는 private
일 수 없음
abstract
메서드는 상속 받은 자손 클래스에서 구현해야 하는데 private
이면 접근할 수 없기 때문
메서드에 private
과 final
을 함께 사용할 필요 없음
private
메서드는 어차피 상속, 접근이 불가하므로 오버라이딩 될 일이 없음. 따라서 오버라이딩 방지를 위한 final
을 붙여줄 필요 없음