자바의 정석 Chapter 07 객체 지향 프로그래밍 Ⅱ - 03. 패키지와 임포트편

강철의사나이·2021년 12월 19일
0

3.package와 import

3.1 패키지 (package)

패키지란 클래스의 묶음이다.
패키지에는 클래스 또는 인터페이스를 포함시킬 수 있고
서로 관련된 클래스끼리 그룹 단위로 묶어 놓음으로써 클래스를 효율적으로 관리할 수 있다.

같은 이름의 클래스 일지라도 서로 다른 패키지에 존재하는 것이 가능하므로,
자신만의 패키지 체계를 유지함으로써 다른 개발자가
개발한 클래스 라이브러리의 클래스와 이름이 충돌하는 것을 방지할 수 있다.

지금까지는 단순히 클래스 이름으로만 클래스를 구분했지만
사실 클래스의 실제 이름(full name)은 패키지명을 포함한 것이다.

예를 들면 STring 클래스의 실제 이름은 java.lang.String이다.
java.lang 패키지에 속한 String 클래스라는 의미다.

그래서 같은 이름의 클래스일 지라도 서로 다른 패키지에 속하면 패키지명으로 구별이 가능하다.

클래스가 물리적으로 하나의 클래스파일(.class)인 것과 같이
패키지는 물리적으로 하나의 디렉토리다.

그래서 어떤 패키지에 속한 클래스는 해당 디렉토리에 존재하는 클래스 파일(.class)이어야 한다.

예를 들어서 java.lang.String클래스는
물리적으로 java의 서브디렉토리인 lang에 속한 String.class 파일이다.

그리고 우리가 자주 사용하는 System클래스 역시 java.lang패키지에 속하므로 lang 디렉토리에 포함되어 있다.

디렉토리가 하위 디렉토리를 가질 수 있는 것처럼,
패키지도 하위 패키지를 가질 수 있으며 점'.'으로 구분한다.

예르 들어서 java.lang 패키지에 lang패키지는 java패키지의 하위 패키지다.

  1. 하나의 소스파일에는 첫 번째 문장으로 단 한 번의 패키지 선언만 허용한다.
  2. 모든 클래스는 반드시 하나의 패키지에 속해야 한다.
  3. 패키지는 점(.)으로 구분하여 계층구조로 구성할 수 있다.
  4. 패키지는 물리적으로 클래스 파일(.class)을 포함하는 하나의 디렉토리다.

3.2 패키지의 선언

패키지를 선언하는 방법
클래스나 인터페이스의 소스파일(.java)의 맨 위에 다음과 같이 한 줄만 적으면 된다.

package 패키지명;

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

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

모든 클래스는 반드시 하나의 패키지에 포함되야 한다고 했는데
지금까지 소스파일을 작성할 때 패키지를 선언하지 않고도 문제가 없었던 이유는
자바에서 기본적으로 제공하는 '이름없는 패키지(unnamed package)' 때문이다.

소스파일에 자신이 속할 패키지를 지정하지 않은 클래스는 자동적으로
'이름 없는 패키지'에 속하게 된다.
결국 패키지를 지정하지 않는 모든 클래스들은 같은 패키지에 속하게 된다.

간단한 프로그램을은 패키지를 지정하지 않아도 되지만,
큰 프로젝트나 Java API:와 같은 클래스 라이브러리를 작성하는 경우에는 미리 패키지를 구성해서 적용해야한다.

package com.codechobo.book;
class PackageTest {
	public static void main(String[] args) {
    	System.out.println("Hello World!");
    }
}

3.3 import문

소스코드를 작성할 때 다른 패키지의 클래스를 사용하려면 패키지명이 포함된 클래스 이름을 사용해야 한다.
하지만, 매번 패키지명을 붙여서 작성하는 것은 불편하다.

클래스의 코드를 작성하기 전에 import문으로 사용하고자 하는
클래스의 패키지를 미리 명시해주면 소스코드에 사용되는 클래스이름에서 패키지명은 생략할 수 있다.

import문의 역할은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공하는 것이다.

컴파일 시에 컴파일러는 import문을 통해 소스파일에 사용된 클래스들의 패키지를 알아 낸 다음
모든 클래스 이름 앞에 패키지 명을 붙여준다.

이클립스는 단축키 'ctrl+shift+o'를 누르면 자동적으로 import문을 추가해준다.

! import문은 프로그램의 성능에 전혀 영향을 주지 않는다.
다만 많이 사용하면 컴파일 시간이 아주 조금 더 걸린다.

