제이자
제어자(modifier)는 클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다.
접근 제어자 public, protected, (default), private
그 외 static, final, abstract, native, transient, synchronized, volatile, strictfp
제어자는 클래스나 멤버 변수와 메서드에 주로 사용되며, 하나의 대상에 대해서 여러 제어자를 조합하여 사용하는 것이 가능하다.
단, 접근 제어자는 한 번에 네 가지 중 하나만 선택해서 사용할 수 있다.
Static
클래스 변수(static멤버변수)는 인스턴스에 관계없이 같은 값을 갖는다. 그 이유는 하나의 변수를 모든 인스턴스가 공유하기 때문이다.
static이 붙은 멤버변수와 메서드, 그리고 초기화 블럭은 인스턴스가 아닌 클래스에 관계된 것이기 때문에 인스턴스를 생성하지 않고도 사용할 수 있다.
인스턴스 메서드와 static메서드의 근본적인 차이는 메서드 내에서 인스턴스 멤버를 사용하는가의 여부에 있다.
static이 사용될 수 있는 곳 : 멤버변수, 메서드, 초기화 블럭
class SaticTest{
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;
}
}
final
변수에 사용되면 값을 변경할 수 없는 상수가 되며, 메서드에 사용되면 오버라이딩을 할 수 없게 되고 클래스에 사용되면 자신을 확장하는 자손 클래스를 정의하지 못하게 된다.
final이 사용될 수 있는 곳 : 클래스, 메서드, 멤버 변수, 지역변수
final class FinalTest{ // 조상이 될 수 없는 클래스
final int MAX_SIZE = 10; // 값을 변경할 수 없는 멤버변수(상수)
final void getMaxSize(){ // 오버라이딩할 수 없는 메서드(변경불가)
final int LV = MAX_SIZE; // 값을 변경할 수 없는 지역변수(상수)
return MAX_SIZE;
}
}
abstract
메서드의 선언부만 작성하고 실제 수행 내용은 구현하지 않은 추상 메서드를 선언하는 데 사용된다.
그리고 클래스에 사용되어 클래스 내에 추상 메서드가 존재한다는 것을 쉽게 알 수 있게 한다.
abstract가 사용될 수 있는 곳 클래스, 메서드
대상 | 의미 |
클래스 | 클래스 내에 추상 메서드가 선언되어 있음을 의미한다. |
메서드 | 선언부만 작성하고 구현부는 작성하지 않은 추상 메서드임을 알린다. |
abstract class AbstractTest { // 추상클래스(추상 메서드를 포함한 클래스)
abstract void move(); // 추상메서드(구현부가 없는 메서드)
}
추상 클래스는 아직 완성되지 않은 메서드가 존재하는 ‘미완성 설계도’이므로 인스턴스를 생성할 수 없다.
AbstractTest a = new AbstractTest(); // 에러. 추상 클래스의 인스턴스 생성 불가
접근 제어자(Access Modifier)
접근 제어자는 멤버 또는 클래스에 사용되어, 해당 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.
클래스나 멤버 변수, 메서드, 생성자에 접근제어자가 지정되어 있지 않다면, 접근제어자가 default임을 뜻한다. (default 생략 )
접근 제어자가 사용될 수 있는 곳 : 클래스, 멤버 변수, 메서드, 생성자
private : 같은 클래스 내에서만 접근이 가능하다.
(default) : 같은 패키지 내에서만 접근이 가능하다.
protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능하다.
public : 접근 제한이 전혀 없다.
접근 범위가 넓은 쪽에서 좁은 쪽의 순으로 왼쪽부터 나열하면 다음과 같다.
접근제한없음 같은 패키지+자손 같은 패키지 같은 클래스
public > protected > (default) > private
public은 접근 제한이 전혀 없는 것이고, private은 같은 클래스 내에서만 사용하도록 제한하는 가장 높은 제한이다.
protected는 패키지에 관계없이 상속 관계에 있는 자손 클래스에서 접근할 수 있도록 하는 것이 제한 목적이지만, 같은 패키지 내에서도 접근이 가능하기 때문에 protected가 default보다 접근 범위가 더 넓다.
캡슐화와 접근 제어자
- 클래스나 멤버, 주로 멤버에 접근 제어자를 사용하는 이유는 클래스의 내부에 선언된 데이터를 보호하기 위함
- 데이터가 유효한 값을 유지하도록 , 또는 비밀번호와 같은 데이터를 외부에서 함부로 변경하지 못하도록 하기 위해서는 외부로부터 접근을 제한하는 것이 필요하다.
- 클래스 내에서만 사용되는, 내부 작업을 위해 임시로 사용되는 멤버 변수나 부분 작업을 처리하기 위한 메서드 등의 멤버들을 클래스 내부에 감추기 위함
- 외부에서 접근할 필요가 없는 멤버들을 private으로 지정하여 외부에 노출시키지 않음으로써 복잡성을 줄일 수 있다.
이것을 데이터 감추기(data hiding)라고 하며, 객체지향 개념의 캡슐화(encapsulation)에 해당하는 내용이다.
접근 제어자를 사용하는 이유
1. 외부로부터 데이터를 보호하기 위해서
2. 외부에는 불필요한, 내부적으로만 사용되는, 부분을 감추기 위해서
예시
시간을 표시하기 위한 클래스 Time이 다음과 같이 정의되어 있을 때, 이 클래스의 인스턴스를 생성한 다음, 멤버 변수에 직접 접근하여 값을 변경할 수 있다.
멤버변수 hour는 0보다 같거나 크고 24보다는 작은 범위의 값을 가져야 하지만 위의 코드에서처럼 잘못된 값을 지정한다고 해도 이것을 막을 방법은 없다.
이런 경우 멤버 변수를 private이나 protected로 제한하고 멤버 변수의 값을 읽고 변경할 수 있는 public메서드를 제공함으로써 간접적으로 멤버변수의 값을 다룰 수 있도록 하는 것이 바람직하다.
public class Time {
private int hour;
private int minute;
private int second;
public int getHour() { return hour;}
public void setHour(int hour) {
if (hour < 0 || hour > 23) return;
this.hour = hour;
}
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;
}
}
만일 상속을 통해 확장될 것이 예상되는 클래스라면 멤버에 접근 제한을 주되 자손 클래스에서 접근하는 것이 가능하도록 하기 위해 private대신 protected를 사용한다. private이 붙은 멤버는 자손 클래스에서도 접근이 불가능하기 때문이다.
보통멤버 변수의 값을 읽는 메서드의 이름을 ‘get멤버 변수 이름’으로으로 하고, 멤버 변수의 값을 변경하는 메서드의 이름을’set멤버 변수 이름’으로 한다. 반드시 그렇게 해야 하는 것은 아니지만 암묵적인 규칙이므로 특별한 이유가 없는 한 따르도록 하자. 그리고 get으로 시작하는 메서드를 ‘겟터(getter)’, set으로 시작하는 메서드를 ‘셋터(setter)’라고 부른다.
추가 설명 - 객체지향의 사실과 오해
어떤 사용자도 직접 기계를 열어 기계 내부의 상태를 직접 접근하려고 하지 않는다.
객체 기계가 제공하는 버튼을 통해서만(Getter, Setter) 상태에 접근할 수 있다는 점은 객체의 캡슐화를 강조한다.
'Server > 자바의정석' 카테고리의 다른 글
[Java 입문] 추상(abstract) & 인터페이스(Interface) (0) | 2022.09.28 |
---|---|
[Java 입문] 다형성(polymorphism) (0) | 2022.09.28 |
[Java 입문] Super (0) | 2022.09.28 |
[Java 입문] 상속 (0) | 2022.09.27 |
[Java 입문] 생성자(constructor) (0) | 2022.09.27 |