제어자
1. 제어자
제어자(modifier)는 클래스, 변수, 메서드에 사용되며 부가적인 의미를 부여합니다. 크게 접근제어자와 그 외의 제어자로 구분합니다.
접근제어자 : public, protected, default, private
그외제어자 : static, final, abstract, native, transient, synchronized 등
여러 제어자를 조합하여 사용하는 것이 가능하나, 접근제어자의 경우 하나만 선택해서 사용하도록 제한되어 있습니다.
1.1 static
static은 '클래스', '공통'의 의미를 가지고 있습니다. 인스턴스가 아닌 클래스와 관련이 있기 때문에 인스턴스를 생성하지 않고 호출이 가능합니다.
static은 멤버변수, 메서드, 초기화블럭에 사용이 가능하며 각 대상별로 다음과 같은 특징이 있습니다.
static 멤버변수
클래스가 메모리에 로드될 때 생성되며 인스턴스 생성없이 사용 가능.
모든 인스턴스에 공통적으로 사용되는 클래스 변수.
static 메서드
인스턴스 생성 없이 호출이 가능한 메서드.
static 메서드 내에서는 인스턴스멤버 직접 사용 불가
다음 코드를 통해 static의 특징에 대해 확인해보겠습니다.
class JavaApp { // static 변수 static int width; static int height; // static 초기화 블럭 static { // static 변수의 초기화 수행 width = 100; height = 200; } // static 메서드 static int max(int a, int b) { return (a > b) ? a : b; } }
1.2 final
final은 '마지막', '변경될 수 없는'의 의미를 가지고 있으며 거의 모든 대상에 사용이 가능합니다.
final은 클래스, 메서드, 변수(멤버변수, 지역변수)에 사용이 가능하며 각 대상별로 다음과 같은 특징이 있습니다.
final 클래스 : 변경이 불가능한 클래스가 되기 때문에 다른 클래스로 상속이 불가능. (부모 클래스가 될 수 없음)
final 메서드 : 변경이 불가능한 메서드가 되기 때문에 오버라이딩이 불가능.
final 변수(멤버변수, 지역변수) : 변경이 불가능한 상수가 됨.
다음 코드를 통해 final의 특징에 대해 확인해보겠습니다.
// final 클래스 (상속불가능) final class JavaApp { // final 변수 final int MAX_SIZE = 10; // final 메서드 final void getMaxSize() { final int localVal = MAX_SIZE; return MAX_SIZE; } }
※ 생성자를 이용한 final 멤버 변수 초기화
인스턴스내의 인스턴스 변수의 경우 생성자를 이용하여 초기화해줄 수 있는데, final이 붙어서 값의 변경이 불가능한 멤버변수(상수)의 경우에도 생성자를 이용한 초기화를 통해 각 인스턴스마다 final 멤버변수의 값을 다르게하여 사용이 가능합니다.
1.3 abstract
abstract은 '미완성'의 의미를 가지고 있습니다. 클래스와 메서드에 사용되는데 메서드의 경우 선언부만 작성된 추상 메서드를 선언하는데에 사용됩니다.
abstract은 각 대상별로 다음과 같은 특징이 있습니다.
abstract 클래스 : 클래스내에 추상 메서드가 선언되어 있음을 의미.
abstract 메서드 : 선언부만 있고 구현부가 없는 추상 메서드.
다음은 abstract이 사용된 클래스와 메서드의 코드입니다.
// abstract 클래스 abstract class JavaApp { // abstract 메서드 abstract void app(); }
abstract 클래스는 미완성 클래스이므로 인스턴스 생성이 불가능하지만, 상속을 받은 후 원하는 메서드만 오버라이딩해서 사용할 수 있다는 장점이 있습니다.
※ abstract에 대한 내용은 추후 interface와 함께 좀더 자세하게 알아보도록 하겠습니다.
2. 접근 제어자
접근 제어자(access modifier)는 멤버, 클래스, 생성자를 외부에서 접근하지 못하도록 제한하는 역할을 합니다. 접근제어자가 지정되어 있지 않은 경우 default 접근 제어자가 적용됐음을 의미합니다.
접근제어자의 종류와 특징은 다음과 같습니다.
접근 제어자 |
동일 클래스 |
동일 패키지 |
자식 클래스 |
전체 |
public |
O |
O |
O |
O |
protected |
O |
O |
O |
X |
default |
O |
O |
X |
X |
private |
O |
X |
X |
X |
public : 접근 제한 없음
protected : 동일한 패키지 내의 클래스 또는 해당 클래스를 상속받은 외부의 클래스에서 접근 가능.
default : 동일한 패키지 내의 클래스에서 접근 가능.
private : 동일한 클래스에서만 접근 가능.
또한 대상별 사용가능한 제어자는 다음과 같습니다.
대상 |
접근 제어자 |
그외 제어자 |
클래스 |
public, default |
static, final |
메서드 |
모든 접근 제어자 (public, protected, default, private) |
static, final, abstract |
멤버변수 |
모든 접근 제어자 (public, protected, default, private) |
static, final |
지역변수 |
X |
final |
2.1 캡슐화 (encapsulation)
접근 제어자는 외부로부터의 데이터 보호 및 내부적으로만 사용되는 부분에 대한 데이터 감추기(data hiding)를 목적으로 사용되는데 이것을 캡슐화(encapsulation)라고 합니다.
접근 제어자를 사용하지 않을 경우 접근하면 안되는 멤버변수에 접근하여 수정이 이루어질 수 있는데, 이러한 경우를 private 또는 protected와 같은 접근 제어자를 사용하여 멤버변수를 캡슐화하고 별도의 public 메서드를 통해 접근을 가능하도록 하는 것이 바람직합니다.
다음 코드를 통해 캡슐화의 특징에 대해 알아보겠습니다.
public class JavaApp { private int hour; private int minute; private int second; public int getHour() { return hour; } public int getMinute() { return minute; } public int getSecond() { return second; } public void setHour(int hour) { this.hour = hour; } public void setMinute(int minute) { this.minute = minute; } public void setSecond(int second) { this.second = second; } }
위의 코드에서 멤버변수의 경우 private 접근 제어자를 사용하여 외부에서 직접 접근하지 못하도록 하였습니다. 대신 public 메서드를 추가로 작성하여 읽기와 값의 변경이 가능하도록 하였습니다.
※ 생성자의 접근 제어자
일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 동일합니다. 하지만 다르게 지정하여 인스턴스 생성을 제한할 수 있습니다. 위의 예제와 마찬가지로 생성자에 private을 붙여 접근을 제한하고 public 메서드를 추가하여 해당 메서드 내에서 인스턴스 생성 및 초기화를 수행하도록 합니다.
(이 때 public 메서드는 외부에서 인스턴스 생성없이 접근해야 하므로 static 제어자를 붙여줍니다)
2.2 제어자 조합시 주의사항
마지막으로 제어자 조합시 주의사항에 대해서 알아보겠습니다. 아래 사항에 유의하여 제어자를 조합하여 사용하면 되겠습니다.
메서드에 static과 abstract을 함께 사용할 수 없음
: abstract 메서드는 선언부만 있고 구현부가 없는데, static은 구현부가 있는 메서드에만 사용이 가능.
클래스에 final과 abstract을 함께 사용할 수 없음
: abstract 클래스는 상속을 통해 구현해야함을 의미하고 final은 확장이 불가능하도록 상속을 막기 때문에 서로 의미가 모순됨.
abstract 메서드에 private을 함께 사용할 수 없음
: abstract 메서드는 상속을 통해 구현해줘야 하는데, private이 붙은 경우 자식 클래스에서 접근할 수 없게됨.
메서드에 final과 private 둘 중에 하나만 사용할 것
: 두 제어자 모두 오버라이딩을 제한하기 때문에, 둘 중에 하나만 사용해도 됨.
이상으로 자바의 제어자에 대해서 알아봤습니다.
※ 참고 문헌
남궁성, 『Java의 정석 3rd Edition』, 도우출판(2016), p344 ~ p353. Chapter 07 객체지향 프로그래밍 II
wikidocs, 자바 제어자, https://wikidocs.net/232