자바 패키지: 네임스페이스 관리, 접근 제어, 코드 구성
자바에서 패키지는 이름 충돌 방지, 접근 제어, 클래스/인터페이스/열거형/애노테이션의 검색·위치 파악·사용 용이성을 위해 사용됩니다.
패키지(Package)는 관련 타입들(클래스, 인터페이스, 열거형, 애노테이션)을 그룹화하여 접근 보호와 네임스페이스 관리를 제공하는 것으로 정의할 수 있습니다.
자바의 기존 패키지들:
- java.lang - 기본 클래스들 번들
- java.io - 입출력 기능 클래스들 번들
프로그래머는 직접 패키지를 정의하여 클래스/인터페이스 등을 그룹화할 수 있습니다. 직접 구현한 관련 클래스들을 그룹화하는 것은 좋은 관행으로, 프로그래머가 해당 클래스/인터페이스/열거형/애노테이션들이 관련되어 있음을 쉽게 파악할 수 있게 합니다.
패키지가 새 네임스페이스를 생성하므로 다른 패키지의 이름들과 충돌이 없습니다. 패키지를 사용하면 접근 제어가 더 쉽고 관련 클래스들을 찾기도 더 쉽습니다.
패키지 생성
패키지를 생성할 때 패키지 이름을 정하고, 해당 패키지에 포함시키고 싶은 클래스/인터페이스/열거형/애노테이션 타입이 들어있는 모든 소스 파일의 최상단에 그 이름과 함께 package 문을 포함해야 합니다.
package 문은 소스 파일의 첫 번째 줄이어야 합니다. 각 소스 파일에는 오직 하나의 package 문만 있을 수 있으며, 이는 파일의 모든 타입에 적용됩니다.
package 문을 사용하지 않으면 클래스, 인터페이스, 열거형, 애노테이션 타입들은 현재 기본 패키지에 놓이게 됩니다.
package 문이 있는 자바 프로그램을 컴파일하려면 -d 옵션을 사용해야 합니다.
javac -d Destination_folder file_name.java
그러면 지정된 대상 폴더에 패키지 이름의 폴더가 생성되고 컴파일된 클래스 파일들이 그 폴더에 놓입니다.
예제: animals 패키지 생성
animals라는 패키지를 만드는 예제입니다. 패키지 이름은 클래스/인터페이스 이름과의 충돌을 피하기 위해 소문자 사용하는 것이 좋습니다.
다음 패키지 예제에는 animals라는 인터페이스가 포함됩니다.
/* File name: Animal.java */
package animals;
interface Animal {
public void eat();
public void travel();
}
이제 같은 패키지 animals에서 위 인터페이스를 구현해 보겠습니다.
package animals;
/* File name: MammalInt.java */
public class MammalInt implements Animal {
public void eat() {
System.out.println("Mammal eats");
}
public void travel() {
System.out.println("Mammal travels");
}
public int noOfLegs() { return 0; }
public static void main(String args[]) {
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
다음과 같이 자바 파일들을 컴파일하세요.
$ javac -d . Animal.java
$ javac -d . MammalInt.java
이제 현재 디렉터리에 animals라는 패키지/폴더가 생성되고 클래스 파일들이 그 안에 놓입니다.
패키지 내의 클래스 파일을 실행하여 결과를 얻을 수 있습니다.
Mammal eats
Mammal travels
import 키워드
같은 패키지 내의 다른 클래스를 사용하려면 패키지 이름을 사용할 필요가 없습니다. 같은 패키지 안의 클래스들은 특별한 구문 없이 서로를 찾습니다.
예제
이미 Employee를 포함하는 payroll 패키지에 Boss 클래스를 추가합니다. Boss는 payroll 접두사 없이 Employee 클래스를 참조할 수 있습니다.
package payroll;
public class Boss {
public void payEmployee(Employee e) {
e.mailCheck();
}
}
Employee 클래스가 payroll 패키지에 없다면? Boss 클래스는 다른 패키지의 클래스를 참조하기 위해 다음 기법 중 하나를 사용해야 합니다.
- 클래스의 완전히 정규화된 이름 사용. 예:
payroll.Employee
import 키워드와 와일드카드(*)로 패키지 임포트. 예: import payroll.*;
import 키워드로 클래스 자체 임포트. 예: import payroll.Employee;
참고 - 클래스 파일에는 임의의 개수 import 문이 있을 수 있습니다. import 문들은 package 문 다음에, 클래스 선언 전에 나타나야 합니다.
패키지의 디렉터리 구조
클래스가 패키지에 놓이면 두 가지 주요 결과가 발생합니다.
- 패키지 이름이 클래스 이름의 일부가 됨 (앞서 논의)
- 패키지 이름이 해당 바이트코드가 위치한 디렉터리 구조와 일치해야 함
자바에서 파일을 관리하는 간단한 방법:
- 클래스, 인터페이스, 열거형, 애노테이션 타입의 소스 코드를 타입의 단순 이름을 파일명으로 하고 확장자를 .java로 한 텍스트 파일에 저장
예:
// File Name: Car.java
package vehicle;
public class Car {
// 클래스 구현
}
이제 소스 파일을 패키지 이름을 반영하는 디렉터리에 넣습니다.
....\vehicle\Car.java
이제 정규화된 클래스 이름과 경로명은 다음과 같습니다.
- 클래스 이름 → vehicle.Car
- 경로명 → vehicle\Car.java (윈도우)
일반적으로 회사는 역순 인터넷 도메인 이름을 패키지 이름으로 사용합니다.
예 - 회사 인터넷 도메인 이름이 apple.com이면 모든 패키지 이름은 com.apple로 시작. 패키지 이름의 각 구성요소는 하위 디렉터리에 대응.
예 - 회사에 com.apple.computers 패키지가 있고 Dell.java 소스 파일이 있다면, 다음과 같은 일련의 하위 디렉터리에 들어갑니다.
....\com\apple\computers\Dell.java
컴파일 시 컴파일러는 정의된 각 클래스/인터페이스/열거형에 대해 서로 다른 출력 파일을 생성합니다. 출력 파일의 기본 이름은 타입 이름이고 확장자는 .class입니다.
예:
// File Name: Dell.java
package com.apple.computers;
public class Dell { }
class Ups { }
이 파일을 -d 옵션으로 컴파일:
$ javac -d . Dell.java
파일들은 다음과 같이 컴파일됩니다.
.\com\apple\computers\Dell.class
.\com\apple\computers\Ups.class
\com\apple\computers\에 정의된 모든 클래스나 인터페이스를 다음과 같이 임포트할 수 있습니다.
import com.apple.computers.*;
.java 소스 파일들처럼 컴파일된 .class 파일들도 패키지 이름을 반영하는 일련의 디렉터리에 있어야 합니다. 하지만 .class 파일의 경로가 .java 소스 파일의 경로와 반드시 같아야 하는 것은 아닙니다. 소스와 클래스 디렉터리를 별도로 배치할 수 있습니다.
\sources\com\apple\computers\Dell.java
\classes\com\apple\computers\Dell.class
이렇게 하면 소스를 공개하지 않고 클래스 디렉터리에 다른 프로그래머들이 접근하게 할 수 있습니다. 컴파일러와 JVM이 프로그램이 사용하는 모든 타입을 찾을 수 있도록 소스와 클래스 파일들을 이런 방식으로 관리해야 합니다.
클래스 디렉터리의 전체 경로 <path-two>\classes를 클래스 경로(class path)라고 하며, CLASSPATH 시스템 변수로 설정합니다. 컴파일러와 JVM은 클래스 경로에 패키지 이름을 추가하여 .class 파일의 경로를 구성합니다.
<path-two>\classes가 클래스 경로이고 패키지 이름이 com.apple.computers라면, 컴파일러와 JVM은 <path-two>\classes\com\apple\computers에서 .class 파일들을 찾습니다.
클래스 경로에는 여러 경로가 포함될 수 있습니다. 여러 경로는 세미콜론(윈도우) 또는 콜론(유닉스)으로 구분합니다. 기본적으로 컴파일러와 JVM은 현재 디렉터리와 자바 플랫폼 클래스를 포함하는 JAR 파일을 검색하므로 이 디렉터리들은 자동으로 클래스 경로에 포함됩니다.
CLASSPATH 시스템 변수 설정
현재 CLASSPATH 변수를 표시하려면 윈도우와 유닉스(Bourne shell)에서 다음 명령어를 사용하세요.
- 윈도우 →
C:\> set CLASSPATH
- 유닉스 →
% echo $CLASSPATH
CLASSPATH 변수의 현재 내용을 삭제하려면:
- 윈도우 →
C:\> set CLASSPATH =
- 유닉스 →
% unset CLASSPATH; export CLASSPATH
CLASSPATH 변수를 설정하려면:
- 윈도우 →
set CLASSPATH = C:\users\jack\java\classes
- 유닉스 →
% CLASSPATH = /home/jack/java/classes; export CLASSPATH