on
7주차 과제: 패키지.
해당 글을 백기선 님의 자바 스터디 7주차 과제를 공부하고 공유하기 위해서 작성되었습니다.
목표
자바의 패키지에 대해 학습한다.
학습할 것
package 키워드
패키지(package)
패키지란, 클래스의 묶음이다. 패키지에는 클래스 또는 인터페이스를 포함시킬 수 있으며, 서로 관련된 클래스들끼리 그룹 단위로 묶어 놓음으로써 클래스를 효율적으로 관리한다.
같은 이름의 클래스라도 서로 다른 패키지에 존재하는 것이 가능하므로, 자신만의 패키지 체계를 유지함으로써 다른 개발자가 개발한 클래스 라이브러리의 클래스와 이름이 충돌하는 것을 피할 수 있다.
클래스의 실제 이름(full name)은 패키지명을 포함한 것이다. 예를 들어, String 클래스의 패키지명을 포함한 이름은 java.lang.String
이다. 즉, java.lang
패키지에 속한 String 클래스라는 의미이다. 따라서 이름이 같더라도 패키지명으로 구별이 가능한 것이다.
클래스가 물리적으로 하나의 클래스파일(.class)인 것과 같이 패키지는 물리적으로 하나의 디렉토리이다. 따라서 어떤 패키지에 속한 클래스는 해당 디렉토리에 존재하는 클래스파일(.class)이어야 한다.
디렉토리가 하위 디렉토리를 가질 수 있는 것처럼, 패키지도 다른 패키지를 포함할 수 있으며 점 ‘.’으로 구분한다. java.lang
패키지에서 lang
패키지는 java
패키지의 하위 패키지이다.
- 하나의 소스파일에는 첫 번째 문장으로 단 한 번의 패키지 선언만을 허용한다.
- 모든 클래스는 반드시 하나의 패키지에 속해야 한다.
- 패키지는 점(.)을 구분자로 하여 계층구조로 구성할 수 있다.
- 패키지는 물리적으로 클래스 파일(.class)을 포함하는 하나의 디렉토리이다.
패키지의 선언
패키지를 선언하는 것은 다음과 같다. 클래스나 인터페이스의 소스파일(.java)에 다음과 같은 한 줄을 적어주면 된다.
package 패키지명;
위와 같은 패키지 선언문은 반드시 소스파일에서 주석과 공백을 제외한 첫 번째 문장이어야 하며, 하나의 소스파일에 단 한번만 선언될 수 있다.
패키지명은 대소문자 모두 허용하지만, 클래스명과 쉽게 구분하기 위해서 소문자로 하는 것을 원칙으로 하고 있다.
- 패키지는 주석과 공백을 제외한 첫 번째 문장이어야 한다.
- 하나의 소스파일에 단 한번만 선언될 수 있다.
- 패키지명은 대소문자 모두 허용되지만, 클래스명과 구분을 위해 소문자로 해야한다.
- 패키지명과 위치한 폴더의 이름이 같아야 한다.
- 패키지명을 java로 시작하면 안된다.
이름 없는 패키지
자바의 모든 클래스는 하나의 패키지에 포함되어야 한다. 만일 소스파일을 작성할 때 패키지를 지정하지 않으면, 자바에서 기본적으로 제공하는 이름없는 패키지에 포함된다. 따라서 패키지를 지정하지 않은 모든 클래스들은 같은 패키지에 속하게 된다.
import 키워드
소스코드를 작성할 때 다른 패키지의 클래스를 사용하려면 패키지명이 포함된 클래스 이름을 사용해야 한다. 하지만, 매번 패키지명을 붙여서 작성하기엔 불편하다.
클래스의 코드를 작성하기 전에 import문으로 사용하고자 하는 클래스의 패키지를 미리 명시해주면 소스코드에 사용되는 클래스이름에서 패키지명을 생략할 수 있다.
import문의 역할은 컴파일러에게 소스파일에 사용된 클래스의 패키지에 대한 정보를 제공하는 것이다. 컴파일 시에 컴파일러는 import문을 통해 소스파일에 사용된 클래스들의 패키지를 알아 낸 다음, 모든 클래스 이름 앞에 패키지명을 붙여 준다.
import문의 선언
모든 소스파일(.java)에서 import문은 package문 다음에, 그리고 클래스 선언문 이전에 위치해야 한다. import문은 package문과 달리 한 소스파일에 여러 번 선언할 수 있다.
- 일반적인 소스파일(*.java)의 구성
- package문
- import문
- 클래스 선언
import문을 선언하는 방법은 다음과 같다.
import 패키지명.클래스명;
import 패키지명.*;
키워드 import와 패키지명을 생략하고자 하는 클래스의 이름을 패키지명과 함께 써준다.
클래스 이름을 지정해주는 대신 ‘*‘을 사용하면, import문을 여러 번 사용하는 대신 한 문장으로 처리할 수 있다. 예를 들어 다음과 같이 줄일 수 있다.
import java.util.ArrayList;
import java.util.Scanner;
import java.util.*;
하나의 패키지에 속한 여러 클래스를 사용할 경우 클래스 이름을 일일히 지정하기 보다는 패키지명.*
과 같이 하는 것이 편리하다.
한 가지 주의해야 할 점은 import문에서 클래스의 이름 대신 ‘*‘을 사용하는 것이 하위 패키지의 클래스까지 포함하는 것은 아니다.
import java.util.*;
import java.text.*;
위의 두 문장을 아래와 같이 할 수 없다.
import java.*;
java.lang 패키지
java.lang
패키지는 자바프로그래밍에 가장 기본이 되는 클래스들을 포함하고 있는 패키지이다. java.lang
패키지는 다른 패키지들과 달리 모든 소스파일에 묵시적으로 선언되어 있다. 따라서 System과 String 같은 java.lang
패키지에 속한 클래스들은 import문 없이 사용할 수 있었던 것이다.
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만으로 참조가능.
위와 같이 선언하였다면 다음과 같이 생략이 가능해진다.
System.out.println(Math.random());
out.println(random());
예제를 살펴보자.
import static java.lang.System.out;
import static java.lang.Math.*;
class App {
public static void main(String[] args) {
// System.out.println(Math.random());
out.println(random());
// System.out.println("Math.PI : " + Math.PI);
out.println("Math.PI : " + PI);
}
}
클래스패스
클래스패스란 클래스를 찾기위한 경로이다. 즉, JVM이 프로그램을 실행할 때, 클래스 파일(.class)을 찾는데 기준이 되는 파일 경로를 말하는 것이다.
(참고 : https://hoonmaro.tistory.com/19)
자바의 실행과정을 살펴보면 소스 코드(.java)를 컴파일하면 소스 코드가 바이트 코드(바이너리 형태의 .class 파일)로 변환된다. Java runtime(java 또는 jre)으로 이 파일(바이너리 형태의 .class 파일)에 포함된 명령을 실행하려면, 이 파일을 찾을 수 있어야 한다. 이 때 classpath에 지정된 경로를 사용하여 .class 파일을 찾는다.
classpath는 .class 파일이 포함된 디렉토리와 파일을 콜론으로 구분한 목록인데, java runtime은 이 classpath에 지정된 경로를 모두 검색해서 특정 클래스에 대한 코드가 포함된 .class 파일을 찾는다.
classpath를 지정할 수 있는 방법은 두 가지가 있다.
- CLASSPATH 환경변수 사용
- java runtime에 -classpath 옵션 사용
classpath에 사용할 수 있는 값
classpath는 콜론 ‘:’으로 구분된 디렉토리 및 파일 목록으로 다음 세 가지 유형의 파일과 디렉토리를 classpath에 지정할 수 있다.
- /dev/workspace/username/java/classes와 같은 디렉토리
- myclass.zip와 같은 zip
- myclass.jar와 같은 jar(자바 아카이브)파일
CLASSPATH 환경변수
JVM이 시작될 때 JVM의 클래스 로더는 CLASSPATH 환경변수를 호출해서 환경 변수에 설정되어 있는 디렉토리가 호출되면 그 디렉토리에 있는 클래스들을 먼저 JVM에 로드한다.
CLASSPATH 환경변수에 대해서 공부하다보니 대부분 윈도우를 기준으로 PATH 설정에 대한 설명들이 올라와있는데 현재 Mac을 쓰고 있다보니 Mac에서는 어떻게 설정하는지 찾아봤다.
Mac에서는 터미널을 이용해서 설정하는데 환경변수 설정을 통해서 작성하는 윈도우와 달리 파일을 생성해주어야 했다.
ls -al
을 사용하여 빨간 상자로 표시된 .bash_profile
이 있는지 확인하고 없다면 만들면 된다.
vi
명령어를 통해서 파일을 수정 또는 생성하는데, 파일 내부에 다음과 같은 문장을 추가하면 PATH
설정이 된다.
export PATH=${PATH}
예를 들어 JDK 1.8을 기본으로 설정하고 PATH 설정을 하려면 다음과 같이 작성한 후 저장하면 된다.
export PATH=${PATH}:$JAVA_HOME/bin
path가 없는데 어떻게 실행이 된걸까?
지금까지 자바를 사용하면서 특별히 오류가 난 적이 없기에 딱히 신경쓰지 않았는데 이번에 PATH에 대해서 공부하면서 확인을 해봤는데 path 설정이 안되어 있었다. 그래서 도대체 어떻게 된 것일까 궁금해서 조금 찾아봤더니 인텔리제이의 경우 인텔리제이 툴 내에서 JDK 설정을 따로 하기때문에 딱히 필요가 없었던거 같다.
그 외에도 CLASSPATH에서 정의된 라이브러리를 쓰기 위해서 클래스 로더가 호출하는 것이기 떄문에 안잡아줘도 된다는 답변도 있었고, 배포환경에서만 신경쓰면 된다는 답변도 있었다.
아무튼 신경쓰이면 잡아주면 되는 것이고 인텔리제이를 계속 쓸거라면 그냥 신경 안 써도 될듯하다.
-classpath 옵션
자바 프로그램을 실행시켜 주는 명령어가 제공되는데, 사용법은 다음과 같다.
java <option> <classfile> <argument>
-
: 호출될 클래스 파일 이름 -
: main 함수에 파라미터로 보내질 문자열
-classpath 옵션 (-cp)
-classpath
옵션은 참조할 클래스 파일의 패스(경로)를 지정하는데, jar 파일, zip 파일, 클래스 파일의 디렉토리 위치를 적어주면 된다.
접근지시자
접근 제어자(지시자)는 멤버 또는 클래스에 사용되어, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다. 접근 제어자가 default임을 알리기 위해 실제로 default를 붙이지는 않는다. 클래스나 멤버변수, 메서드, 생성자에 접근 제어자가 지정되어 있지 않다면, 접근 제어자가 default임을 뜻한다.
- 접근 제어자가 사용될 수 있는 곳 - 클래스, 멤버변수, 메서드, 생성자
- private : 같은 클래스 내에서만 접근이 가능하다.
- default : 같은 패키지 내에서만 접근이 가능하다.
- protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손 클래스에서 접근이 가능하다.
- public : 접근 제한이 없다.
public은 접근 제한이 전혀 없고, private은 같은 클래스 내에서만 사용하도록 제한하는 가장 높은 제한이다. 그리고 default는 같은 패키지 내의 클래스에서만 접근이 가능하도록 하는 것이다.
protected는 패키지에 관계없이 상속관계에 있는 자손클래스에서 접근할 수 있도록 하는 것이 제한목적이지만, 같은 패키지 내에서도 접근이 가능하다.
대 상 | 사용가능한 접근 제어자 |
클래스 | public, (default) |
메서드 | public, protected, (default), private |
멤버변수 | |
지역변수 | 없 음 |
접근 제어자를 이용한 캡슐화
클래스나 멤버, 주로 멤버에 접근 제어자를 사용하는 이유는 클래스 내부에 선언된 데이터를 보호하기 위해서이다. 데이터가 유효한 값을 유지하도록, 또는 외부에서 비밀번호와 같은 데이터를 함부로 변경하지 못하도록 하기 위해서 외부로부터의 접근을 제한해야 한다.
이러한 것을 데이터 감추기(data hiding)라고 하며, 객체지향개념의 캡슐화(encapsulation)에 해당하는 내용이다.
또다른 이유는 클래스 내에서만 사용되는, 내부 작업을 위해 임시로 사용하는 멤버변수나 부분작업을 처리하기 위한 메서드 등의 멤버들을 클래스 내부에 감추기 위해서이다.
- 접근 제어자를 사용하는 이유
- 외부로부터 데이터를 보호하기 위해
- 외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해
Reference
Comments
JAVA STUDY HALLE 의 다른 글
-
15주차 피드백 06 Mar 2021
-
15주차 과제: 람다식. 28 Feb 2021
-
14주차 피드백 27 Feb 2021
-
14주차 과제: 제네릭. 22 Feb 2021
-
13주차 피드백 20 Feb 2021
-
13주차 과제: I/O. 08 Feb 2021
-
12주차 피드백 06 Feb 2021
-
12주차 과제: 애노테이션. 01 Feb 2021
-
11주차 피드백 30 Jan 2021
-
11주차 과제: Enum. 24 Jan 2021
-
10주차 피드백 23 Jan 2021
-
10주차 과제: 멀티쓰레드 프로그래밍. 18 Jan 2021
-
9주차 피드백 16 Jan 2021
-
9주차 과제: 예외 처리. 10 Jan 2021
-
8주차 피드백 09 Jan 2021
-
8주차 과제: 인터페이스. 03 Jan 2021
-
7주차 피드백 02 Jan 2021
-
7주차 과제: 패키지. 28 Dec 2020
-
6주차 피드백 27 Dec 2020
-
6주차 과제: 상속. 21 Dec 2020
-
5주차 피드백 20 Dec 2020
-
5주차 과제: 클래스. 14 Dec 2020
-
4주차 피드백 13 Dec 2020
-
4주차 과제: 제어문. 30 Nov 2020
-
3주차 피드백 29 Nov 2020
-
3주차 과제: 연산자. 22 Nov 2020
-
2주차 피드백 21 Nov 2020
-
2주차 과제: 자바 데이터 타입, 변수 그리고 배열. 15 Nov 2020
-
1주차 피드백 15 Nov 2020
-
1주차 과제: JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가. 08 Nov 2020