본문 바로가기

프로그래밍언어/JAVA

[JAVA] 제어자 (Modifier)

반응형

1. 제어자 (modifier)

제어자란 클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다. 제어자는 접근 제어자와 그 외의 제어자로 구분할 수 있다.

- 접근 제어자: public, protected, default, private
- 그 외의 제어자: static, final, abstract, native, transient, synchronized, volatile, strictfp

제어자는 여러 제어자를 조합하여 사용하는 것이 가능한데, 접근 제어자는 4가지 중 하나만 선택해서 사용할 수 있다.


2. static

static은 '클래스의' 또는 '공통적인'의 의미를 가지고 있다. 인스턴스 변수는 하나의 클래스로부터 생성되었더라도 각기 다른 값을 유지하지만 클래스 변수는 인스턴스에 관계없이 같은 값을 가진다. 모든 인스턴스가 클래스 변수를 공유한다는 의미이다.

static으로 선언된 멤버변수와 메서드, 초기화 블럭은 인스턴스가 아닌 클래스에 관계된 것이기 때문에 인스턴스를 생성하지 않고도 사용할 수 있다. 하지만 static 메서드에서는 인스턴스 멤버를 사용할 수 없다. 인스턴스 멤버는 인스턴스를 생성할 때 생성되기 때문에 클래스에서 바로 접근하는 static 메서드에서는 접근할 수 없다.

※ static 멤버변수는 클래스가 메모리에 로드될 때 생성된다. 이와 같이 static 초기화 블럭도 클래스가 메모리에 로드될 때 단 한번만 수행되며 주로 클래스 변수를 초기화 하는데 사용한다.


3. final

final은 '마지막의' 또는 '변경될 수 없는'의 의미를 가지고 있으며 거의 모든 대상에 사용할 수 있다.

final은 클래스, 메서드, 멤버변수, 지역변수 등에 사용되며 각각의 사용되는 위치에 따라 의미가 달라진다.

- 클래스: 변경될 수 없는 클래스. 확장될 수 없는 클래스가 되어 상속에서 조상 클래스로 사용할 수 없다.

              대표적인 final 클래스로 String과 Math가 있다.
- 메서드: 변경될 수 없는 메서드. 오버라이딩을 통해 재정의 될 수 없다.
- 멤버변수 & 지역변수: 변수의 값을 변경할 수 없다. 상수가 된다.


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

일반적으로 final 이 붙은 변수는 상수가 되기 때문에 선언과 동시에 초기화를 진행해주지만 인스턴스 변수의 경우 생성자에서 초기화가 가능하도록 할 수 있다.

 

class Test {
  final int NUMBER;
  final String STR;

  Test(int number, String str) {
    NUMBER = number;
    STR = str;
  }

  ...
}

 

final로 선언된 인스턴스 변수의 경우 생성자에서 초기화 할 수 있는데, 만약 이 방법이 불가능하다면 모든 인스턴스는 final로 선언된 변수의 초기값이 같아지게 될 것이다.


4. abstract

abstract는 '추상적인'의 의미를 가지고 있다. 메서드의 선언부만 작성하고 실제 메서드 내용은 구현하지 않은 추상 메서드를 선언하는데 사용된다. 클래스에서 사용되는 경우는 해당 클래스 안에 추상 메서드가 존재한다는 것을 알려주는데, 이러한 클래스를 추상 클래스라고 한다.

// 추상 클래스
abstract class AbstractClass {
  // 추상 메서드 : 선언부만 존재한다.
  abstract void abstractMethod();
}



5. 접근 제어자 (access modifier)

접근 제어자는 멤버 또는 클래스에 사용되어 해당 객체에 접근을 제한하는 역할을 한다.

접근 제어자는 다음의 4가지가 존재한다.
- public: 접근 제한이 없다.
- protected: 같은 패키지 내부, 다른 패키지에서 해당 클래스를 상속한 자손 클래스에서 접근이 가능하다.
- default: 같은 패키지 내부에서만 접근이 가능하다.
- private: 같은 클래스 내부에서만 접근이 가능하다.

※ 접근 제어자가 default 임을 알리기 위해 실제로 default를 붙이지는 않는다. 명시적으로 접근 제어자가 붙어있지 않은 경우에 default로 인식된다.

캡슐화 (encapsulation)

접근 제어자를 사용하면 해당 객체 내부의 데이터를 외부에 보이지 않도록 숨겨서 보호할 수 있다. 데이터가 유효한 값을 유지하고 외부에서 함부로 추출하거나 변경하지 못하도록 접근을 제어하는 것을 data hiding 이라고 하며, 객체지향개념의 캡술화 (encapsulation) 에 해당되는 내용이다.

또한 외부에서 접근이 필요없는 멤버들을 private으로 지정하여 외부에 노출시키지 않도록 하여 복잡성을 줄이는데 이 것 역시 캡슐화에 해당한다.

getter와 setter 메서드를 생성하여 private 한 변수로 외부 접근이 간접적으로 이루어지도록 한다. 이를 통해서 직접 접근할 경우 발생할 수 있는 예외 상황 들을 메서드에서 제한할 수 있다. getter는 해당 변수의 값을 반환하는 메서드이고 setter는 변수의 값을 설정해주는 메서드이다.

 

// private 멤버와 getter, setter 예시
public class Test {
  private int number;

  public int getNumber() {
    return this.number;
  }

  public void setNumber(int number) {
    this.number = number;
  }
}

 

생성자에 접근 제어자를 붙여서 인스턴스의 생성을 제한할 수도 있다. 생성자의 접근 제어자를 private으로 지정하면, 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없게 된다. 클래스 내부에서는 인스턴스의 생성이 가능하다.

대신 인스턴스를 생성하여 반환해주는 public 메서드를 통해서 외부에서 해당 클래스의 인스턴스를 사용할 수 있도록 할 수 있다. 이러한 방식을 통해서 해당 클래스의 인스턴스 개수를 제한할 수 있다.

생성자가 private인 클래스를 조상 클래스로 상속받을 수 없다. 그 이유는 자손 클래스에서 상속하는 경우에 해당 클래스의 생성자를 통해 초기화를 수행해야 하는데, private인 경우 이를 호출하지 못하기 때문이다.


6. 제어자(modifier)의 조합

제어자와 사용가능한 대상
- 클래스: public, (default), final, abstract
- 메서드: 모든 접근 제어자, final, abstract, static
- 멤버변수: 모든 접근 제어자, final, static
- 지역변수: final

※ 제어자 사용 시 주의사항

- 메서드에 static + abstract는 사용할 수 없다.
static 메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이다.

- 클래스에 abstract와 final을 동시에 사용할 수 없다.
클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고 abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순되기 때문이다.

- abstract 메서드의 접근 제어자가 private일 수 없다.
abstract 메서드는 자손 클래스에서 구현해주어야 하는데, 접근 제어자가 private 이면, 자손 클래스에서 접근할 수 없기 때문이다.

- 메서드에 private과 final을 같이 사용할 필요는 없다.
접근 제어자가 private는 오버라이딩 될 수 없기 때문이다. 이 둘 중 하나만 사용해도 의미가 충분하다.
반응형

'프로그래밍언어 > JAVA' 카테고리의 다른 글

[JAVA] 추상클래스 (abstract class)  (0) 2021.11.20
[JAVA] 다형성 (Polymorphism)  (0) 2021.11.19
[JAVA] 자바 패키지  (0) 2021.11.08
[JAVA] 오버라이딩 (Overriding)  (0) 2021.11.08
[JAVA] 상속 (Inheritance)  (0) 2021.11.04