패키지란 많은 클래스들을 체계적으로 관리하기 위해 존재한다.
폴더를 만들어서 파일을 저장하듯, 패키지를 만들어서 클래스를 저장/관리 한다.
패키지이름.하위패키지이름.클래스이름 형식으로 구성된다. 이것은 같은 이름을 가진 클래스를 서로 다른 패키지에 정의할 수 있도록 한다. 즉, 정확한 클래스를 식별하기 위해 패키지 경로를 포함한 FQCN을 사용하는 것이다.package com.example.myapp;
public class MyClass {
// 클래스 내용
}
위 클래스의 실제 디렉토리 구조는 src/com/example/myapp/MyClass.java 형태이다.
패키지는 클래스를 컴파일 하는 과정에서 자동적으로 생성되는 폴더이다.
컴파일러는 클래스에 포함되어 있는 패키지 선언을 보고, 파일 시스템의 폴더로 자동 생성 시킨다.
패키지 이름에도 명명 규칙이 있다.
자바는 개발자들이 사용할 수 있도록 여러 많은 패키지 및 클래스를 제공한다.
가장 자주 쓰이는 패키지로는 java.lang 과 java.util이 있다.
자바에서 java.lang 패키지는 아주 기본적인 것들이기 때문에 import로 불러오지 않아도 자바가 알아서 java.lang의 클래스를 불러온다.
같은 패키지에 속하는 클래스들은 서로 아무 조건 없이 서로 사용할 수 있지만,
다른 패키지에 속하는 클래스를 사용하려면 2가지 방법 중 하나를 선택해야 한다.
ex) "com.hankook" 패키지에 소속된 Tire 클래스를 이용해서 필드 선언 후 객체 생성
package com.mycompany;
public class Car{
com.hankook.Tire tire = new com.hankook.Tire(); // 객체생성
}
위 예시는 패키지 이름이 짧아 불편함이 없어보이지만 길이가 길거나 이렇게 사용해야할 클래스가 많다면 전체적으로 코드의 가독성이 떨어진다.
package com.mycompany;
import com.hankook.*;
import com.kumho.*;
public class Car{
SnowTire snowTire = new SnowTire();
BigWidthTire bigWidthTire = new BigWidthTire();
com.hankook.Tire hankookTire = new com.hankook.Tire();
com.kumho.Tire kumnhoTire = new com.kumho.Tire();
}
서로 다른 패키지에 동일한 이름의 클래스가 존재하고 두 패키지가 모두 import되어 있는 경우, 자바 컴파일러는 어떤 패키지에서 클래스를 로딩할지 결정할 수 없어 컴파일 에러가 발생하기 때문에 정확한 패키지 이름 전체를 기술해야한다.
사용하고자 하는 패키지를 import문으로 선언하고 클래스를 사용할 때는 패키지를 생략한다. import문의 개수에는 제한이 없다.
package com.mycompany;
import com.hankook.Tire; // 혹은, import com.hankook.*;
// *는 모든 클래스를 의미
public class Car{
Tire tire = new Tire();
}
⚠️ import문으로 지정된 패키지의 하위 패키지는 import 대상이 아니므로 만약 com.mycompany 패키지의 클래스와 com.mycompany.project 패키지의 클래스를 둘다 사용하려면 각각 import문을 사용해야 한다.
import com.mycompany.*;
import com.mycompany.project.*;
Java에서 정적 멤버(필드나 메서드)를 사용할 때 클래스 이름을 생략하고 직접 사용할 수 있도록 도와준다. 일반적인 import는 클래스 전체를 참조하지만 static import는 클래스의 정적 멤버를 참조한다.
import static java.lang.System.*;
..
out.println("TEXT");
위 코드에서 import문의 static이 빠진다면 Compile Error가 발생한다.
또한, 테스트 코드에서 static import를 활용하면 JUnit의 정적 메서드를 호출할 때 클래스 이름을 생략할 수 있다.
👉 사용 전
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Assertions;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
// Assertions 클래스의 메서드를 사용할 때 클래스 이름 필요
Assertions.assertEquals(5, result);
}
}
👉 사용 후
import static org.junit.jupiter.api.Assertions.assertEquals; // static import
import org.junit.jupiter.api.Test;
public class CalculatorTest {
@Test
public void testAdd() {
Calculator calculator = new Calculator();
int result = calculator.add(2, 3);
// 클래스 이름 없이 바로 호출
assertEquals(5, result);
}
}
JVM이나 Java 컴파일러에 사용자정의 클래스와 패키지의 위치를 지정해주는 파라미터이다. 쉽게 말해, JVM이 프로그램을 실행할 때 클래스파일을 찾는 데, 이 클래스들이 어디 있는지 위치를 지정해주는 값이다.
소스 코드(.java)를 컴파일하면 소스 코드가 바이트 코드(.class)로 변환된다. java runtime(java 또는 jre)으로 이 .class 파일에 포함된 명령을 실행하려면, 이 파일을 찾을 수 있어야 한다. .class 파일을 찾을 때, classpath에 지정된 경로를 사용한다.
JVM의 클래스로더는 런타임 시에 $CLASSPATH 환경변수를 호출해 해당 디렉토리에 정의된 클래스들을 로딩하게 된다.

