제어자

goose_bumps·2024년 5월 15일

Java

목록 보기
7/21

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

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

1. static

클래스 변수 또는 클래스 메서드에 사용되었던 제어자이다. 공통적인 특성을 가지게 하며 인스턴스와 무관하게 만든다. 예를 들어, 인스턴스 변수의 경우 인스턴스마다 다른 값을 가지지만 클래스 변수의 경우 인스턴스와 무관하게 동일한 값을 갖는다.
멤버변수, 메서드, 초기화 블럭에 사용이 가능하며 인스턴스를 생성하지 않고 사용이 가능하다.

class example{
	static String cv1;
    static int cv2 = 3;
    static void classMethod(){	
    	System.out.println("class method");
        }
    static{
    	//클래스 변수의 복잡한 초기화 수행
        }
}

static 추가 시

  • 멤버변수 - 클래스 변수가 된다, 클래스가 메모리에 로딩 시 생성된다
  • 메서드 - 인스턴스 멤버를 직접 사용할 수 없다

2. final

상수를 만들 때 사용하는 제어자로 알려져 있다. 변수(멤버변수, 지역변수) 외에도 클래스, 메서드에 추가될 수 있는데 그 기능이 다양하다.

  • 클래스 - 자식 클래스에게 상속이 불가능하다(=조상 클래스가 될 수 없다), 변경 또는 확장할 수 없는 클래스가 된다
  • 메서드 - 변경 불가한 메서드가 되며 오버라이딩이 불가능하다
  • 변수 - 값을 변경할 수 없는 상수가 된다

final이 추가된 변수의 경우 선언과 초기화가 동시에 가능하지만, 인스턴스 변수의 경우 생성자에게 초기화를 맡길 수 있다.

class modifier{
	final int WEIGHT;
	final int HEIGHT;
	modifier(int WEIGHT, int HEIGHT){
		this.WEIGHT = WEIGHT;
		this.HEIGHT = HEIGHT;
	}
	modifier(){
		this(96,179);
	}
	public String toString() {
		return WEIGHT + " " + HEIGHT;
	}
}

public class example {
	public static void main(String[] args) {
		modifier m = new modifier(100,188);
		// m.WEIGHT = 4;
		System.out.println(m);
	}
}

인스턴스 생성 시 생성자에 매개변수를 입력하면 상수의 초기화가 이뤄지고, 입력하지 않을 경우 기본 생성자가 매개변수가 있는 생성자를 호출하여 정해진 값을 넣게 된다.
인스턴스 생성 후 상수의 초기화가 이루어졌기 때문에 참조변수를 사용하여 상수를 초기화 할 수 없다.

3. abstract

클래스, 메서드 앞에 추가가 가능하며 추상 클래스가 될 경우 반드시 추상 메서드를 포함해야 한다.
추상 메서드의 경우 선언부만 존재하고 내용은 없다. 미완성이기 때문에 추상 클래스는 인스턴스를 생성할 수가 없다. 추상 클래스는 다른 클래스가 상속을 하여 오버라이딩을 하기 위해 사용된다. 즉, 다른 클래스가 추상 클래스를 상속할 때 의미가 있는 클래스이고 추상 메서드의 경우 자식 클래스가 구현을 해주어야 한다.
자세한 내용은 뒤에서 다시 정리하겠다.

abstract class example{
	abstract void method(); //내용이 없기 때문에 중괄호가 없다   
}

4. 접근 제어자

접근 제어자는 멤버, 클래스에 사용되어 외부에서 접근하지 못하도록 제한하는 역할을 한다.
접근 허용 범위는 접근 제어자마다 다르며 접근 제어자를 추가하지 않을 경우 컴파일러는 자동으로 default를 추가한다.

  • public - 접근 제한이 전혀 없다
  • protected - 같은 패키지 또는 다른 패키지일 경우 자식 클래스에서 접근 가능하다
  • default - 같은 패키지 내에서만 접근 가능하다
  • private - 같은 클래스 내에서만 접근 가능하다

