Java 언어의 특징 중 하나는 캡슐화(Encapsulation)이다.
캡슐화 :
객체의 내부 구조 및 데이터를 캡슐처럼 감싸 외부에서 직접 볼 수 없게 은닉하여 보호하는 것
캡슐화를 위해 클래스, 멤버 변수(필드), 멤버 함수(메서드), 생성자 등에 외부에서 접근 가능 범위를 제어하는 접근 제어자를 지정할 수 있다.
접근 제어자에는 private, protected, default, public 총 4가지의 접근 제어자가 있고 각각의 접근 범위는 다음과 같다.
클래스의 경우 public, default만 지정 가능하다.
다시 말해 다른 패키지에서 해당 클래스를 접근하고자 한다면 public 지정을 해줘야한다.
여담으로 C++에서는 접근 제어자가 public, protected, private으로 3가지가 있다.
C++에서는 기본 접근 제어자가 private이다.class Person { string sid; // private public: Person(string sid) { this->sid = sid; } void getSid() { cout << this->sid << endl; } }; // C++ 클래스에선 세미 콜론 int main(void) { Person p1("11-22-33"); p1.getSid(); cout << p1.sid; // 접근 불가 return 0; }반면 Java에서는 기본 접근 제어자가 default이다.
class Person { // default 클래스 : 같은 패키지에서 접근 가능 String sid; // default 필드 : 같은 패키지에서 접근 가능 Person(String sid) { this.sid = sid; } public void getSid() { System.out.println(this.sid); } } public class Test { public static void main(String[] args) { Person p1 = new Person("11-22-33"); p1.getSid(); System.out.println(p1.sid); // 접근 가능 } }
우선 private의 경우 대개 멤버 변수에 적용하여 외부에서의 직접적인 접근을 막는다.
대신 생성자 함수를 통한 초기화나 getter/setter를 통한 접근이 가능하게끔 구현한다.
예를 들어 다음과 같이 작성한다.
class Person{
private String socialId;
Person(String socialId){
this.socialId = socialId;
}
public String getSid(){
return this.socialId;
}
public void setSid(String socialId){
this.socialId = socialId;
}
}
public class test {
public static void main(String[] args) {
Person p1 = new Person("11-22-33"); // 생성자를 이용한 필드 초기화
p1.socialId = "11-22-44"; // 접근 불가
p1.setSid("11-22-44"); // setter를 이용한 필드값 변경
}
}
protected의 경우 상속 관계에 있는 클래스에서 접근이 가능하다.
예를 들어 다음 코드와 같이 private으로 접근제어가 지정된 socialId 필드에 대해서는 오류가 난다.
public class Person{
private String socialId;
}
public class Student extends Person {
private String studentId;
Student(String socialId, String studentId){
super.socialId = socialId; // 접근 불가
this.studentId = studentId;
}
}
하지만 socialId가 protected 로 지정되었다면 오류가 발생하지 않는다.
public class Person{
protected String socialId;
}
public class Student extends Person {
private String studentId;
Student(String socialId, String studentId){
super.socialId = socialId;
this.studentId = studentId;
}
}
또한 다른 패키지에 위치해있더라도 오류가 발생하지 않는다.
package person;
public class Person{ // default일 경우 외부 패키지에서 접근 불가
protected String socialId;
}
package student;
import person.Person; // Person 임포트
class Student extends Person {
private String studentId;
Student(String socialId, String studentId){
super.socialId = socialId;
this.studentId = studentId;
}
}
default의 경우 같은 패키지내에서만 접근이 가능하다.
위 예시를 그대로 가져와보자면
package person;
class Person{ // student 패키지에서 접근 불가
protected String socialId;
}
Person 클래스의 접근 제어자는 default이므로 외부 패키지에서 접근할 수 없다.