3.4 import문의 선언

모든 소스파일 (.java)에서 import문은 package문 다음에
그리고 클래스 선언문 이전에 위치해야 한다.

import문은 package문과 다르게 한 소스파일에 여러 번 선언할 수 있다.

일반적인 소스파일(*.java)의 구성은 다음의 순서로 되어 있다.
1. package문
2. import문
3. 클래스 선언

import문을 선언하는 방법

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

키워드 import와 패키지명을 생략하고자 하는 클래스의 이름을 패지키명과 함께 써주면 된다.

같은 패키지에서 여러 개의 클래스가 사용될 때, import문을 여러번 사용하는 대신
'패키지명.*'을 사용해서 지정된 패키지에 속하는 모든 클래스를 패키지명 없이 사용할 수 있다.

클래스 이름을 지정하는 대신 '*'을 사용하면,
컴파일러는 해당 패키지에 클래스 이름을 찾아야 하는 수고를 더 해야 할 것이다.
그렇다고 해서 실행 시 성능상의 차이는 전혀 없으니 안심하자.

import java.util.Calendar;
import java.util.Date;
import java.util.ArrayList;

이처럼 import 문을 여러 번 사용하는 대신 아래와 같이 한 문장으로 처리하면 된다.

import java.util.*;

한 패키지에서 여러 클래스를 사용하는 경우 클래스의 이름을 하나하나 지정해주는 것보다 '패키지.'을 사용하는 것이 편하다.
다만 import하는 패키지의 수가 많을 경우 어느 클래스가 어느 패키지에 속하는지 구별하기 어려운 단점이 있다.
또한 import 문에서 클래스의 이름 대신 '
'를 사용하는 것이 하위 패키지의 클래스까지 포함하는 것이 아니라는 점이다.

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

그래서 위 코드를 아래 코드로 대체할 수 없다.

import java.*;

ex) 현재 날짜와 시간을 지정된 형식에 맞춰서 출력

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

class ImportTest {
	public static void main(String[] args){
    	Date today = new Date();
        
        SimpleDateFormat date = new SimpleDateFormat("yyyy/MM/dd");
        SimpleDateFormat time = new SimpleDateFormat("hh:mm:ss a");
        
        System.out.println("오늘 날짜는"+date.format(today));
        System.out.println("현재 시간은"+time.format(today));
    }
}

실행 결과 : 오늘 날짜는 2021/12/19 // 현재 시간은 16:29:43 오후

SimpleDateFormat과 Date 클래스는
다른 패키지에 속한 클래스므로 import문으로 어느 패키지에 속하는 클래스인지 명시했다.

그래서 소스에서 클래스 이름 앞에 패키지명을 생략할 수 있었다.
만약 import문을 지정하지 않았다면 다음과 같이 클래스 이름에 패키지명도 적었어야 할 것이다.

java.util.Date today = new java.util.Date();
java.text.SimpleDateFormat date
			= new java.text.SimpleDateFormat("yyyy/MM/dd");
java.text.SimpleDateFormat time
		    = new java.text.SimpleDateFormat("hh:mm:ss a");

import문으로 패키지를 지정하지 않으면 위 코드와 같이 모든 클래스 이름 앞에 패키지명을 반드시 붙여야 한다.

단, 같은 패키지 내의 클래스들은 import문을 지정하지 않고도 패키지명을 생략할 수 있다.

지금까지 System과 String 같은 java.lang 패키지의 클래스들을 패키지명 없이 사용할 수 있었던 이유는
모든 소스파일에는 묵시적으로 아래와 같은 import문이 선언됐기 때문이다.

import java.lang.*;

java.lang 패키지는 아주 빈번히 사용되는 중요한 클래스들이 속한 패키지이기 때문에
따로 import문으로 지정하지 않아도 되도록 한 것이다.

3.5 static import문

import문을 사용하면 클래스의 패키지명을 생략할 수 있는 것과 같이
static import문을 사용하면 static 멤버를 호출할 때 클래스 이름을 생략할 수 있다.

특정 클래스의 static 멤버를 자주 사용할 때 편리하고, 코드도 간결해진다.

import static java.lang.Integer.*; // Integer 클래스의 모든 static 메서드
import static java.lang.Math.random; // Math.random()만 . 괄호 안붙임.
import static java.lang.System.out; // System.out을 out만으로 참조 가능

위의 코드처럼 static import문을 선언했다면, 아래의 코드를 간략하게 할 수 있다.

System.out.println(Math.random();

=>

out.println(random());

0개의 댓글