메서드와 멤버변수의 경우에는 4가지 접근 제어자를 모두 사용가능하지만 클래스의 경우 public, default만 사용 가능하다.(지역변수는 접근 제어자 사용 불가)

접근 제어자는 왜 사용할까? 접근 제어자의 역할이 외부로부터 접근을 제한하는 것이라고 하였다. 외부로부터 접근을 제한하여 외부로부터 데이터를 보호하고( ex. 비밀번호) 내부적으로만 사용되는 부분을 감추기 위해 사용한다. 비밀번호 같은 경우 외부에서 함부로 변경하면 안되기 때문에 접근 제어자를 사용할 필요가 있다.

접근 제어자의 필요성의 예시로 시간을 설정하는 클래스가 있다고 가정해보자. 사용자가 입력을 하여 시간을 설정한다고 할 때 시의 경우 0보다 작거나 23보다 크면 안된다.

class NowTime{
	private int hour;
	private int minute;
	private int seconds;
	void setHour(int hour) {
		if(hour < 0 || hour > 23)
			return;
		this.hour = hour;
	}
	void setMinute(int minute) {
		if(minute < 0 || minute > 59)
			return;
		this.minute = minute;
	}
	void setSeconds(int seconds) {
		if(seconds < 0 || seconds > 59)
			return;
		this.seconds = seconds;
	}
	public String toString() {
		return hour + ":" + minute + ":" + seconds;
	}
}
public class example {
	public static void main(String[] args) {
		NowTime n = new NowTime();
		n.setHour(4);
		n.setMinute(32);
		n.setSeconds(24);
		System.out.println(n);
	}
}

여기서 멤버변수들은 private 접근 제어자를 가지고 있기 때문에 인스턴스를 호출하여 값을 초기화할 수 없다. 값을 초기화하려면 set 메서드를 호출하는 방법 밖에 없다. private는 같은 클래스 내에서는 접근이 가능하기 때문에 같은 클래스에 있는 set 메서드는 접근이 가능하기 때문이다. 이렇게 하면 사용자가 터무니없는 값을 입력하는 것을 방지할 수 있게 된다.


생성자에도 접근 제어자를 사용할 수 있다. 그런데 생성자에 사용하는 경우는 언제일까? 보통 생성하려는 인스턴스의 개수를 제한하고자 할 경우에 사용한다. 생성자에 private 접근 제어자가 있으면 외부에서는 인스턴스 생성이 불가능하다. 이때 인스턴스를 생성하려면 내부에서 밖에 생성할 수 없다.

class example{
	int iv1;
    int iv2;
    private example(){}
}

public class mainClass{
	public static void main(String args[]){
    	example e = new example() // 외부에서 생성 불가능
    }
}

클래스 내부에서 인스턴스를 생성하고 클래스 메서드로 이를 호출하면 된다. 여기서 클래스 메서드를 사용하는 이유는 인스턴스를 생성하지 않고 인스턴스를 호출해야 하기 때문에 클래스 메서드만 가능하기 때문이다.

final class example{
	int iv1;
    int iv2;
    private example(){}
    example e = new example();
    static example getInstance(){
    	return e;
    }   
}

public class mainClass{
	public static void main(String args[]){
    	example e = example.getInstance();
    }
}

한 가지 알아두어야 하는 점은 생성자의 접근 제어자가 private인 클래스는 다른 클래스의 조상 클래스가 될 수 없다. 자식 클래스가 인스턴스 생성 시 조상 클래스의 인스턴스를 생성해야 하는데 외부에서 접근이 제한되어 있기 때문에 불가능하다. 따라서, 생성자의 접근 제어자가 private인 경우 다른 클래스의 조상이 될 수 없다는 의미로 클래스 앞에 final 제어자를 추가하여 알리는 것이 좋다.

주의할 점

  • 메서드에 static과 abstract이 함께 사용될 수 없다
  • 클래스에 abstract과 final을 동시에 사용할 수 없다
  • abstract 메서드에 접근 제어자가 private일 수 없다
  • 메서드에 private과 final을 같이 사용할 필요는 없다(접근 제어자가 private인 메서드는 오버라이딩 불가)

0개의 댓글