📚 자바의 정석을 정리한 내용입니다.
접근 제어자가 아닌 제어자들로는
static, final, abstract, synchronized......등이 있다.
몇 가지만 소개한다.
멤버변수, 메서드, 초기화 블럭 앞에 붙는다.
static이 변수에 붙으면 모든 인스턴스에서 공통으로 사용되는 클래스 변수가 된다.
메서드에 붙으면 인스턴스 생성없이 호출할 수 있는 static 메서드가 된다.
클래스, 메서드, 멤버변수, 지역변수에 붙는다.
final이 붙으면 수정할 수 없는 메서드, 변수, 클래스가 된다.
즉,
final변수는 값을 변경할 수 없는 상수.
final method는 오버라이딩 불가.
final class는 extends 불가.
final 변수라도
생성자를 이용한 초기화를 통해 각 인스턴스마다 다른 값을 가지게 할 수 있다.
클래스, 메서드 앞에 붙는다.
클래스에 붙으면, 추상 메서드가 선언되어 있다는 것을 뜻한다.
메서드에 붙으면 선언부만 있고 구현부가 없는 추상 메서드라는 것을 뜻한다.
자바에는 public, protected, default, private 이렇게 4개의 접근 제어자가 있다.
이미지 출처 : https://www.softwaretestingmaterial.com/access-modifiers-in-java/
이미지 출처 : https://www.softwaretestingmaterial.com/access-modifiers-in-java/
왜 귀찮게 접근을 제어할까? 데이터를 보호하기 위해서다. 클래스 외부에서 데이터를 함부로 변경하지 못하도록 보호할 필요가 있다. 이것을 데이터 감추기Data Hiding이라고 한다. Data Hiding은 객체지향개념에서 캡슐화Encapsulation에 해당하는 내용이다.
내부에서만 이용하고, 외부에는 불필요한 부분을 감추기 위해 멤버를 private으로 지정하는데, 이것 역시 캡슐화에 해당한다.
만약 Time이라는 클래스를 이렇게 정의한다고 하자.
class Time {
int hour;
int minute;
int second;
}
이러면 누가 언제 어디서든 값을 바꿀 수 있기 때문에 위험하고, 또 시간으로 들어와야 하는 값에 25이나 33 같은 유효하지 않은 값을 넣을지도 모른다. 이 문제를 해결하기 위해서 이렇게 쓴다.
public class Time {
private int hour, minute, second;
Time(int hour, int minute, int second) {
setHour(hour);
setMinute(minute);
setSecond(second);
}
/* SETTER */
public int getHour() {
return hour;
}
public int getMinute() {
return minute;
}
public int getSecond() {
return second;
}
/*GETTER*/
public void setHour(int hour) {
if(hour < 0 || hour > 23) return; //유효성 검사
this.hour = hour;
}
public void setMinute(int minute) {
if(minute < 0 || minute > 59) return;
this.minute = minute;
}
public void setSecond(int second) {
if(second < 0 || second > 59) return;
this.second = second;
}
@Override
public String toString() {
return "Time{" +
"hour=" + hour +
", minute=" + minute +
", second=" + second +
'}';
}
}
public class TimeMain {
public static void main(String[] args) {
Time time = new Time(13, 47, 22);
//time.hour = 22; 이제 이런식으로 수정하지 않는다.
time.setHour(time.getHour()+1);
System.out.println(time);
}
}
이런 식으로 하면 Time클래스의 멤버를 직접 수정할 수 없다. setter를 거쳐야 하기 때문에 유효성 검사를 통해 유효하지 않은 값은 return할 수 있다.
일반적으로 생성자의 접근 제어자는 클래스의 접근 제어자와 일치하지만 다르게 지정할 수 있다.
private으로 지정하면 외부에서 생성자에 접근할 수 없다. 해당 클래스 내에 인스턴스를 return하는 static메서드를 선언해두면, private생성자여도 외부에서 인스턴스를 생성할 수 있다.
주의할 점은 private 생성자를 가진 클래스는 다른 클래스의 조상이 될 수 없다. 따라서 class 앞에 fianl을 명시적으로 붙이는 것이 좋다.
위에 말이 좀 어려웠는데 코드로 보면 쉽다.
final class Singleton {
private Singleton() {}
public static Singleton getInstance() {
return new Singleton();
}
}
public class SingletonTest {
public static void main(String[] args) {
//Singleton singleton = new Singleton(); //ERROR
Singleton singleton = Singleton.getInstance();
}
}