BootStrap Class Loader
jre/lib/rt.jar 에 담긴 JDK 클래스 파일을 로딩해줌Extension Class Loader
jre/lib/ext폴더나 java.ext.dirs 환경 변수로 지정된 폴더에 있는 클래스 파일을 로딩한다.
System Class Loader
바로 System Class Loader 가 우리가 만든 Class를 메모리에 올리는 역할을 하는데, 그 때 classpath 기준으로 클래스들을 로드해준다.
이 classpath 를 지정하기 위한 두 가지 방법이 있다.
CLASSPATH 환경변수 사용
java runtime 에 -classpath 옵션 사용
CLASSPATH=.;C:\Program Files\Java\jdk-10.0.1\lib\tools.jar
환경변수는 운영체제에 지정하는 변수로 자바 가상머신과 같은 애플리케이션들은 환경변수 값을 참고해서 동작하게 된다. 자바는 클래스 패스로 환경변수 CLASSPATH를 사용하는데 이 값을 지정하면 실행할때마다 -cp(classpath) 옵션을 사용하지 않아도 된다.
JVM이 시작될 때 JVM의 클래스 로더는 이 환경 변수를 호출한다. 그래서 환경 변수에 설정되어 있는 디렉토리가 호출되면 그 디렉토리에 있는 클래스들을 먼저 JVM에 로드한다. 그러므로 CLASSPATH 환경 변수에는 필수 클래스들이 위치한 디렉토리를 등록하도록 한다.

javac <options> <souce files>
컴파일러가 컴파일 하기 위해서 필요로 하는 클래스 파일들을 찾기 위해서 컴파일시 파일 경로를 지정해주는 옵션이다. 즉, 다른 클래스에 의존하는 클래스의 소스 파일을 컴파일 하기 위해서 다른 클래스가 위치하는 경로를 잡아주는 것이다.
-cp(classpath) 옵션은 컴파일할 때, 실행할 때 모두 사용할 수 있다.
👉 javac -classpath C:\Java\Engclasses C:\Java\Hello.java
이 명령어는 C:\Java\Engclasses 디렉터리에 있는 클래스를 참조하여 C:\Java\Hello.java를 컴파일합니다.
👉 javac -classpath .;C:\Java\Engclasses;C:\Java\Korclasses C:\Java\Hello.java
이 명령어는 C:\Java\Engclasses와 C:\Java\Korclasses 디렉터리를 클래스 경로로 지정한다.
.은 현재 디렉터리를 포함하고, ;로 각 디렉터리를 구분한다. (Windows 기준)
-classpath 대신 단축어 -cp를 사용할 수 있다.
명령어에서 -classpath를 지정하면 CLASSPATH 환경 변수는 무시된다.
접근 제한자(Access Modifier) / 접근 수준 지시자(Access-level Modifier)
main() 메소드가 없는 클래스는 대부분 외부 클래스에서 이용할 목적으로 설계된 클래스이다. 클래스들은 외부 클래스에서 접근할 수 있는 멤버와 접근할 수 없는 멤버를 구분하여 설계하는 것이 바람직하다.
객체 생성을 막기 위해 생성자를 호출하지 못하게 하거나, 객체의 특정 데이터를 보호하기 위해 해당 필드에 접근하지 못하게 하거나, 특정 메소드를 호출할 수 없도록 제한한다.
이러한 기능을 구현하기 위해 자바는 접근 제한자(Access Modifier) 를 제공하고 이는 접근 수준 지시자 (Access-level Modifier)라고도 한다.
4가지 접근 제한자가 있으며, 제한이 작은 순서는 public < protected < default < private 이다. 자세한 내용은 아래 링크에 정리해두었다.