자바의 패키지에 대해 학습하세요.
패키지란 클래스나 인터페이스 등을 모은 단위이다. 관련 클래스를 그룹화 하고 포함된 클래스의 네임스페이스를 정의하는 역할을 한다.
소스에 가장 첫 줄에 있어야하고, 패키지 선언은 소스 하나에 하나만 있어야 한다.
모든 클래스에는 정의된 클래스 이름과 패키지 이름이 있다. 이 둘을 합쳐야
완전하게 한 클래스를 표현한다고 할 수 있으며 FQCN(Fully Qualified Class Name) 이라고 한다.
String a = "Class Name";
java.lang.String b = "Full Package Class Name";
자바는 개발자들이 사용할 수 있도록 많은 패키지 및 클래스를 제공한다.
패키지 중 java.lang은 자주 사용하는 패키지이지만
한번도 import하여 사용한적이 없다.
즉, 자바에서 java.lang 패키지는 아주 기본적인 것들이기 때문에 import로 불러오지
않아도 자바가 알아서 java.lang의 클래스를 불러온다.
그외에도 아래와 같은 패키지를 제공한다.
import 키워드는 다른 패키지에 있는 클래스나 인터페이스 등을 참조할 때 사용한다.
자바 클래스에서 static 메소드는 클래스에 대한 인스턴스 생성없이 메소드를 사용할 수 있다. static 메소드를 static import를 사용해서 클래스명 없이 바로 사용할 수 있다.
JVM이 프로그램을 실행할 때, 클래스 파일을 찾는데 기준이 되는 파일 경로를
말한다.
즉, 클래스를 찾기 위한 경로
java 명령을 통해 클래스 파일을 실행할 때 클래스 파일을 찾는 기준이 되는 경로를
클래스패스라고 하며 기본적으로는 java 명령을 실행하는 위치를 의미한다.
JVM은 프로그램을 실행할 때 Class Loader가 .class 파일들을 메모리에 적재시켜 주는
역할을 한다. 클래스패스를 통해 클래스 로더에게 어떤 클래스파일들을
메모리에 적재시킬지 알려주는 것이다.
자바의 클래스 로더는 계층 구조이며, 3가지의 서로 다른 클래스로더로 구성되어 있다.
기본 클래스로더 중 최상위 클래스 로더로써,
rt.jar에 있는 JVM을 실행시키기 위한 핵심 클래스들을 로딩한다.
String 클래스나, Object 클래스를 사용할 수 있었던 이유가 바로,
BootStrap Class loader 가 자동으로 메모리에 적재해 주기 때문이다.
java 9 부터는 rt.jar, tools.jar 등 기본적으로 제공되던 jar 파일이 없어지고 그 안에 있던 내용들은 모듈 시스템에 맞게 lib 폴더 안에 저장된다.
Bootstrap Class loader의 자식클래스로써, jre/lib/ext 폴더나 java.ext.dirs 환경 변수로 지정된 폴더에 있는 클래스 파일을 로딩한다.
자바 9 부터는 Platform Class loader로 이름 변경
$CLASSPATH에 설정된 경로를 탐색하여 그곳에 있는 클래스들을 로딩하는 역할을 한다. 개발자가 작성한 .class 파일을 로딩한다.
자바 클래스 로더는 3가지 원칙에 의해 동작한다.
1) 위임 원칙(Delegation) : 클래스로딩 작업을 상위 클래스 로더에 위임한다.
3가지 기본 클래스로더의 윗 방향으로 클래스 로딩을 위임하는 것을 말한다.
어떠한 클래스를 로딩할때 System Class loader에서 부터 시작해서 자신이 직접 로딩하지 않고 Bootstrap Class loader까지 위임한 후 차례로 내려 오면서 찾으면 반환하고 없으면 자식 클래스 로더로 이동하여 찾는다.
모두 찾지 못하면 ClassNotFoundException이 발생한다.
2) 가시 범위 원칙(Visibility) : 하위 클래스로더는 상위 클래스로더가 로딩한 클래스를 볼 수 있지만, 상위 클래스 로더는 하위 클래스로더가 로딩한 클래스를 볼 수 없다.
만약 개발자가 만든 클래스를 로딩하는 System Class loader가 Bootstrap Class loader에 의해 로딩된 String.class를 볼 수 없다면 애플리케이션은 String.class를 사용할 수 없을 것이다. 따라서 하위에서는 상위를 볼 수 있어야 애플리케이션이 제대로 동작할 수 있다.
3) 유일성 원칙(Uniqueness) : 하위 클래스로더는 상위 클래스로더가 로딩한 클래스를 다시 로딩하지 않게 해서 로딩된 클래스의 유일성을 보장한다.
Classpath를 지정하기 위한 두 가지 방법이 있다.
컴퓨터 시스템 변수 설정을 통해 지정할 수 있다.
JVM이 시작될 때 JVM의 클래스 로더는 이 환경 변수를 호출한다. 그래서 환경 변수에
설정되어 있는 디렉토리가 호출되면 그 디렉토리에 있는 클래스들을 먼저
JVM에 로드한다.
$ ~ java Test
Error: Could not find or load main class Test
Caused by: java.lang.ClassNotFoundException: Test
// 다른 경로에서 Test.class 를 실행 시키는 경우 위처럼 클래스를 찾지 못한다.
아래와 같이 클래스 패스를 정의해 준다.
export CLASSPATH=.:/Users/jang-won-yong/dev/workspace/Dispatch/src
$ echo $CLASSPATH
.:/Users/jang-won-yong/dev/workspace/Dispatch/src
// 콤파(.)는 현재 위치한 디렉토리부터 찾는다.
// 구분자인 콜론(:) 을 사용해 현재 위치(.)에 찾는 파일이 없다면 다음 경로에 있는 .class 파일을 찾는다.
// 윈도우에선 구분자로 세미콜론, 맥에선 콜론을 사용한다.
$~ java Test
dynamic method dispatch call!
하지만, 환경변수를 사용하게 되면 운영체제를 변경하면 클래스 패스가 사라지기 때문에 이식성면에서 불리할 수 있다.
최근에는 운영체제 상의 환경변수로 클래스패스를 설정하는 것은 지양하고 IDE나 빌드도구를 통해서 클래스패스를 설정한다.
java 명령 또는 javac 명령 실행 시 옵션으로 클래스패스를 지정할 수 있다. 또한, CLASSPATH 환경 변수 설정 후 실행 하였는데 -classpath 옵션이 우선순위가 높은 것을 볼 수 있다.
단축 옵션인 -cp 옵션도 동일한 기능을 한다.
classpath 옵션은 java, javac 모두 사용 가능하다!
$~ java -cp /Users/jang-won-yong/dev/workspace/Dispatch/src Test
dynamic method dispatch call!
Reference
https://homoefficio.github.io/2018/10/13/Java-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%A1%9C%EB%8D%94-%ED%9B%91%EC%96%B4%EB%B3%B4%EA%B8%B0/
https://github.com/whiteship/live-study/issues/7