패키지

*.java 구성

1. package문

2. import문

3. 클래스 선언

package

패키지는 클래스(인터페이스 포함)의 묶음이다. 서로 관련된 클래스들끼리 그룹 단위로 묶어 놓아 클래스를 효율적으로 관리할 수 있다. (패키지는 물리적인 디렉토리임)

서로 다른 패키지에 있다면 같은 이름의 클래스를 사용하는 것이 가능하다.

클래스의 실제 이름 즉, full name 은 패키지명 + 클래스이름 이다.
예를들어, String 클래스의 full name은 java.lang.String 이다.

💡 하나의 소스파일에는 첫 번째 문장으로 단 한 번의 패키지 선언만을 허용한다.
💡 모든 클래스는 반드시 하나의 패키지에 속해야 한다. (java 기본제공 - unnamed package)
💡 패키지는 점(.)을 구분자로 계층구조로 구성할 수 있다.
💡 패키지는 물리적으로 클래스 파일을 포함하는 하나의 디렉토리이다.

패키지 선언

package 패키지명;

패키지 선언문은 반드시 주석과 공백을 제외한 첫 번째 문장이어야 한다. 하나의 소스파일에 단 한번만 선언될 수 있으며 해당 소스파일에 포함된 모든 클래스나 인터페이스는 선언된 패키지에 속하게 된다.

패키지명은 대소문자를 모두 허용 하지만 클래스명과 쉽게 구분하기 위해서 소문자로 하는 것을 원칙 으로 하고있다.

  • 패키지명 예시
    • com.회사이름.프로그램이름 (com.naver.goodapp)
    • com.회사이름.플랫폼.프로그램이름 (com.naver.android.goodapp)

import

다른 패키지에 있는 클래스를 사용하려면 패키지명이 포함된 클래스 이름을 사용해야 한다. 그러나 매번 full name을 붙여서 작성하기는 여간 귀찮은 일이 아니다. 이 때, import 키워드를 활용하여 사용하고자 하는 클래스의 패키지를 미리 명시해주면 패키지명은 생략하고 클래스 이름으로 다른 패키지에 있는 클래스를 사용할 수 있다.

즉, import문의 역할은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공하는 것이다. 컴파일시 컴파일러는 import문을 통해 사용된 클래스패키지를 알아낸 다음 모든 클래스 이름 앞에 패키지명을 붙여준다.

import 선언

package 패키지명;

import 패키지명.클래스명;
import 패키지명.*;

같은 패키지에서 여러 클래스가 사용될 때 import 패키지명.* 형식으로 작성하면 여러 클래스를 일일이 적어줄 필요 없이 지정된 패키지에 속하는 모든 클래스를 패키지명 없이 사용할 수 있다.

import문은 package문 다음에, 클래스 선언문 이전에 위치해야 하고 여러 번 선언할 수 있다.

.* 의형식을 사용하는 경우 *은 클래스의 이름 대신 사용하는 것이므로 다음과 같은 코드는 작성 할 수 없다.

import java.util.*;
import java.text.*;

import java.*;      // 불가능

만약 intellij 같은 툴을 사용한다면 Alt + Enter 단축키로 import를 할 수 있다.

java.lang 패키지는 별도의 import 없이 사용이 가능하다.

static import

패키지, 클래스명 없이 접근 가능하게 해주는 import 문으로 JDK 1.5부터 지원한다.

예를들어,

import java.lang.Math.abs;

int value = Math.abs(-3);

기본 import문을 사용하면 패키지명 없이 클래스명.메소드명 으로 사용할 수 있지만

import static java.lang.Math.abs;

int value = abs(-3);

static import문을 사용하면 패키지명, 클래스명 없이 메소드명만으로도 사용이 가능하다.

클래스패스

말 그대로 클래스를 찾기 위한 경로로, JVM이 프로그램을 실행할 때 클래스파일을 찾는데 기준이 되는 파일 경로이다.

