[Java] 객체지향 프로그래밍 - 제어자

제어자(modifier)란?

제어자Modifier는 클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여할 수 있어요. 제어자의 종류는 크게 접근 제어자와 그 외의 제어자로 나눌 수 있어요.

제어자 종류
접근 제어자 : public, protected, default, private
그 외 : static, abstract, native, trasient, synchronized, volatile, strictfp

주로 클래스, 멤버 변수 그리고 메서드에 사용되며 하나의 대상에 대해서 여러 제어자를 조합하여 사용하는 것이 가능해요.

단, 접근 제어자의 경우 한번에 네 가지 중 하나만 사용할 수 있어요(public, private을 동시에 적용할 수 없다는 의미에요).

static - 클래스의, 공통적인

static 제어자는 '클래스의', '공통적인'이라는 의미를 가져요. 그 예로 클래스 내에 static으로 선언된 클래스 변수가 있죠. 이는 따로 인스턴스를 만들지 않아도 사용할 수 있고 값도 공유해요. 이와 같이 static이 붙은 메서드도 인스턴스를 생성하지 않고도 사용할 수 있어요.

class A {
	static int a = 100;
    static void aFunc() {}
}

public static void main(String[] args){
	A.a = 200;	// 이렇게 인스턴스 없이도 사용할 수 있어요
    A.aFunc();
}

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

변수에 적용한다면 const와 동일하게 이를 상수화시켜요. 즉, 못 바꾸게 하죠. 메서드에 적용한다면 더 이상 오버라이딩을 못하게 하고 클래스에 적용한다면 더 이상 상속할 수 없게 만들어요.

final class A {				// 더 이상 상속 불가
	final int a = 100; 		// 상수화, 이제 값 못 바꿈
    final void method(){} 	// 더 이상 오버라이딩 불가
}
class B extends A {			// Error! - 상속 못해요
	@Override
    void method() {}		// Error! - 오버라이딩 못해요
}

final 멤버 변수를 초기화할 수 있는 방법은 하나 존재해요. 바로 생성자초기화 블록예요. 그렇게 상수로 정의할 수 없는 초기화 로직을 수행할 수 있어요.

class A {
    final static List<Integer> list; // 이렇게 =이 아닌 초기화 작업도 가능해요
    static{
        list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
    }

    final static List<Integer> list2 = new ArrayList<>();;
    static{
        //list2 = new ArrayList<>();	// 다시 초기화는 못해요
        list2.add(1);
        list2.add(2);
        list2.add(3);
        list2.add(4);
    }
    
    final int a;
    A(){
        a = 10;							// 생성자에서도 가능해요
        //a = 30;						// 마찬가지로 재초기환 안되요
    }

void method() { /*a = 20;*/ }			// 여기선 초기화 못해요
}

abstract - 추상의, 미완성의

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

클래스에서만 사용되어 클래스 내에 추상 메서드가 존재한다는 것을 쉽게 알 수 있게 해요. 따라서 클래스, 메서드에서만 abstract 선언이 가능해요.

abstract class : 클래스 내에 추상 메서드가 선언되어 있음을 알려요. 추상 클래스는 new를 통해 직접적인 생성이 불가해요.
abstract {타입} 함수명({파라미터}) : 선언부만 작성하고 구현부는 작성되지 않은 추상 메서드임을 알려요

abstract class App{			// 추상 클래스
	abstract void run();	// 추상 메서드, 구현부가 없어요
}

가끔씩 완성된 클래스도 abstract 선언으로 추상 클래스로 만드는 경우도 있어요.

이 경우는, 추상 클래스는 직접적으로 생성, 즉 new를 사용할 수 없어요. 이를 활용해서 직접적인 인스턴스 생성을 막아요.

public abstract class WindowAdapter{
	public void open(){}
	public void listen(){}
	public void run(){}
	public void close(){}
}

위를 보면 아무 의미 없는 코드에요. 따라서 이를 직접 생성하는 것은 의미가 없죠. 그래서 abstract를 통해 이를 막는거죠. 대신 이를 상속하는 클래스들은 해당 부모 클래스에서 필요한 부분만 오버라이딩해서 사용할 수 있는 장점이 있어요.

접근 제어자(Access modifier)

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

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

여기서 default는 어떤 키워드가 아닌 제어자가 명시되어 있지 않은 경우를 의미해요.

접근 범위가 넓은 순으로 나열하면 아래와 같아요.

public \to protected \to (default) \to private

캡슐화(Encapsulation)

클래스나 멤버, 주로 멤버에 접근 제어자를 사용하는 이유는 클래스의 내부의 데이터를 보호하기 위해서에요.

클래스를 통해 기능을 만들어서 다른 개발자들에게 제공했다고 가정해봐요. 해당 클래스의 일부 변수나 메서드들은 함부로 다루면 의도치 않은 결과를 발생시킬 수 있어요. 그렇기에 제어자를 통해 외부에서 사용 가능한 것과 그러면 안되는 것을 구분시킬 수 있어요.

예를 들면, 사람이라는 클래스를 만들었어요. 그런데 여기서 어떤 개발자가 요즘은 헌혈집에 가면 피가 항상 부족하다는 이야길 들었어요. 그래서 물은 피보다 많으니까 피대신 수혈하면 수급하는 곳이 많아 좋지 않을까?라는 생각으로 사람이라는 클래스에 있는 피를 물로 바꿨어요. 당연히 사람은 죽어버리겠죠? 사람 클래스를 만든 개발자는 피가 거꾸로 솟을 꺼에요. 그래서 이렇게 감춰야할 것은 감추고 사용할 수 있는 것은 사용하게 접근을 제한할 필요가 있는거에요.

이렇게 외부로부터의 접근을 제한하는 것을 데이터 감추기(data hiding), 또는 캡슐화(Encapsulation)라고 해요. 코드의 복잡성을 최소화하기 위해 필요해요.

제어자의 조합

제어자는 아래와 같이 조합해서 사용할 수 있어요.

1. 메서드에 static과 abstract를 함께 사용할 수 없어요
클래스 메서드는 몸통이 있는 메서드에만 사용할 수 있기 때문이에요.

// 사용 X
abstract static void method();

2. 클래스에 abstract와 final을 함께 사용할 수 없어요
클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미고, abstract는 상속을 통해 완성되어야 하기 때문에 서로 모순이 되요.

// 사용 X
abstract final void method();

3. abstract 메서드의 접근 제어자가 private일 수 없어요
abstract 메서드는 자식 클래스에서 구현해야 하고 private는 자식도 접근할 수 없기 때문에 모순이 되요.

// 사용 X
private abstract void method();

4. 메서드에 private와 final을 같이 사용할 '필요'는 없어요.
private 메서드는 오버라이딩이 불가능하기 때문이에요. 둘 중 하나만 사용해도 의미가 충분해요.

// 쓸데 없는 TMI, 둘 중 하나만 써도 되요
private final void method();

좋은 웹페이지 즐겨찾기