[Java 기초] 패키지

Updated:

이번 포스트에서는 자바의 패키지에 대해서 알아보도록 하겠다. 👨‍🏫

📋 목차

  • package 키워드
  • import 키워드
  • 클래스패스 $($class path)
  • CLASSPATH 환경변수
  • class path 옵션
  • 접근지시자

package 키워드

패키지는 서로 관련된 클래스들의 묶음.

사실 클래스의 실제 이름은 패키지명을 포함하고있다.

예로 String클래스의 패키지명을 포함한 이름은 java.lang.String이다.

java디렉토리의 서브디렉토리인 lang에 속한 String .class 파일이다.

package 패키지명;

패키지 선언문은

  • 소스파일에서 첫 번째 문장이어야하며 한번만 선언가능
  • 패키지명은 소문자인게 관례
  • 모든 클래스는 반드시 하나의 패키지에 속해야 한다.
  • 패키지는 .을 구분자로 하여 계층구조를 형성
  • 패키지는 .class 파일을 포함하는 하나의 디렉토리이다.

import 키워드

import문으로 사용하고자 하는 클래스의 패키지를 명시.

소스코드에 사용되는 클래스이름에서 패키지명을 제외할수 있다.

import 패키지명.*;

import 패키지명.클래스명;

*의 사용이 하위 패키지의 클래스까지 포함하지는 않는다.

예제

import java.util.Date;
import java.text.SimpleDateFormat;

class Example {
    public static void main(String[] args) {
        Date today = new Date();

        SimpleDateFormat date = new SimpleDateFormat("yyyy/MM/dd");
        System.out.println("오늘 날짜는 :" + date.format(today));
    }
}

static import문

static 멤버를 호출할 때 클래스 이름을 생략할 수 있으며 코드가 간결해진다.

import문은 패키지의 이름을 생략가능 import static클래스의 이름을 생략가능

import 뒤에 static을 추가하여 선언.

import static java.lang.System.out;
import static java.lang.Math.*;

class Example {
    public static void main(String[] args) {
        out.println(random());
    }
}

Class Path

컴파일러나 JVM이 프로그램을 실행할 때, 클래스파일 $($.class)을 찾기위한 파일 경로.

소스코드 $($.java)를 컴파일하면 바이트코드 $($.class)로 변환되고 java 런타임 $($java)로 .class파일 내의 명령을 실행하기 위해서는 해당 .class파일을 찾아야 한다.

이 .class 파일을 찾기위해서 class path에 지정된 경로를 사용한다.

;를 구분자로 사용하여 여러 디렉토리 경로 혹은 파일 $($zip, jar)을 class path에 추가할 수 있다.

classpath 사용법

앞서 classpath는 .class 파일을 찾기위한 경로라고했다.

java 프로그램을 실행하기 위해서는 JVM이 class파일을 찾아갈 수 있도록 classpath 경로를 설정해 주어야한다.

  1. .class 파일이 생성된 디렉토리가 /Users/Documents 일 때.

CLASSPATH=/Users/Documents

  1. 현재 작업 디렉토리가 /Users/Documents 일 때.

CLASSPATH=.

  1. 다른 디렉토리 $($/Users/testing)에 추가 class파일이 있는 경우

CLASSPATH=/Users/Documents;/Users/testing

  1. testing 디렉토리에 유용한 java 클래스가 많을 경우 jar파일로 묶는다.

CLASSPATH=/Users/Documents;/Users/testing/testing.jar

CLASSPATH 환경변수

환경변수 설정을 굳이 할 필요가 없다는 의견도 있을것이다. 물론 IDE가 알아서 환경변수를 설정해주기 때문에 필요없지만 서버 컴퓨터를 사용해야 할 경우 다르다.

서버 컴퓨터에서는 클라이언트의 요청을 처리해야하고 이 때문에 IDE를 설치하는 것은 리소스 낭비이다. 때문에 우리는 CLI 환경에서도 환경변수를 통해 자바 파일들을 다룰수 있어야 한다.

필자는 macOS를 사용하기 때문에 macOS에서 환경변수 설정하는 방법은 추후에 포스팅하도록 하겠다.