classpath 지정하는 방법

  1. java -classpath 옵션 사용 (-classpath = -cp)

    다음코드를 temp 디렉토리에 저장한다.

     public class ClasspathTest {
         public static void main(String[] args) {
             Test test = new Test();
             test.print();
         }
     }
        
     class Test {
         public void print() {
             System.out.println("Hello, world");
         }
     }
    

    그런다음 javac[ClasspathTest.java](http://classpathtest.java) 명령어로 컴파일을 하면 다음과같이 클래스파일이 생긴다.

    그리고 Test.class 파일을 lib 폴더 에 옮긴다.

    그리고 java 명령어로 ClasspathTest.java를 실행하면 다음과 같은 에러가 나오게 된다.

     Exception in thread "main" java.lang.NoClassDefFoundError: Test
     	at ClasspathTest.main(ClasspathTest.java:3)
     Caused by: java.lang.ClassNotFoundException: Test
     	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
     	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
     	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
     	... 1 more
    

    에러를 찬찬히 보게되면 Test.class 파일이 현재 디렉터리에 존재하지 않기 때문에 찾을 수 없다는 메시지이다. → 클래스패스를 지정해주어야 한다.

     java -classpath ".;lib" ClasspathTest             // Widow
     java -classpath ".:lib" ClasspathTest             // linux
    

    이렇게 -classpath 옵션을 이용하여 현재디렉토리와 lib 폴더를 지정해주면 실행할 때 사용할 클래스들의 위치를 jvm이 알 수 있어 오류가 나지 않는다.

    • . : 현재 디렉터리에서 클래스를 찾는다.
    • ; or : : 경로와 경로를 구분해주는 구분자
  2. CLASSPATH 환경변수 사용

    1번방법으로 매번 classpath를 지정하기는 매우 귀찮은 일이다. 컴퓨터 시스템 변수 설정을 통해 그 번거로움을 없앨 수 있다.

    JVM의 클래스 로더는 여기에서 설정한 환경변수를 호출하고 환경변수에 저장되어 있는 디렉토리에 있는 클래스들을 먼저 JVM에 로드하게 된다. 그러므로 CLASSPATH 환경변수에는 필수 클래스들이 위치한 디렉토리를 등록하는 것이 좋다.

    • 환경변수
      • 사용자변수 : OS 내 사용자별로 다르게 설정 가능한 환경변수
      • 시스템변수 : 시스템 전체에 모두 적용되는 환경변수
    • 윈도우

      https://blog.opid.kr/62

      변수 값 항목에 CLASSPATH 위치를 지정해주면 된다.

    • 리눅스 (Ubuntu)

      /etc/environment 파일을 수정하면 된다.

        JAVA_HOME=...
        CLASSPATH=.:...
      

      윈도우는 구분자로 ; 를 사용하지만 리눅스에서는 : 로 구분한다는 것에 주의하면서 수정한다.

      수정후 source /etc/environment 하게 되면 적용이 완료된다.

접근지시자 (Access Modifier)

변수, 메소드, 클래스 선언시 사용하며 해당 변수, 메소드, 클래스의 접근을 제한하는 역할의 키워드이다.

선언된 데이터를 외부로부터 보호해주기 위한 것으로 캡슐화(Encapsulation)와 정보은닉의 특성을 구현할 수 있게 해준다.

또한, 생략이 가능하며 생략시 default 를 의미한다.

  • public : 같은 프로젝트면 어디에서든 접근 가능
  • default (package private) : 같은 패키지 안에서는 어디에서든 접근 가능
  • private : 같은 클래스 안에서는 어디에서든 접근 가능
  • protected : 상속 관계이면 어디에서나 접근 가능

접근제어자를 사용하면 클래스 외부에서의 직접적인 접근을 허용하지 않는 멤버를 설정하여 정보은닉을 구체화 할 수 있다.

private

외부에 공개되지 않으며 외부에서 직접 접근할 수 없다. public 메소드를 통해서만 접근할 수 있다. 주로 클래스 내부의 세부적인 동작을 구현하는데 사용된다.

http://www.tcpschool.com/java/java_modifier_accessModifier

public

외부로 공개되며 해당 객체를 사용하는 프로그램 어디에서나 직접 접근할 수 있다.

http://www.tcpschool.com/java/java_modifier_accessModifier

default (package private)

접근제어의 기본값으로 접근제어자가 지정되지 않으면 자동적으로 default 접근제어를 가지게 된다. 같은 클래스 멤버와 같은 패키지에 속하는 멤버에서만 접근 가능하다.

http://www.tcpschool.com/java/java_modifier_accessModifier

protected

protected로 설정된 멤버는 부모 클래스에 대해서는 public 멤버처럼 취급되며, 외부에서는 private 멤버처럼 취급된다.

  • 이 멤버를 선언한 클래스의 멤버
  • 이 멤버를 선언한 클래스가 속한 패키지의 멤버
  • 이 멤버를 선언한 클래스를 상속받은 자식 클래스의 멤버

위에 기재한 멤버들은 protected 멤버에 접근할 수 있다.

http://www.tcpschool.com/java/java_modifier_accessModifier