제어자 (Modifier)
클래스, 변수, 메소드의 선언부에 함꼐 사용되어 부가적인 의미를 부여
•
제어자의 종류
◦
접근 제어자 : public, protected, default, private
◦
그 외 : static, final, abstract, native, transient, synchronized, volatile, stricfp
•
클래스, 멤버변수, 메소드에 주로 사용
•
하나의 대상에 대해 여러 제어자를 조합하여 사용하는 것도 가능
◦
접근 제어자는 넷 중 하나만 가능!
static - 클래스의, 공통적인
•
static이 사용될 수 있는 곳 : 멤버변수, 메소드, 초기화 블럭
•
멤버변수
◦
모든 인스턴스에 공통적으로 사용되는 클래스변수가 됨.
◦
클래스변수는 인스턴스를 생성하지 않고도 사용 가능
◦
클래스가 메모리에 로드될 떄 생성
•
메소드
◦
인스턴스를 생성하지 않고도 호출이 가능한 static 메소드가 됨.
◦
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;
}
}
Java
final - 마지막의, 변경될 수 없는
•
거의 모든 대상에 사용 가능
◦
클래스, 메소드, 멤버변수, 지역변수
•
클래스
◦
변경 및 확장 불가능한 클래스
◦
다른 클래스의 조상 불가능
•
메소드
◦
변경 불가능한 메소드
◦
오버라이딩을 통한 재정의 불가능
•
멤버변수 / 지역변수
◦
값을 변경할 수 없는 상수
final class FinalTest { // 조상이 될 수 없는 클래스
final int MAX_SIZE = 10; // 값을 변경할 수 없는 멤버변수 (상수)
final void getMaxSize() { // 오버라이딩 불가능한 메소드 (변경 불가)
final int LV = MAX_SIZE; // 값을 변경할 수 없는 지역변수(상수)
return MAX_SIZE;
}
}
Java
생성자를 이용한 final 멤버변수의 초기화
•
일반적으로 final이 붙은 변수는 상수이므로, 선언과 동시에 초기화
•
인스턴스의 경우 생성자에서 초기화 가능!
◦
클래스 내 매개변수를 갖는 생성자를 선언하여, 인스턴스 생성 시 final이 붙은 멤버변수를 초기화하는 데 필요한 값을 생성자의 매개변수로부터 제공받음.
→ 각 인스턴스마다 final이 붙은 멤버변수가 다른 값을 갖도록 하는 것이 가능
•
여러 종류의 값을 갖는 인스턴스지만, 한번 초기화된 값이 바뀌면 안되는 경우
FinalCardTest.java
abstract - 추상의, 미완성의
•
클래스
◦
클래스 내에 추상 메소드가 선언되어 있음을 의미
•
메소드
◦
선언부만 작성하고 구현부는 작성하지 않은 추상 메소드임을 알림.
•
아직 미완성된 메소드가 존재하는 미완성 설계도이므로, 인스턴스 생성 불가
abstract class AbastractTest { // 추상 클래스 (추상 메소드를 포함한 클래스)
abstract void move(); // 추상 메소드 (구현부가 없는 메소드)
}
Java
•
완성된 클래스에 abstract를 붙여 추상 클래스로 만드는 경우?
◦
아무런 내용이 없는 메소드들이 정의된 클래스는 인스턴스를 생성해봤자 의미가 없기 떄문에, 추상 클래스로 만들어 인스턴스 생성을 막음.
public abstract class WindowAdapter
implements WindowListener, WindowStateListener, WindowFocusListener {
public void windowOpened(WindowEvent e) { }
public void windowClosing(WindowEvent e) { }
public void windowClosed(WindowEvent e) { }
public void windowIconified(WindowEvent e) { }
...
}
Java
→ 클래스 자체는 쓸모가 없어보이지만, 특정 메소드만 오버라이딩하기엔 좋음!
접근 제어자 (Access Modifier)
멤버 또는 클래스에 사용되어, 해당 멤버나 클래스를 외부에서접근 못하도록 제한하는 역할
•
접근 제어자가 사용될 수 있는 곳 : 클래스, 멤버변수, 메소드, 생성자
◦
private : 같은 클래스 내에서만 접근 가능
◦
default : 같은 패키지 내에서만 접근 가능 (일반적으로 따로 명시하여 지정하진 않음)
◦
protected : 같은 패키지 내, 다른 패키지의 자손 클래스에서 접근 가능
◦
public : 자유롭게 접근 가능
•
클래스 : public, (default) 사용 가능
•
메소드 : public, protected, (default), private 전부 사용 가능
접근 제어자를 이용한 캡슐화
•
접근 제어자를 사용하는 이유?
◦
클래스 내부에 선언된 데이터를 보호하기 위해
◦
외부엔 불필요한, 내부적으로만 사용하는, 멤버변수나 메소드 등을 감추기 위해
•
외부로부터 접근을 제한하여 데이터를 감추는 것? → 객체 지향의 캡슐화
•
접근 제어자를 적절히 선택하여 접근 범위를 최소화하자!
◦
메소드의 오류를 검사할 때,
default, private 등 접근 제어자에 따라 확인해야 하는 범위가 달라짐.
•
public으로 자유로운 접근을 허용할 경우
public class Time {
public int hour;
public int minute;
public int second;
}
// 다음과 같이 허용되면 안되는 값으로 멤버변수를 변경하는 것이 가능함.
Time t = new Time();
t.hour = 25;
Java
•
private이나 protected로 접근 범위를 제한하고 멤버변수에 접근 가능한 메소드는 따로
public class Time {
// 상속을 통해 확장하여 자손 클래스에서 접근 가능하게 하려면 protected
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;
}
}
Java
TimeTest.java
생성자의 접근 제어자
•
생성자에 접근 제어자를 사용함으로써 인스턴스의 생성 제한 가능
•
보통 생성자의 접근 제어자는 클래스의 접근 제어자와 같지만, 다르게 지정도 가능
•
생성자의 접근 제어자를 private으로 지정
class Singleton {
private Singleton() {
...
}
...
}
Java
◦
외부에서 생성자에 접근 불가하므로, 인스턴스 생성 불가
◦
클래스 내부에선 인스턴스 생성 가능
•
인스턴스를 생성해 반환해주는 public 메소드를 제공하여
외부에서 인스턴스를 사용할 수 있게 → 사용 가능한 인스턴스 개수 제한 가능
class Singleton {
...
// getInstance()에서 사용될 수 있도록 인스턴스가 미리 생성되야 하므로 static
private static Singleton s = new Singletion();
private Singleton() {
...
}
// 인스턴스를 생성하지 않고도 호출할 수 있어야 하므로 static
public static Singleton getInstance() {
return s;
}
...
}
Java
•
private 클래스는 조상 클래스가 될 수 없다!
◦
자손 클래스의 인스턴스를 생성할 때 조상클래스의 생성자에 접근해야 하는데 불가능
→ 혼동을 피하기 위해 private 클래스는 final을 덧붙여 상속 불가능하다고 알릴 필요 有
•
인스턴스를 생성할 필요 없는 경우는 불필요한 접근을 막기 위해 private
◦
상수와 static 메소드로만 구성된 Math()
public final class Math {
private Math() { }
...
}
Java
SingletonTest.java
제어자의 조합
•
사용 가능한 제어자
◦
클래스 : public, (default), final, abstract
◦
메소드 : 모든 접근 제어자, final, abstract, static
◦
멤버변수 : 모든 접근 제어자, final, abstract
◦
지역변수 : final
•
제어자 사용 유의점
1.
메소드에 static과 abstract 함께 사용 불가
•
static은 내용이 있는 메소드에만 사용 가능
2.
클래스에 abstract과 final 함꼐 사용 불가
•
final은 확장 불가를 의미하지만, abstract는 상속(확장)을 통해서 유의미해짐.
3.
abstract 메소드의 접근 제어자로 private 불가
•
확장을 위해선 자손 클래스에서 접근이 가능해야 함.
4.
메소드에 private과 final 함께 사용할 필요 X
•
private 메소드는 오버라이딩이 불가하므로, 굳이 final을 더 써줄 필욘 없음.