본문 바로가기
자바

[Java] 자바의 패키지란? - package, import, 클래스패스, -classpath 옵션, CLASSPATH 환경변수, 접근지시자

by 책 읽는 개발자_테드 2021. 8. 12.
반응형

package 키워드

 

package:

- 클래스를 체계적으로 관리하기 위한 도구 / 클래스들을 구분 짓는 폴더

- 패키지의 물리적인 형태는 파일 시스템의 폴더

- 단순히 파일 시스템의 폴더 기능만 하는 것이 아니라 클래스의 일부분

 

- 클래스를 유일하게 만들어주는 식별자

클래스 이름이 동일해도 패키지가 다르면 다른 클래스로 인식한다. 또한 패키지 내부에 패키지를 둘 수도 있다. '

 

- 패키지와 클래스는 도트(.)를 사용해서 표시

상위패키지.하위패키지.클래스

 

패키지를 나타내는 코드

package week7.하위패키지;

public class ClassName {

}

 

패키지 이름 규칙

1. 숫자로 시작하거나, ‘_’ 과 ‘$’를 제외한 특수 문자를 사용 금지

2. java로 시작하는 패키지 금지(자바 표준 API에서만 사용)

3. int, static 등 자바 예약어 금지

4. 모두 소문자로 작성하는 것이 관례

 

여러 개발 회사가 참여하는 대규모 프로젝트나, 다른 회사의 패키지를 이용해서 개발할 경우, 패키지 이름이 중복될 가능성이 있다. 

이떄, 회사들 간에 패키지가 서로 중복되지 않도록 흔히 회사의 도메인 이름 역순으로 패키지 이름을 짓는다.

 

com.tistory.whiteship

 

패키지는 왜 필요할까?

- 클래스를 체계적으로 관리하지 않으면 수십, 수백 개의 클래스 간의 관계가 뒤엉켜 복잡해질 수 있음

 

import 키워드

 

같은 패키지에 속하는 클래스들은 아무런 조건 없이 다른 클래스를 사용할 수 있지만, 다른 패키지에 속하는 클래스를 사용하려면 두 가지 방법 중 하나를 선택해야 한다.

 

🖋️ 1. 패키지와 클래스를 모두 기술(이러한 표현을 FQCN(Fully Qualified Class Name)이라고 함)

🖋️ 2. import 문을 사용

 

첫 번째 방법으로 week7.하위패키지2 패키지에 소속된 Ship 클래스를 이용해서 필드를 선언하고 객체를 생성해보자.

public class Main {

   public static void main(String[] args){
       week7.하위패키지2.Ship ship = new week7.하위패키지2.Ship();
   }

}

 

이 경우 패키지 이름이 길거나, 사용해야 할 클래스 수가 많다면 코드가 난잡해 보이게 된다. 그래서 두 번째 방법인 import문을 주로 사용한다. 

 

import문이 작성되는 위치:패키지 선언과 클래스 선언 사이

import week7.하위패키지2.Ship;

public class Main {

   public static void main(String[] args){
       Ship ship = new Ship();

   }
}

 

패키지의 포함된 다수의 클래스를 사용해야 한다면 클래스 이름을 생략하고 대신 *를 사용해서 import문을 한 번 작성한다.

import week7.하위패키지2.*;

import a.*; 이런게 선언한다고 a 패키지 밑에 있는 모든 패키지를 import하지는 않는다. * 사용하면 그 패키지에 선언된 클래스들만 import 한다. 즉, a.b, a.b.c에 선언된 클래스는 import하지 않는다.

 

첫 번째 방법이 꼭 필요한 상황

- 서로 다른 패키지에 동일한 클래스 이름이 존재하고, 두 패키지가 모두 import 되어 있을 경우

자바 컴파일러가 어떤 패키지에서 클래스를 로딩할지 결정할 수 없어 컴파일 에러가 발생한다. 때문에 첫 번째 방법을 사용해야한다.

public class Main {

   public static void main(String[] args){
   
       week7.하위패키지2.korea.Ship ship1 = new week7.하위패키지2.korea.Ship();
       week7.하위패키지2.usa.Ship ship2 = new week7.하위패키지2.usa.Ship();

   }
}

 

빌트 인 패키지(Built in Package)

자바는 개발자들이 사용할 수 있도록 여러 패키지를 제공한다. 이 중에서 자주 사용하는 패키지는 import를 하지 않아도 사용할 수 있다. 예를 들어 java.lang 패키지는 import 없이 사용할 수 있다. 

 

이러한 패키지를 빌트 인 패키지라고 한다. 다음은 java.lang의 String 클래스, System 클래스를 사용하는 예시다.

// import java.lang.String; 생략
// import java.lang.System; 생략
public class BuiltInPackage {
    public static void main(String[] args){
        String message = "저는 빌트 인 패키지 내부에 있습니다.";
        System.out.println(message);
    }
}

 

static import

일반적인 import와 다르게 메소드와 변수를 패키지, 클래스명 없이 접근 가능

import  org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

public class staticImportTest {
    @Test
    void nonStaticImport(){
        int one = 1;
        Assertions.assertThat(one).isEqualTo(1);
    }
    
    @Test
    void staticImport(){
        int one = 1;
        assertThat(one).isEqualTo(1);
    }
}

 

위 코드는 변수 'one'이 정수 1이 맞는지 검사하는 단위 테스트다. 그 중에서 nonStaticImport 메소드는 static import를 적용하였고,  staticImport 메소드는 static import를 적용하지 않았다.

 

