객체의 속성과 기능을 캡슐(Class)로 만들어, 외부로부터 보호하는 것
비슷한 목적을 가진, 클래스와 인터페이스의 묶음
우리가 폴더에 비슷한 여러 파일을 묶어 저장하는 것과 동일하다.
package 패키지명;
이 작성되어야 한다.java.lang: 자바의 기본 클래스
java.util: 확장 클래스
java.io: 입출력 관련 클래스
다른 패키지를 사용하기 위한 구문
만약 Import를 사용하지 않는다면, 우리는 해당 클래스를 사용할 때마다 package 풀 네임을 작성해줘야 한다.
// import문을 사용하지 않는 경우, 다른 패키지 클래스 사용방법
package practicepack.test2;
public class PackageImp {
public static void main(String[] args) {
// 다른 패키지의 클래스
practicepack.test.ExampleImport example = new practicepack.test.ExampleImport();
}
}
import 문을 사용하면, 해당 클래스를 간단하게 선언할 수 있다.
package practicepack.test2; // import문을 사용하는 경우
import practicepack.test.ExampleImp // import문 작성
public class PackageImp {
public static void main(String[] args) {
ExampleImp x = new ExampleImp(); // 이제 패키지명을 생략 가능
}
}
✅ import문은
컴파일 시
에 처리가되므로 프로그램의 성능에는 영향을 주지 않습니다.
캡슐화를 만족하면서도, 데이터의 변경이 필요한 경우는 getter, setter를 사용한다.
클래스를 만들고, getter/setter를 만든다고 캡슐화가 된 것이 아니다!
캡슐화란 객체의 데이터 뿐만 아니라, 객체의 내부 기능까지 감추고 최소한의 기능만을 외부에 제공하는 것이다.
여기서 중요한 키워드는 1. 객체 간의 의존성과 2. 객체의 자율성 이다.
객체 간의 의존성을 줄여야 한다!
즉, 클래스 Car에 대한 것은 무조건 Car 내에서 해결해야 한다.
의존성을 줄인다면, Car 객체에서 문제가 발생했을 때, Car 클래스만 수정하면 된다.(수정 범위 최소화)
캡슐화를 하게 되면, 객체의 자율성이 보장된다.
예를 들어, Car 클래스와 Person 클래스가 있다고 생각해보자.
(코드 길이가 너무 길어 getter/setter/생성자는 생략하고 작성했다.)
1) Class 내부의 멤버 변수들은 private로 선언한다.
2) 멤버 변수들에 대한 getter, setter 메서드를 생성한다.
public class Car {
private String name;
private int fuelPercent = 100;
// 생성자, getter, setter 생략
// 메서드 - 시동걸기, 시동 끄기, 가기
public void on(){
System.out.println("시동을 겁니다. 부릉~");
}
public void off(){
System.out.println("시동을 끕니다. 힝");
}
public void go(){
System.out.println("부릉부릉");
}
}
public class Person {
private String name;
// 포함관계 - 사람이 자동차를 가지고 있기 때문에
private Car car;
// 생성자, getter, setter 생략
public void drive(){
car.on();
car.off();
car.go();
}
}
여기까지만 했을 때, 캡슐화가 완료된 줄 알았다.
하지만 Person 클래스의 drive 메서드에서 Car의 멤버 메서드가 3개나 사용됨을 볼 수 있다.(= 3개의 메서드가 외부로 노출되고 있다.)
아까 말했던 것처럼, 클래스 Car에 대한 것은 무조건 Car 내에서 해결해야 하며, 객체의 내부 기능을 최대한 감추고 최소한의 기능만을 외부에 제공해야 한다.
따라서 코드를 수정해보면, 다음과 같다.
public class Car {
private String name;
private int fuelPercent = 100;
// 생성자, getter, setter 생략
// 메서드 - 시동걸기, 시동 끄기, 가기
private void on(){
System.out.println("시동을 겁니다. 부릉~");
}
private void off(){
System.out.println("시동을 끕니다. 힝");
}
private void go(){
System.out.println("부릉부릉");
}
public void operate(){
if(fuelPercent<= 0){
System.out.println("연료가 부족합니다!");
}
else{
on();
go();
off();
}
}
}
public class Person {
private String name;
// 포함관계 - 사람이 자동차를 가지고 있기 때문에
private Car car;
// 생성자, getter, setter 생략
public void drive(){
car.operate();
}
}
3) on, off, go 메서드들을 operate 메서드로 묶는다.
4) on, off, go 메서드들은 외부에 노출될 필요가 없으므로 private로, 외부에 노출할 operate 메서드만 public으로 선언한다.
✅ 외부에 노출을 최소화하고, 외부에 노출되는 것만 public으로 선언하며 나머지는 private로 선언한다.