jacketList

[Java] 패키지(package) 본문

카테고리 없음

[Java] 패키지(package)

ukkkk7 2024. 4. 20. 16:32
728x90
반응형

학습할 것 (필수)

  • package 키워드
  • import 키워드
  • 클래스패스
  • CLASSPATH 환경변수
  • -classpath 옵션
  • 접근지시자

 

🔍 패키지

  • 클래스를 묶어 구분짓는 폴더 구조
  • 서로 관련있는 것을 묶어놓음으로써 효율적으로 클래스를 관리할 수 있고 클래스 풀네임(FQCN)의 고유성을 보장하기 위해 사용
    • FQCN(Fully Qualified Class Name) : 클래스가 속한 패키지명까지 모두 포함한 이름을 의미(패키지명.클래스명)
      • ex) String 클래스의 패키지는 "java.lang" 이며 FQCN은 "java.lang.String"이 된다.
  • 점(.) 을 구분자로 하여 계층구조로 구성되어 있음
  • 모든 클래스는 반드시 하나의 패키지에 속해야 함
    • 패키지를 선언하지 않으면 자바에서 기본적으로 제공하는 이름없는 패키지(unnamed package)로 속하게 됨
  • 규칙
    • 소문자를 원칙으로 함
    • 소스코드에서 주석과 공백을 제외한 첫 번째 줄에 딱 한 번 선언되어야 함
    • 자바의 예약어를 사용하면 안된다(ex - int, static)
  • 선언
package 패키지명;
package com.study.halle.week7;

 

 

🔍 import 키워드

import 패키지명.클래스명

다른 패키지의 클래스를 사용하기 위해 import 하는 경우 import 패키지명으로 선언한다.

package com.mycompany;

import com.hankook.Tire; // 혹은, import com.hankook.*;

public class Car{
	Tire tire = new Tire();
}

 

❗주의 : import로 선언한 패키지의 하위패키지가 존재하고 이를 사용하고 싶다면 하위패키지 또한 import로 선언해줘야 한다.

 

 

한 클래스에서 서로 다른 패키지에 같은 이름의 클래스를 사용하는 경우

 

이와같이 다른 패키지에 같은 이름의 클래스가 정의되어 있을때 같은 클래스에서 사용하기 위해서는 정확한 패키지 이름 전체를 기술해야 한다.

-> 자바 컴파일러는 어떤 패키지에서 클래스를 로딩할 지 결정할 수 없어서 컴파일 에러가 발생하기 때문

 

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();
}

 

위와같이 패키지의 전체 이름을 기술해서 컴파일 에러를 해결할 수 있다.

 

static import 

static import는 자바 버전5 이상에서 소개된 기능이다.

 

임의의 패키지 클래스에서 public static으로 정의된 멤버(필드나 메소드)를 사용할 때, 클래스명을 언급하지 않고도 사용할 수 있다.

 

사용이유

  • static 메소드를 사용하는 경우 짧고 간단한 코드를 작성할 수 있다.
  • 테스트 코드 작성 시 유용하다.
// import static으로 static 메서드 쓸 수 있게 한다.
import static org.junit.jupiter.api.Assertions.assertAll;  
import static org.junit.jupiter.api.Assertions.assertEquals;  
import static org.junit.jupiter.api.Assertions.assertThrows;

 

// assertAll(), assertEquals(), assertThrows()등의 
// static 메서드를 '메서드 이름으로만' 사용할 수 있다. 

@Test  
@DisplayName("노드 추가 테스트")  
void addTest() {  
    assertAll("노드 추가 오류",  
  () -> {// init()에서 생성한 linkedlist를 확인  
  assertEquals("1,3,5,7", list.toString(head));  
  },  
  () -> {// 허용범위를 벗어난 position에 add하려는 경우  
  Exception exception = assertThrows(IndexOutOfBoundsException.class, () ->  
                        list.add(head, new ListNode(9), list.getSize(head) + 1));  
  }  
    );  
}

 

 

 

 클래스패스(ClassPath)

클래스를 찾기 위한 경로 

JVM이 프로그램을 실행할 때, 클래스파일을 찾는데 클래스 패스를 사용한다.

자바가 클래스를 찾아 사용해야 하는데, 클래스들이 어디 있는지 위치를 지정해주는 값이다.

 

import org.company.Menu;
Menu menu = new Menu();

 

org.company 패키지에 있는 Meny라는 클래스를 현재 클래스에서 사용하며 JVM은 Menu 클래스의 위치를 찾아서 해당 클래스의 인스턴스를 생성한다.

JVM이 Menu 클래스를 찾기위해 모든 클래스를 검사하는 것은 매우 비효율적이다. 이때 CLASSPATH변수를 사용하여 해당 클래스가 위치한 곳을 JVM에게 알려준다.

 