장점: 'That(one) is 1' 과 같이 영어 문장 읽듯이 코드를 읽을 수 있어서, 코드의 의도를 한 눈에 볼 수 있다는 점이다. 이러한 장점은 코드가 길어지고, 많은 메소드와 필드를 사용할 때 더 빛을 발한다.

 

클래스에 import한 동일한 이름의 static 변수나 static 메소드가 자신의 클래스에 있다면?

- import static으로 가져온 것보다 자신의 클래스에 있는 static 변수나 메소드가 우선된다.

 

클래스패스

 

클래스패스란, JVM이나 Java 컴파일러에 클래스와 패키지의 위치를 지정해주는 파라미터이다. 즉, 자바에서 클래스를 찾을 때 사용하는 경로다. 클래스패스를 지정해주지 않으면 기본적으로 현재 디렉토리가 클래스 패스로 지정된다.

 

클래스패스를 사용하기 위한 방법으로는 -classpath 옵션, CLASSPATH 환경변수 두 가지가 있다. 

 

-classpath 옵션

 

다음의 소스코드로 작성된 Main.java라는 파일이 있다고 가정해보자.

 

class Print{

    void firstPrint(){

        System.out.println("Hello World!");

    }
}

public class Main {

    public static void main(String[] args){

        Print print = new Print();
        print.firstPrint();

    }
}

 

(리눅스에서 ls 명령어는 디렉토리 내용을 출력합니다.)

 

 

Main.java 파일을 javac 명령어를 통해 컴파일하자. 그러면 다음과 같이 Main.java 파일에 있던 Main 클래스와 Print 클래스가 .class 파일 형태로 생성된다.

 

 

그리고 java 명령어로 Main 클래스를 실행하면 다음과 같이 ‘Hello World!’가 출력된다.

 

 

이번에는 ‘hide’라는 이름의 디렉토리를 만들고, Print.class를 hide 디렉토리로 옮기자.

 

 

그리고 다시 java 명령어로 프로그램을 실행하면, main 메소드에서 사용되는 Print 클래스를 찾지 못해 java.lang.NoClassDefFoundError가 발생한다.

 

 

이러한 프로그램 실행을 위한 클래스경로를 JVM에게 알려주는 역할을 하는 것이 클래스패스입니다. 다음과 같은 명령어를 실행하면 다시 정상적으로 프로그램이 실행된다.

 

java -classpath ".:hide" Main

 

 

java 명령어 뒤에 -classpath를 입력하면 클래스패스를 설정할 수 있다. 그리고 클래스경로는 큰따옴표(“”)안에 입력한다. 클래스경로는 콜론(:)을 사용해서 여러개 입력할 수 있다. 예를 들어 현재 경로, hide 디렉토리, good 디렉토리를 클래스경로로 지정하려면 “.:hide:good” 을 입력한다.

 

지금까지 설명한 -classpath 옵션은 java, javac 명령어에 모두 사용할 수 있다.

 

CLASSPATH 환경변수

 

환경변수는 운영체제에 지정하는 변수다. JVM과 같은 애플리케이션들은 환경변수의 값을 참고하여 동작한다. 자바는 위에서 설명한 클래스패스로 CLASSPATH 환경변수를 사용한다. 

 

터미널에서 위 프로그램을 실행 디렉토리로 다시 이동하자. 그리고 pwd 명령어로 현재 디렉토리 경로를 확인한다. 현재 디렉토리 경로는 /Users/simseungcheol/Desktop/whiteship 이다. 

 

 

다음으로 터미널에 open ~/.bash_profile을 입력하여, bash_profile 설정파일을 연다. 

 

 

CLASSPATH 환경변수는 다음과 같은 형태로 작성한다.

 

export CLASSPATH = 경로 또는 export CLASSPATH = 경로1:경로2:경로3

 

보자마자 알 수 있겠지만, CLASSPATH 환경변수 또한 콜론”:”으로 구분하여 클래스경로를 여러개 등록할 수 있다. 이제 마지막 줄에 다음과 같이 클래스패스를 설정하고 저장하자

 

 export CLASSPATH=/Users/simseungcheol/Desktop/whiteship:/Users/simseungcheol/Desktop/whiteship/hide

 

 

클래스패스 설정이 끝났으면, 터미널에 source ~/.bash_profile 를 입력하여 설정사항을 등록한다.

 

이제 -classpath 옵션을 생략하고, 자바 프로그램을 실행해도 정상적으로 작동한다.

 

 

CLASSPATH 환경변수를 사용하면 자바 프로그램을 실행할 때마다 -classpath 옵션을 사용하지 않아도 된다는 점이 간편하지만, 운영체제를 변경하면 클래스 패스가 사라지기 때문에 이식성이 좋지 않다는 단점이 있다.

 

접근지시자

https://scshim.tistory.com/202

 

[Java] 접근 제한자 - public, protected, default, private

[java] 접근 제한자 - public, protected, default, private 클래스를 설계할 때 외부 클래스에서 접근할 수 있는 멤버와 접근할 수 없는 멤버로 구분해서 필드, 생성자, 메소드를 설계하는 것이 바람직

scshim.tistory.com

 

 

출처

이것이 자바다

자바의신

생활코딩

hardlearner.tistory.com/284

https://effectivesquid.tistory.com/entry/자바-클래스패스classpath란

www.notion.so/ed8e346f88f54849a06ff968b1877ca5

반응형

댓글