캡슐화란 특정 객체 안에 관련된 속성과 기능을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것을 말합니다.
- 데이터 보호의 목적
- 내부적으로만 사용되는 데이터에 대한 불필요한 외부 노출을 방지하기 위함
캡슐화의 가장 큰 장점은 정보 은닉(Data Hiding)
패키지란 특정한 목적을 공유하는 클래스와 인터페이스의 묶음을 의미한다.
자바에서 패키지는 물리적인 하나의 디렉토리라 할 수 있으며
이 디렉토리는 하나의 계층구조를 가지고 있는데, 계층 구조간 구분은 점(.)으로 표현
// 패키지를 생성했을 때
package practicepack.test; // 패키지 구문 포함. 패키지가 없다면 구문 필요없음
public class PackageEx {
}
패키지로 클래스를 묶어놓는 것의 장점은
Import문은 다른 패키지 내의 클래스를 사용하기 위해 사용하며, 패키지 구문과 클래스문 사이에 작성한다.
package practicepack.test2; // import문을 사용하는 경우
import practicepack.test.ExampleImp // import문 작성
public class PackageImp {
public static void main(String[] args) {
ExampleImp x = new ExampleImp(); // 이제 패키지명을 생략 가능
}
}
import문은 컴파일 시에 처리가되므로 프로그램의 성능에는 영향을 주지 않는다.
자바에서 제어자는 클래스, 필드, 메서드, 생성자 등에 부가적인 의미를 부여하는 키워드를 의미
자바에서 제어자는 크게 접근 제어자와 기타 제어자로 구분 한다.
public(접근 제한 없음) > protected(동일 패키지 + 하위클래스) > default(동일 패키지) > private(동일 클래스)
package package1; // 패키지명 package1
//파일명: Parent.java
class Test { // Test 클래스의 접근 제어자는 default
public static void main(String[] args) {
Parent p = new Parent();
// System.out.println(p.a); // 동일 클래스가 아니기 때문에 에러발생!
System.out.println(p.b);
System.out.println(p.c);
System.out.println(p.d);
}
}
public class Parent { // Parent 클래스의 접근 제어자는 public
private int a = 1; // a,b,c,d에 각각 private, default, protected, public 접근제어자 지정
int b = 2;
protected int c = 3;
public int d = 4;
public void printEach() { // 동일 클래스이기 때문에 에러발생하지 않음
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(d);
}
}
// 출력값
2
3
4
package package2; // package2
//파일명 Test2.java
import package1.Parent;
class Child extends package1.Parent { // package1으로부터 Parent 클래스를 상속
public void printEach() {
// System.out.println(a); // 에러 발생!
// System.out.println(b);
System.out.println(c); // 다른 패키지의 하위 클래스
System.out.println(d);
}
}
public class Test2 {
public static void main(String[] args) {
Parent p = new Parent();
// System.out.println(p.a); // public을 제외한 모든 호출 에러!
// System.out.println(p.b);
// System.out.println(p.c);
System.out.println(p.d);
}
}
package1의 Parent 클래스로부터 상속을 받아 만들어진 Child 클래스를 살펴보면, 같은 클래스와 같은 패키지 안에 있는 private(a)과 default(b) 제어접근자를 사용하는 멤버에는 접근이 불가능한 반면
다른 패키지의 하위 클래스에 접근가능한 protected(c)와 어디서나 접근이 가능한 public(d)에는 접근이 가능하다는 사실을 확인
Test2 클래스는 상속받은 클래스가 아니기 때문에 다시 protected(c)에는 접근이 불가능하고 public(d)에만 접근이 가능한 것을 확인할 수 있다.
객체지향의 캡슐화의 목적을 달성하면서도 데이터의 변경이 필요한 경우 어떻게 할 수 있나!?
public class GetterSetterTest {
public static void main(String[] args) {
Worker w = new Worker();
w.setName("김코딩");
w.setAge(30);
w.setId(5);
String name = w.getName();
System.out.println("근로자의 이름은 " + name);
int age = w.getAge();
System.out.println("근로자의 나이는 " + age);
int id = w.getId();
System.out.println("근로자의 ID는 " + id);
}
}
class Worker {
private String name; // 변수의 은닉화. 외부로부터 접근 불가
private int age;
private int id;
public String getName() { // 멤버변수의 값
return name;
}
public void setName(String name) { // 멤버변수의 값 변경
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age < 1) return;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
//Output
근로자의 이름은 김코딩
근로자의 나이는 30
근로자의 ID는 5
setter 메서드는 외부에서 메서드에 접근하여 조건에 맞을 경우 데이터 값을 변경 가능하게 해준다.
getter 메서드는 이렇게 설정한 특정 데이터를 읽어오는 데 사용하는 메서드