만일 Menu클래스가 dir이라는 디렉토리에 존재한다면, Menu 클래스의 전체 경로는 dir/org/company/Menu가 된다.

 

이때 dir이라는 디렉토리를 classpath 변수로 등록해 놓고, 나머지 정보 (org/company/Meny)는 import명령어를 통해 제공해줌으로써 외부 패키지의 클래스를 가져와 사용할 수 있게 된다.

 

CLASSPATH 세팅

CLASSPATH는 어플리케이션에서 필요한 파일의 위치를 자바 컴파일러와 JVM에 알려주는 역할을 한다.만약 CLASSPATH가 세팅되어 있지 않다면 자바 컴파일러는 필요한 파일을 찾을 수 없고 컴파일 타임에 ERROR를 던지게 된다.

 

 

컴퓨터 시스템 변수 설정을 통해 환경변수를 지정할 수 있고 JVM의 클래스 로더는 시작될 때 이 환경 변수를 호출한다. 해당 환경변수가 호출되면 그 디렉토리에 있는 클래스들을 먼저 JVM에 로드한다. 

 

위와같이 환경변수를 사용하게 되면 모든 프로젝트에 환경변수가 다 적용되기 때문에 이렇게 사용하게 되면 나중에 개발할 때 해당 CLASSPATH 때문에 라이브러리가 꼬일 수 있다. 되도록이면 환경변수는 위와같이 적용하기 보다는 개발시에 적용시켜 주는것이 좋다.

 

 

🔍  접근지시자

접근지시자란 접근의 허용 범위를 제한하기 위해 생겨난 개념이다.

 

클래스들은 외부 클래스에서 접근할 수 있는 멤버와 접근할 수 없는 멤버를 구분하여 설계하는 것이 바람직하다.

이러한 기능을 구현하기 위해 자바는 접근 제한자(Access Modifier)를 제공하고 이는 접근 수준 지시자(Access-level-Modifier)라고도 한다.

 

 

멤버에 접근하는 클래스                  private                     default                                    protected                                 public
같은 패키지의 클래스 X O O O
다른 패키지의 클래스 X X X O
접근 가능 영역 클래스 내 동일 패키지 내 동일 패키지와 자식 클래스 모든 클래스

 


QnA에서 나온것들

 

 

Anti Pattern

public interface Constants {
    int num = 100;
    String name = "hello";
}

 

인터페이스에 선언하는 field는 기본적으로 static 키워드가 붙는다.

public class Child implements Constants{

    public static void main(String[] args) {
        System.out.println(Constants.name);
    }

}

 

이렇게 상수를 출력해주는 방법이 있지만

public class Child implements Constants{

    public static final String name = "java";

    public static void main(String[] args) {
        System.out.println(Child.name);
    }


}

 

이와같이 출력해주면 상수가 아닌 Child클래스에서 선언한 static 변수가 사용된다.

Child클래스에서 선언된 static 변수를 지워주면 Constants의 name을 사용한다.

 

interface는 규약을 정의하는것이기 때문에 위와같이 사용하면 규약을 위반하는 경우가 된다.

 

 

만일 상수만 모아놓은 클래스만 사용하고 싶다면 아래와같이 객체 생성을 제한한 후에 사용하면 된다.

public class Constants {
    public static final int num = 100;
    public static final String name = "hello";
    
    private Constants(){
        
    }
}

 

 

 

Enum

public class Child{
    private enum MyEnum{
        HELLO("hello"), BOOK("book");
        private String text;

        private MyEnum(String text){
            this.text = text;
        }

        public String getText(){
            return text;
        }
    }


    public static void main(String[] args) {
        Child child = new Child();
        child.print(MyEnum.HELLO);
    }

    private void print(MyEnum myEnum) {
        System.out.println(myEnum.getText());
    }


}

 

위와같이 print의 타입이 Enum타입이면 타입을 Enum으로 제한하고 Enum에서 지정한 값만 올 수 있기 때문에 typeSafe하다고 말한다.



public static void main(String[] args) {
        Child child = new Child();
        child.print("fwelawbjwebfhlwfjawe");
    }


private void print(String text) {
        System.out.println(text);
    }
}

 

만일 print의 파라미터 타입을 String으로 하면 print에 아무값이나 들어갈 수 있기 때문에 typeSafe하지 않다고 한다. 이와같은 이유로 enum을 사용하기도 한다.

 

 

 

references

https://five-cosmos-fb9.notion.site/ed8e346f88f54849a06ff968b1877ca5

https://ahnyezi.github.io/java/javastudy-7-package/

https://kils-log-of-develop.tistory.com/430

 

 

728x90
반응형