classpath 옵션 -cp

-cp $($classpath)는 참조하려는 클래스가 위치한 경로를 설정하는 옵션이다.

window, unix에서의 classpath 옵션의 구분자가 (;, :) 다르므로 주의해야한다.

window : java -cp .;

unix : java -cp .:

접근제어자

  • private : 같은 클래스 내에서만 접근 가능.
  • default : 같은 패키지내의 클래스에서만 접근 가능. $($생략가능)
  • protected : 패키지에 관계없이 상속관계에 있는 자손클래스에서 접근 가능.
  • public : 접근 제한이 없다.

접근범위

public > protected > (default) > private

캡슐화

접근제어자를 사용하는 가장 큰 이유는 캡슐화$($encapsulation)이다.

클래스 내에서만 사용되는 멤버변수나 부분작업 처리를 위한 멤버들 같이 외부에서 접근할 필요가 없는 멤버들을 private으로 지정.

외부로부터 접근을 제어하고 데이터를 감추는 것으로 복잡성을 줄일수 있다.

또한 범위가 넓을수록 멤버하나를 변경한다고 했을때 변경한 후에 오류가 없는지 테스트해야할 범위가 더 넓어진다. 따라서 적절한 접근제어자를 선정해서 접근 범위를 최소로 해야한다.

예제

보통 외부로부터 변경되면 안되는 멤버변수를 private으로 지정한 다음, 어떠한 조건을 갖는 public 멤버함수를 통해서 해당 조건을 만족한 경우에만 private 멤버변수를 변경할 수 있게 설정한다.

import static java.lang.System.out;

public class Example {
    public static void main(String[] args) {
        Time t = new Time(00, 55, 12);
        out.println(t);
        // t.hour = 2; private에 직접 접근하여 값변경불가
        t.setHour(t.getHour() + 1);
        out.println(t);
    }
}

class Time {
    private int hour, minute, second;

    Time(int hour, int minute, int second) {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }

    public int getHour() { return hour; }
    public void setHour(int hour) {
        if( hour < 0 || hour > 12) return;
        this.hour = hour;
    }

    public int getMinute() { return minute; }
    public void setMinute(int minute) {
        if( minute < 0 || minute > 59) return;
        this.minute = minute;
    }

    public int getSecond() { return second; }
    public void setSecond(int second) {
        if( second < 0 || second > 59) return;
        this.second = second;
    }

    public String toString() {
        return hour + ":" + minute + ":" + second;
    }
}

하나의 소스파일$($.java)에는 단 하나의 public 클래스만 존재할 수 있다.

생성자의 접근제어자

생성자를 통해 직접 인스턴스를 생성하지 못하게 하고 public메서드를 통해 인스턴스에 접근하게 하여 사용할 수 있는 인스턴스의 개수를 제한할 수 있다.

예제

final class Singleton {
    private static Singleton s = new Singleton();

    private Singleton() {
        // ...
    }

    public static Singleton getInstance() {
        if(s == null) s = new Singleton();
        return s;
    }
}

class SingletonTest {
    public static void main(String[] args) {
    // Singleton s = new Singleton(); -> private. 직접 객체생성 불가
        Singleton s = Singleton.getInstance(); // 클래스메서드여서 객체생성없이 사용가능.
    }
}

private으로 지정한 생성자의 경우 public 메서드에 의해 사용될 수 있도록 인스턴스가 미리 생성되어 있어야 하기 때문에 static을 같이 선언해 주어야 한다.

private 인스턴스를 생성해주는 public메서드 또한 인스턴스 생성 없이 호출해야 하므로 static으로 선언되어야 한다.

생성자가 private인 클래스는 자식 클래스에서 생성자에 접근하지 못하기 때문에 누군가의 조상 클래스가 될 수 없다. 따라서 통상 클래스 앞에 final을 붙여서 상속할 수 없는 클래스인것을 나타내준다.


참조
Java의 정석 $($남궁 성)
whiteship 자바 라이브 스터디

Categories:

Updated:

Leave a comment