패키지라는 단어를 실생활에서 사용할 때는 묶음 상품의 의미로 사용한다. 통기타 패키지에 튜너, 스트랩, 보면대 등이 함께 들어있는 것처럼. 컴퓨터에서는 연관있는 파일을 트리구조로 묶어 표현한다. 연관성을 기준으로 폴더를 나누고 파일을 잘 넣어두어야 컴퓨터에 파일이 많아지고 복잡해질수록 빠르고 정확하게 원하는 파일을 잘 찾을 수 있게 된다.
├── 자바스터디
├── 자바 스터디 일정.xlsx
└── 자바 스터디 그림.pptx
자바의 패키지는 묶음 상품과 디렉토리 구조의 트리 구조 처럼, 연관있는 클래스 파일들을 묶어둘 뿐 아니라 더 나아가, 패키지 기준의 namespace를 구성하기 위해 쓰인다.
사용자가 정의하는 패키지도 있지만, 자바 언어 자체에 포함된 package들을 먼저 언급하고 넘어간다. 대표적으로 java.lang
과 java.util
이 있다. 두 패키지의 멤버들을 알고, 활용할 줄 안다면 기본적인 자바 프로그래밍은 가능하다.
java.lang
에는 .java
의 소스 파일에 import하지 않아도 default로 사용할 수 있는 패키지 멤버들이 포함되어 있다.
java.util
의 대표적 멤버는 다양한 데이터 구조 인터페이스들이 포함된 Collection framewrok이다. Collection의 구현체 네이밍은 보통 [구현방식][상속받은 인터페이스]의 형태이다. LinkedList는 List와 Deque 인터페이스를 다중 상속받았다.
📌 중요하고 자주 사용되는 구현체들은 bold 표시 하였다.
package는 optional이지만 대부분의 클래스 파일은 package를 가진다. 파일에 선언할 때는 파일 시작부분에 package 키워드와 함께 패키지를 적어주고, 세미콜론으로 마무리한다.
package tina.problemsolving.baekjoon;
패키지의 네이밍 컨벤션은 도메인 순서와 반대로 나열하는 것이 일반적이다.sample.naver.com
이라는 도메인 이름이 있다면 패키지를 만들때는 com.naver.sample
이런 식으로 선언한다. 역순인게 자연스러운 이유가 패키지는 여러 개의 서브 패키지가 hierarchical하게 연결되고, 범위가 큰 것에서 작은 것으로 좁혀진 후, dot 연산자를 통해 클래스의 기능을 접근해서 사용하기 때문이다.
변수의 scope를 정리하면서 접근 지시자를 정리했다. 그때 접근 기준 중에 package가 있었고, 접근 지시자를 써주지 않으면 패키지 안에서의 namespace를 가진다.
class | package | subclass | global | |
---|---|---|---|---|
private | ⭕ | ❌ | ❌ | ❌ |
(default) | ⭕ | ⭕ | ❌ | ❌ |
protected | ⭕ | ⭕ | ⭕ | ❌ |
public | ⭕ | ⭕ | ⭕ | ⭕ |
패키지 안에서의 namespace를 가지는 것이 어떤 의미가 있을까? 바로 동일한 이름의 클래스를 식별할 수 있게 된다. 프로그래밍을 하다보면 개별 라이브러리나 프레임워크가 동일한 이름의 클래스를 가지는 경우가 있다. 이럴때, import 키워드를 통해 fully qualified class nameFQCN을 적어줌으로써 소속을 명확히 하고, 이름의 unique함을 보장할 수 있게된다.
import는 수입하다는 뜻인데, 다른 패키지의 기능을 사용하기 위해 사용하는 키워드이다. 특정 패키지의 멤버를 참조해서 사용하는 방식이다.
import java.util.ArrayList;
import java.util.List;
...
List<Integer> list = new ArrayList<>(); // new java.util.ArrayList<>();
java.util.ArrayList
처럼 FQCN을 참조하여 사용할수도 있지만, import 키워드를 통해 ArrayList와 List를 가져왔으니 바로 참조해서 사용할 수 있다.
패키지 멤버는 globally unique name을 가지는 것이 또 중요한 이유는 의도하지 않은 라이브러리의 패키지의 멤버를 참조함으로써 발생하는 문제 때문이다. 인텔리제이는 Ctrl + Alt + O
를 통해 자동 임포트를 해주는 기능이 있는데, 자바에 package 기능이 없었거나 package를 제대로 확인하지 않고 다른 패키지 멤버가 import 됐을 경우에는 큰 문제가 생길 수 있을 것이다.
후자의 경우 그 코드가 그대로 Github이나 Gitlab에 올라가게 된다면..? 만약 패키지 멤버의 이름도 같고 각 멤버의 메소드 네임도 같았다면..? 기능 확인 없이 merge되고 그대로 배포되었다면..사소해보이는 문제가 골치를 아프게 하기 마련이니 코드를 유심히 읽어보고, 테스트하는 습관과 문화는 필수적이라는 생각이 든다.
Anyway..만약 다른 패키지의 동일한 이름을 가진 멤버를 사용해야 한다면 다음의 import는 에러가 발생하므로, 둘중 하나만 멤버 기준으로 import하고 다른 하나의 멤버를 절대 경로 접근하듯 full name을 적어서 접근하거나 둘다 full name을 적어 사용해야 한다.
import apackage.Aclass;
import bpackage.Aclass;
에러 메세지: apackage.Aclass is already defined in a single-type import
첫번째 포스팅에서 터미널에서 자바 프로그램 컴파일하고 실행하는 방법을 간단하게 언급했다. 자바 소스 파일은 javac 명령어를 통해 바이트 코드 형태의 클래스 파일로 번역되는데, JVM이 해당 클래스 파일의 위치를 찾을수 있도록 그 경로를 알려주는 것이 classpath이다.
보통 다른 라이브러리의 클래스 파일을 사용할 필요가 있을 때 classpath를 사용한다. 가장 일반적인 활용은 자바 언어 자체의 lib에 대한 classpath를 설정하는 것이다. 환경변수를 써도 되고, 명령어 옵션 중에 classpath를 넣어서 써도 된다. 여러개의 클래스 파일을 참조하는 경우엔 세미콜론을 통해 덧붙여 사용하면 된다.
$ javac -classpath ./lib/library.jar Aclass.java
$ java -classpath .;./lib/library.jar Aclass
📌 시스템 환경변수를 사용할 수도 있지만, 모든 프로젝트에 대해 적용되므로 IDE등을 통해 프로젝트별로 classpath를 설정하는 것이 바람직하다. classpath 관련 내용을 jdk 설치 세팅할 때 주로 보게 되는 이유이기도 한듯.
참고
https://docs.oracle.com/javase/tutorial/java/package/index.html
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/lang/package-summary.html
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/package-summary.html
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/doc-files/coll-index.html
https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/doc-files/coll-overview.html
Java in a Nutsell, 7th Edition
https://github.com/tinajeong/univRankAnalyzer/blob/master/doc/%EC%82%AC%EC%8B%A4%EC%9D%80%20%EB%90%98%EA%B2%8C%20%EC%9C%A0%EC%9A%A9%ED%95%9C%20%EC%9E%90%EB%B0%94%20%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8(3).md
https://effectivesquid.tistory.com/entry/%EC%9E%90%EB%B0%94-%ED%81%B4%EB%9E%98%EC%8A%A4%ED%8C%A8%EC%8A%A4classpath%EB%9E%80
https://m.blog.naver.com/PostView.nhn?blogId=k_builder&logNo=40164572729&proxyReferer=https:%2F%2Fwww.google.com%2F
계속해서 문서를 업데이트하고 있습니다. 언제든지 댓글피드백 남겨주세요. 😉