접근 제어자
접근 제어자는 멤버 또는 클래스에 사용되어,
해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.
클래스나 멤버 변수, 생성자에 접근 제어자가 지정되어 있지 않다면,
접근 제어자가 default(package-private)임을 뜻한다.
접근 제어자는 클래스, 멤버 변수, 메서드, 생성자에서 사용 가능하며 접근 제어자는 아래와 같이 정리할 수 있다.
- private : 같은 클래스 내에서만 접근이 가능하다.
- protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능하다.
- default(package-private) : 같은 패키지 내에서만 접근이 가능하다.
- public : 접근 제한이 전혀 없다.
접근 범위가 넓은 쪽에서 좁은 쪽의 순으로 왼쪽부터 나열하면 다음과 같다.
public > protected > default(package-private) > private
더 간단하게 살펴보기 위해 아래와 같이 표로 정리해보았다.
빈칸은 사용 불가능하다는 의미다.
제어자 | 같은 클래스 | 같은 패키지 | 자손 클래스 | 전체 |
public | 가능 | 가능 | 가능 | 가능 |
protected | 가능 | 가능 | 가능 | |
default | 가능 | 가능 | ||
private | 가능 |
제어 접근자가 어느 키워드에서 사용 가능한 지 아래와 같이 정리할 수 있다.
- 클래스 : public, (default)
- 메서드 : public, protected, (default), private
- 멤버 변수 : public, protected, (default), private
- 지역변수 : 없음
접근 제어자를 사용하는 이유는 아래와 같이 2가지가 있다.
- 외부로부터 데이터를 보호하기 위해서
- 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서
이제 구체적인 예시를 살펴보자.
public class Time(){
public int hour;
public int minute;
public int second;
}
위와 같은 클래스의 멤버 변수는 아래 코드 멤버 변수에 직접 접근해 수정이 가능하다.
Time t = new Time();
t.hour = 25;
멤버변수멤버 변수 hour는 0보다는 같거나 크고 24보다는 작은 범위의 값을 가져야 하지만,
접근 제어자가 public이면 잘못된 값을 지정해도 막을 방법이 없다.
이런 경우 멤버 변수를 private이나 protected로 제한하고 멤버 변수의 값을 읽고 변경할 수 있는
public메서드를 제공함으로써 간접적으로 멤버 변수의 값을 다룰 수 있도록 하는 것이 바람직하다.
아래 코드는 멤버 변수 접근 제어자를 private로 바꾸고 get메서드로 멤버 변수의 값을 반환하고,
set 메서드로 매개변수에 값이 조건에 맞다면 멤버 변수의 값을 매개변수의 값으로 할당하도록 작성되었다.
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;
}
public int getMinute() { return minute; }
public void setMinute(int minute){
if ( minute < 0 || minute > 59 ) return;
this.minute = minute;
}
public int getSecond() { return second;}
public void setSecond(int second){
if ( second < 0 || second > 59) return;
this.second = second;
}
}
위와 같은 코드에서는 멤버변수에 의한 접근은 오직 메서드를 통해서만 가능하다.
보통 멤버변수의 값을 읽는 메서드의 이름을 'get멤버 변수'로 하고,
멤버 변수의 값을 변경하는 메서드의 이름을 'set멤버 변수 이름'으로 한다. 보통 각각 게터, 세터라고 부른다.
생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다.
보통 생성자의 접근 제어자는 클래스의 접근 제어자와 같지만, 다르게 지정할 수도 있다.
생성자의 접근 제어자를 private로 지정하면, 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없다.
따라서 클래스 내부에서 인스턴스를 생성해야 한다.
대신 인스턴스를 생성해서 반환해주는 public 메서드를 제공함으로써 외부에서 이 클래스의 인스턴스를 사용할 수 있게 해주어야 한다.
이 메서드는 public 이면서 static이어야 한다.
class Singleton {
private static Singleton s = new Singleton();
//getInstance ()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다.
private Singleton {
...
}
public static Singleton getInstance(){
return s;
}
}
이처럼 생성자를 통해 직접 인스턴스를 생성하지 못하게 하고 public 메서드를 통해 인스턴스에 접근하게 함으로써
사용할 수 있는 인스턴스의 개수를 제한할 수 있다.
getInsgtance 메서드를 통해 불러오는 인스턴스는 모두 같은 인스턴스이므로 싱글턴이 보장된다.
또 생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다.
왜냐하면, 자손 클래스의 인스턴스를 생성할 때 조상 클래스의 생성자를 호출해야만 하는데,
생성자의 접근 제어자가 private이므로 자손 클래스에서 호출하는 것이 불가능하기 때문이다.
그래서 클래스 앞에 final 제어자를 추가해 상속할 수 없는 클래스라고 알리는 것이 좋다.
public final class Singleton {
private Singleton (){ ... }
}
이상으로 마치겠습니다.
참고 자료
자바의 정석
댓글