김영한의 실전 자바 기본편 - 4일차
패키지
패키지: 이름 그대로 물건을 운송하기 위한 포장 용기나 그 포장 묶음을 뜻한다.
프로그램이 작고 단순해서 클래스가 몇개 없다면 상관없지만 매우 많은 클래스가 등장 하게 된다면 관련 있는 기능들을 분류해서 관리해야 한다.
- 패키지를 사용하는 경우 항상 코드 첫줄에 package test 과 같이 패키지 이름을 적어주어야한다.
- 같은 패키지에 있는 경우에는 패키지 경로를 생략해도된다.
- 패키지가 다르면 패키지 전체 경로를 포함해서 클래스를 적어주어야 한다.
패키지 - import
패키지가 다르다고 항상 전체 경로를 적어주는 것은 불편하다. 이때는 import를 사용하면 된다.
package pack;
import pack.a.User;
public class PackageMain2 {
public static void main(String[] args) {
Data data = new Data();
User user = new User();
}
}
- 코드에서 첫줄에는 package를 사용하고, 다음 줄에는 import를 사용할 수 있다.
- import를 사용하면 다른 패키지에 있는 클래스를 가져와서 사용할 수 있다.
- 특정 패키지에 포함된 모든 클래스를 포함해서 사용하고 싶으면 import 시점에 *(별) 을 사용하면 된다.
클래스 이름 중복
pack.a.User
pack.b.User
패키지 경로는 다르지만 클래스 이름이 둘다 User 인 경우가 있다.
같은 이름의 클래스가 있다면 import는 둘중 하나만 선택할 수 있다. 다른 나머지 하나는 전체 경로를 적어줘야한다.
package pack;
import pack.a.User;
public class PackageMain3 {
public static void main(String[] args) {
User user = new User();
pack.b.User userB = new pack.b.User();
}
}
패키지 규칙
- 패키지의 이름과 위치는 폴더 위치와 같아야 한다.
- 패키지 이름은 모두 소문자를 사용한다
- 패키지 이름의 앞 부분에는 일반적으로 회사의 도메인 이름을 거꾸로 사용한다. ex) com.company.myapp
- 필수는 아니지만 외부 라이브러리와 함께 사용되면 같은 패키지에 같은 클래스 이름이 존재 할 수 있다.
- 도메인 이름을 거꾸로 사용하면 이런 문제를 방지할 수 있다.
접근 제어자
접근 제어자 종류
- private : 모든 외부 호출을 막는다.
- default(package-private) : 같은 패키지안에서 호출은 허용한다.
- protected: 같은 패키지안에서 호출은 허용한다. 패키지가 달라도 상속 관계의 호출은 허용한다.
- public: 모든 외부 호출을 허용한다.
private이 가장 많이 차단하고 public이 가장 많이 허용한다
private -> default -> protected -> public
접근제어자를 명시하지 않으면 같은 패키지안에서 호출을 허용하는 default 접근 제어자가 적용된다.
접근 제어자 사용 위치
클래스 레벨에도 일부 접근 제어자를 사용할 수 있다.
public class Speaker { //클래스 레벨
private int volume; //필드
public Speaker(int volume) {} //생성자
public void volumeUp() {} //메서드
public void volumeDown() {}
public void showVolume() {}
}
접근 제어자 사용 - 클래스 레벨
클래스 레벨의 접근 제어자 규칙
- 클래스 레벨의 접근 제어자는 public, default만 사용할 수 있다.
- private, protected는 사용할 수 없다.
- public 클래스는 반드시 파일명과 이름이 같아야 한다.
- 하나의 자바 파일에는 public 클래스는 하나만 등장할 수 있다.
- 하나의 자바 파일에 default 접근 제어자를 사용하는 클래스는 무한정 만들 수 있다.
캡슐화
캡슐화는 데이터와 해당 데이터를 처리하는 메서드를 하나로 묶어서 외부에서의 접근을 제한하는 것을 말한다.
캡슐화를 통해 데이터의 직접적인 변경을 방지하거나 제한할 수 있다.
정리하자면 캡슐화는 속성과 기능을 하나로 묶고, 외부에 꼭 필요한 기능만 노출하고 나머지는 모두 내부로 숨기는 것이다.
캡슐화에서 가장 필수로 숨겨야 하는 것은 속성(데이터)이다.
객체 내부의 데이터를 외부에서 함부로 접근하게 두면, 클래스 안에 로직을 무시하고 데이터를 변경할 수 있다.
객체의 기능 중에서 외부에서 사용하지 않고 내부에서만 사용하는 기능들이 있다. 이런 기능도 모두 감추는 것이 좋다.
package access;
public class BankAccount {
private int balance;
public BankAccount() {
balance = 0;
}
//public 메서드 : deposit
public void deposit(int amount) {
if(isAmountValid(amount)){
balance += amount;
}else{
System.out.println("유효하지 않은 금액입니다.");
}
}
//public 메서드 : withdraw
public void withdraw(int amount){
if(isAmountValid(amount) && balance - amount >= 0){
balance -= amount;
}else{
System.out.println("유효하지 않은 금액이거나 잔액이 부족합니다.");
}
}
//public 메서드: getBalance
public int getBalance(){
return balance;
}
private boolean isAmountValid(int amount){
//금액이 0보다 커야함
return amount > 0;
}
}
package access;
public class BankAccountMain {
public static void main(String[] args) {
BankAccount account = new BankAccount();
account.deposit(10000);
account.withdraw(3000);
System.out.println("" + account.getBalance());
}
}
캡슐화된 예제를 실습했다.
private
- balance : 데이터 필드는 외부에 직접 노출하지 않는다.
- isAmountValid() : 입력 금액을 검증하는 기능은 내부에서만 필요한 기능이다. private 을 사용한다.
public
- deposit() : 입금
- withdraw() : 출금
- getBalance(): 잔고
BankAccount를 사용하는 입장에서는 단 3가지 메서드만 알면 된다. 나머지 내용은 모두 BankAccount 내부에 숨어있다.
isAmountValid()를 외부에 노출하게 되면 개발자 입장에서는 사용할 수 있는 메서드가 하나 더 늘게되고 입금과 출금 전에 본인이 먼저 isAmountValid 를 사용해서 검증해야 하는 의문을 가질 것이다.
접근 제어자와 캡슐화를 통해 데이터를 안전하게 보호하고, 개발자 입장에서 해당 기능을 사용하는 복잡도도 낮출 수 있다.
Reference