본문으로 바로가기

[Java] 제어자

category Language/Java 2020. 1. 18. 15:56

1. 제어자란?

제어자는 클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다.

 

제어자의 종류는 크게 두가지로 나뉜다.

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

제어자는 클래스나 멤버변수와 메서드에 주로 사용되며,

하나의 대상에 대해서 여러 제어자를 조합하여 사용하는 것이 가능하다.

단, 접근 제어자는 한번에 네가지 중 하나만 선택해서 사용할 수 있다.

 

2. static - 클래스의, 공통적인

인스턴스 변수는 하나의 클래스로부터 생성되었더라도 각기 다른 값을 유지하지만,

클래스변수는 인스턴스에 관계없이 같은 값을 갖는다.

하나의 변수를 모든 인스턴스가 공유하기 때문이다.

 

static이 붙은 멤버변수와 메서드, 그리고 초기화 블럭은 인스턴스를 생성하지 않고도 사용이 가능하다.

 

예제코드

class StaticTest {
    static int width = 200;          // 클래스 변수 (static변수)
    static int height = 120;         // 클래스 변수 (static변수)

    static {                         // 클래스 초기화 블럭
        // static변수의 복잡한 초기화 수행
    }

    static int max(int a, int b) {   // 클래스 메서드(static메서드)
        return a > b ? a : b;
    }
}

3. final - 마지막의, 변경될 수 없는

final은 거의 모든 대상에 사용 될 수 있다.

사용대상에 따라 의미가 다르다.

  • 클래스 -> 확장될 수 없는 클래스, 자손 클래스를 정의할 수 없음
  • 메서드 -> 오버라이딩을 할 수 없는 메서드
  • 변수 -> 값을 변경할 수 없는 상수

예제 코드

final class FinalTest {             // 조상이 될 수 없는 클래스
    final int MAX_SIZE = 10;        // 값을 변경할 수 없는 멤버변수(상수)

    final void getMaxSize() {       // 오버라이딩할 수 없는 메서드(변경불가)
        final int LV = MAX_SIZE;    // 값을 변경할 수 없는 지역변수(상수)
        return MAX_SIZE;
    }
}

4. abstract - 추상의, 미완성의

메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 추상메서드를 선언하는데 사용

클래스에 사용되어 클래스 내에 추상메서드가 존재한다는 것을 쉽게 알 수 있게 한다.

 

추상 클래스는 아직 완성되지 않은 메서드가 존재하는 '미완성 설계도'이므로 인스턴스를 생성할 수 없다.

abstract class AbstractTest{	//추상 클래스(추상 메서드를 포함한 클래스)
    abstract void move();	//추상 메서드(구현부가 없는 메서드)
}

5. 접근 제어자 (access modifier)

접근 제어자는 멤버 또는 클래스에 사용되어, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.

클래스나 멤버변수, 메서드, 생성자에 접근 제어자가 지정되어 있지 않다면, 접근제어자가 default임을 뜻한다.

 

  • private - 같은 클래스 내에서만 접근 가능
  • default - 같은 패키지 내에서만 접근 가능
  • protected - 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근 가능
  • public - 접근 제한이 전혀 없다.

접근 범위

protected는 패키지에 관계없이 상속관계에 있는 자손클래스에서 접근할 수 있도록 하는 것이 제한 목적이지만,

같은 패키지 내에서도 접근이 가능하다. 그래서 protected가 default보다 접근범위가 넓다.

 

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

  • 캡슐화(encapsulation)

    객체지향개념에서 데이터가 유효한 값을 유지하도록, 또는 비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 외부로부터의 접근을 제한하는 것
  • 접근 제어자를 사용하는 이유

    외부로부터 데이터를 보호하기 위해서,
    외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해서

예제코드

public class Time {  // 메소드를 통한 접근 허용
    private int hour;
    private int minute;
    private int second;  // 접근 제어자를 private으로 하여 외부에서 직접 접근하지 못하도록 한다.

    public int getHour() { return hour; }
    public void setHour(int hour) {
        if(hour < 0 || hour > 23) return;
        this.hour = hour;  // 멤버변수의 값을 읽고 변경할 수 있는 public 메서드를 제공함으로써 간접적으로 멤버변수의 값을 다룰 수 있도록 하는 것이 바람직하다.
    }

    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; 
    }
}

7. 생성자의 접근 제어자

생성자의 접근 제어자를 private으로 지정하면, 외부에서 생성자에 접근할 수 없으므로 인스턴스를 생성할 수 없다.
그래도 클래스 내부에서는 인스턴스를 생성할 수 있다.

대신 인스턴스를 생성해서 반환해주는 public메서드를 제공함으로써

외부에서 이 클래스의 인스턴스를 사용할 수 있도록 한다.
이 메서드는 public인 동시에 static이어야 한다.

 

예제코드

class Singleton {
    ...
    private static Singleton s = new Singleton(); // getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되어야 하므로 static이어야 한다.
    
    private Singleton() {
        ...
    }
    
    // 인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static 이어야 한다.
    public static Singleton getInstance() {
        return s;
    }
    ...
}

8. 제어자의 조합

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

<제어자 조합 시 주의사항>

  • 메서드에 static과 abstract를 함께 사용할 수 없다.
    • static 메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이다.
  • 클래스는 abstract와 final을 동시에 사용할 수 없다.
    • 클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미이고,
      abstract는 상속을 통해서 완성되어야 한다는 의미이므로 서로 모순되기 때문이다.
  • abstract메서드는 접근 제어자가 private일 수 없다.
    • abstract메서드는 자손클래스에서 구현해주어야 하는데 접근 제어자가 private이면,
      자손 클래스에서 접근할 수 없기 때문이다.
  • 메서드에 private과 final을 같이 사용할 필요는 없다.
    • 접근 제어자가 private인 메서드는 오버라이딩될 수 없기 때문이다.

'Language > Java' 카테고리의 다른 글

[Java] toString()과 String.valueOf()  (0) 2020.01.18
[Java] 추상클래스(abstract class)  (0) 2020.01.18
[Java] 다형성(Polymorphism)  (0) 2020.01.18
[Java] 상속(Inheritance)  (0) 2020.01.18
[Java] 오버로딩과 오버라이딩  (0) 2020.01.17