제어자란?
제어자는 클래스, 변수 또는 메소드의 선언부에 함께 사용되어 부가적인 의미를 부여한다.
제어자의 종류는 다음과 같이 접근 제어자와 그 외의 제어자로 나눌 수 있다.
접근 제어자 : public, protected, default, private
그 외 : static, final, abstract, native, transient, synchronized, volatile, strictfp
하나의 대상에 대해서 여러 제어자를 조합하여 사용하는 것이 가능하나,
접근 제어자는 한 번에 네 가지 중에 하나만 선택해서 사용할 수 있다.
static - 클래스의, 공통적인
static은 '클래스의' 또는 '공통적인'의 의미를 가지고 있다.
인스턴스 변수는 하나의 클래스로부터 생성되었더라도 각기 다른 값을 유지하지만,
클래스변수는 인스턴스에 관계없이 같은 값을 갖는다.
그 이유는 하나의 변수를 모든 인스턴스가 공유하기 때문이다.
static이 멤버변수로 사용되었을 때 다음과 같은 의미를 갖는다.
1. 모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다.
2. 클래스변수는 인스턴스를 생성하지 않고도 사용 가능하다.
3. 클래스가 메모리에 로드될 때 생성된다.
static이 메소드에 사용되었을 때 다음과 같은 의미를 갖는다.
1. 인스턴스를 생성하지 않고도 호출이 가능한 static메소드가 된다.
2. static메소드 내에서는 인스턴스멤버들을 직접 사용할 수 없다.
멤버변수, 메소드 이 외에도 초기화블럭에서 static이 사용될 수 있는데,
static초기화 블럭은 클래스 메모리에 로드될 때 단 한번만 수행되며, 주로 클래스변수를 초기화하는데 사용된다.
final - 마지막의, 변경될 수 없는
final은 '마지막의' 또는 '변경될 수 없는'의 의미를 가지고 있으며 거의 모든 대상에 사용될 수 있다.
final이 클래스에 사용될 때는
변경될 수 없는 클래스, 확장될 수 없는 클래스가 된다.
그래서 final로 지정된 클래스는 다른 클래스의 조상이 될 수 없다.
final이 메소드에 사용될 때는
변경될 수 없는 메소드, fianl로 지정된 메소드는 오버라이딩을 통해 재정의 될 수 없다.
final이 변수로 사용될 때는
값을 변경할 수 없는 상수가 된다.
fianl을 실습에 적용해보자.
final이 붙은 변수는 상수이므로 일반적으로 선언과 초기화를 동시에 하지만,
인스턴스변수의 경우 생성자에서 초기화 되도록 할 수 있다.
클래스 내에 매개변수를 갖는 생성자를 선언하여, 인스턴스를 생성할 때
final이 붙은 멤버변수를 초기화하는데 필요한 값을 생성자의 매개변수로부터 제공받는 것이다.
이 기능을 활용하면 각 인스턴스마다 fianl이 붙은 멤버변수가 다른 값을 갖도록 하는 것이 가능하다.
위의 클래스처럼, 카드의 경우 각 카드마다 다른 종류와 숫자를 갖지만, 일단 카드가 생성되면
카드의 값이 변경이 되서는 안 된다.
따라서 final로 선언을 해주되, 각 인스턴스마다 각기 다른값을 갖기 위해서 선언과 초기화를 동시에 해주지는 않았다.
메인클래스에 보면 c.NUMBER = 5에서는 에러가 발생하였다.
final로 선언된 변수를 다른 값으로 변경하려고 했기 때문이다.
abstract - 추상의, 미완성의
abstract는 '미완성'의 의미를 가지고 있다.
메소드의 선언부만 작성하고 실제 수행내용은 구현하지 않은 추상 메소드를 선언하는데 사용된다.
abstract가 클래스하고 메소드에서 사용될 수 있는데
클래스에서 사용되었을 때는
클래스 내에 추상 메소드가 선언되어 있음을 의미하고,
메소드에서 사용되었을 때는
선언부만 작성하고 구현부는 작성하지 않은 추상 메소드임을 의미한다.
추상 클래스는 아직 완성되지 않은 메소드가 존재하는 '미완성 설계도'이므로 인스턴스를 생성할 수 없다.
접근 제어자
접근 제어자는 멤버 또는 클래스에 사용되어,
해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.
접근 제어자가 사용될 수 있는 곳 - 클래스, 멤버변수, 메소드, 생성자
private : 같은 클래스 내에서만 접근이 가능하다.
default : 같은 패키지 내에서만 접근이 가능하다.
protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.
public : 접근 제한이 전혀 없다.
접근 제어자를 이용한 캡슐화
클래스나 멤버, 주로 멤버에 접근 제어자를 사용하는 이유는 클래스의 내부에 선언된 데이터를 보호하기 위해서이다.
데이터가 유효한 값을 유지하도록, 또는 비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해서는
외부로부터 접근을 제한하는 것이 필요하다.
이것을 데이터 감추기 라고 하며, 객체지향개념의 캡슐화에 해당하는 내용이다.
또 다른 이유는 클래스 내에서만 사용되는, 내부 작업을 위해 임시로 사용되는 멤버변수나
부분작업을 처리하기 위한 메소드 등의 멤버들을 클래스 내부에 감추기 위해서이다.
만일 메소드 하나를 변경해야 한다고 가정했을 때, 이 메소드의 접근 제어자가 public이라면,
메소드를 변경한 후에 오류가 없는지 테스트해야하는 범위가 넓다.
그러나 접근제어자가 default라면 패키지 내부만, private라면 클래스 하나만 살펴보면 된다.
이렇게 접근 제어자 하나가 때로는 상당한 차이를 만들어낼 수 있다.
다음 예제를 살펴보자.
public class Time{
public int hour;
public int minute;
public int second;
}
Time t = new Time() ;
t.hour = 25;
클래스의 인스턴스를 생성한 다음, 멤버변수에 직접 접근하여 값을 변경해보았다.
멤버변수 hour는 0보다는 같거나 크고 24보다는 작은 범위의 값을 가져야 하지만,
위의 코드에서처럼 잘못된 값을 지정한다고 해도 이것을 막을 방법은 없다.
따라서 이런 경우에는 접근자로 각 멤버변수들을 제한하고 멤버변수의 값을 읽고 변경할 수 있는
public메소드를 제공함으로써 간접적으로 멤버변수의 값을 다룰 수 있도록 하는 것이 바람직하다.
다음 예시를 살펴보자.
get으로 시작하는 메소드는 단순히 멤버변수의 값을 반환하는 일을 하고,
set으로 시작하는 메소드는 매개변수에 지정된 값을 검사하여 조건에 맞는 값일 때만
멤버변수의 값을 변경하도록 작성되어 있다.
단순히 hour이라는 변수에 직접적으로 접근하는 것이아닌, 메소드로 간접적으로 접근하여 변경해주는 것이다.
위의 Time클래스를 응용한 실습프로그램을 살펴보자.
메인클래스에서 t.hour = 13로 접근했더니 오류가 발생하였다.
왜냐하면 Time클래스에서 멤버변수가 private로 선언되었기 떄문이다.
따라서 이 들을 다루기 위한 public메소드를 추가하였다.
메소드를 통한 접근을 통해 일정조건을 만족할때만 변수가 초기화 되도록 하였다.
생성자의 접근 제어자
생성자에 접근 제어자를 사용함으로써 인스턴스의 생성을 제한할 수 있다.
생성자의 접근 제어자를 private으로 지정하면, 외부에서 생성자에 접근할 수 없으므로,
인스턴스를 생성할 수 없게 된다.
class Singleton(){
private Singleton(){ }
}
인스턴스를 생성할 수 없게 되었으므로,
인스턴스를 생성해서 반환해주는 public메소드를 제공함으로써
외부에서 이 클래스의 인스턴스를 사용하도록 다음과 같이 해주었다.
class Singleton(){
private static Singleton s = new Singleton() ; //getInstance에서 사용될 수 있도록 미리 생성되어야 하므로 static으로 선언해야 한다.
private Singleton() { }
public static Singleton getIntance() {
return s;
}
}
생성자가 private인 클래스는 다른 클래스의 조상이 될 수 없다.
왜냐하면 자손클래스의 인스턴스를 생성할 때 조상클래스의 생성자를 호출해야하는데,
생성자의 접근제어자가 private이므로 자손클래스에서 호출하는 것이 불가능하기 때문이다.
그래서 클래스 앞에 final을 추가하여 상속할 수 없는 클래스라는 것을 알리는 것이 좋다.
'JAVA > Basic' 카테고리의 다른 글
[JAVA-basic] 다형성(2) (0) | 2021.08.24 |
---|---|
[JAVA-basic] 다형성 (0) | 2021.08.24 |
[JAVA-basic] 오버라이딩 (0) | 2021.08.19 |
[JAVA-basic] 상속(2) (0) | 2021.08.18 |
[JAVA-basic] 상속 (0) | 2021.08.18 |