https://github.com/whiteship/live-study
백기선님 자바 기초 스터디 7주차
목표
자바의 패키지에 대해 학습하세요.
학습할 것 (필수)
- package 키워드
- import 키워드
- 클래스패스
- CLASSPATH 환경변수
- -classpath 옵션
- 접근지시자
package 키워드
패키지(package)
패키지는 클래스의 묶음이다.
서로 관련된 클래스끼리 그룹 단위로 묶어 놓음으로써 클래스를 효율적으로 관리할 수 있다.
클래스가 물리적으로 하나의 클래스파일(.class)인 것과 같이 패키지는 물리적으로 하나의 디렉토리이다.
그래서 어떤 패키지에 속한 클래스는 해당 디렉토리에 존재하는 클래스 파일(.class)이어야 한다.
예를 들어, String 클래스의 실제 이름은 java.lange.String이다. 즉, java.lang 패키지에 속한 String 클래스라는 것이다.
이처럼 모든 클래스는 반드시 하나의 패키지에 속하며,
패키지는 점(.)을 구분자로 하여 계층구조로 구성할 수 있다. (ex. java.lang)
패키지의 선언
패키지는 클래스의 소스 파일(.java)의 맨 위에 다음과 같이 한 줄만 적어주면 된다.
package 패키지명;
패키지명은 대소문자를 모두 허용하지만, 클래스명과 쉽게 구분하기 위해서 소문자로 하는 것을 원칙으로 하고 있다.
FQCN (Fully Qualified Class Name)
모든 클래스에는 정의된 클래스 이름과 패키지 이름이 있다.
이 둘을 합쳐야 완전하게 한 클래스를 표현할 수 있으며 FQCN(Fully Qualified Class Name)이라 한다.
ex) String 클래스의 패키지는 "java.lang" 이며 FQCN은 "java.lang.String"이 된다.
import 키워드
import문
소스코드를 작성할 때 다른 패키지의 클래스를 사용하려면 패키지명이 포함된 클래스 이름을 사용해야 한다.
public class Study {
public static void main(String[] args) {
java.util.List<Integer> arr = new java.util.ArrayList<>();
}
}
자주 쓰는 List와 ArrayList 클래스의 경우 이처럼 패키지명 java.util을 붙여줘야 사용할 수 있다.
그러나 클래스의 코드를 작성하기 전에 import문으로 사용하고자 하는 클래스의 패키지를 미리 명시해주면 사용되는 클래스이름에서 패키지명은 생략할 수 있다.
import java.util.ArrayList;
import java.util.List;
public class Study {
public static void main(String[] args) {
List<Integer> arr = new ArrayList<>();
}
}
import문의 선언
모든 소스파일(.java)에서 import문은 package문 다음에, 그리고 클래스 선언문 이전에 위치해야 한다.
1. package문
2. import문
3. 클래스 선언
package com.study
import java.util.ArrayList;
import java.util.List;
public class Study {
public static void main(String[] args) {
List<Integer> arr = new ArrayList<>();
}
}
List, ArrayList처럼 같은 패키지에서 import문을 여러 번 사용하는 경우, 패키지명.*을 이용해서 지정된 패키지에 속하는 모든 클래스를 패키지명 없이 사용할 수 있다.
import java.util.*;
public class Study {
public static void main(String[] args) {
List<Integer> arr = new ArrayList<>();
}
}
+) 참고로 java.lang.String클래스는 따로 import java.lang;을 하지 않는다. java.lang패키지는 매우 빈번히 사용되는 중요한 클래스들이 속한 패키지이기 때문에 따로 import하지 않는다.
static import문
static import문을 사용하면 static멤버를 호출할 때 클래스 이름을 생략할 수 있다.
Math.random();
예시는 static import를 통해 다음과 같이 간결하게 표현할 수 있다.
import static java.lang.Math.random;
random();
클래스패스
클래스패스란 말 그대로 클래스를 찾기 위한 경로이다.
자바의 경우, JVM이 실행될 때, 클래스 파일을 찾는 데 기준이 되는 파일 경로를 말하는 것이다.
소스 코드(.java)를 컴파일(javac)하면 소스 코드는 바이트코드(.class)로 변환된다.
이후 java 명령어로 이 바이트코드를 실행하기 위해서는 이 파일을 찾을 수 있어야 한다.
이 때, 클래스패스에 지정된 경로를 사용하는 것이다.
다음과 같은 경로에 자바 소스 코드가 있다.
</Users/danuri/Desktop/bin/ClassPathTest.java>
class Item {
public void print() {
System.out.println("Hello world");
}
}
class ClassPathTest {
public static void main(String[] args) {
Item item = new Item();
item.print();
}
}
bin % ls
ClassPathTest.java
소스 코드를 컴파일 해보자.
bin % javac ClassPathTest.java
bin % ls
ClassPathTest.class ClassPathTest.java Item.class
이렇게 하나의 소스 코드여도 소스 코드에 포함된 클래스들은 전부 .class 파일로 컴파일된다.
두 .class 파일 모두 현재 디렉토리 /Users/danuri/Desktop/bin/에서 생성된다.
이제 실행해보자.
bin % java ClassPathTest
Hello world
예상한 것과 같이 잘 실행되는 것을 볼 수 있다.
여기서 클래스패스에 대해 생각해보자.
java ClassPathTest
ClassPathTest를 실행하려면 두 클래스 ClassPathTest.class와 Item.class가 필요하다.
즉, 이 두 파일을 찾기 위한 클래스패스는 /Users/danuri/Desktop/bin/ 인 것이다.
java 명령의 경우 클래스패스가 따로 지정되어 있지 않다면 현재 디렉토리를 클래스패스로 지정하기 때문에
java ClassPathTest가 문제 없이 실행된 것이다.
클래스 패스를 따로 지정하는 방법은 지금부터 알아보겠다.
CLASSPATH 환경변수
만약 소스 코드가 있는 /Users/danuri/Desktop/bin/ 경로에 lib이라는 폴더를 하나 만들고 여기에 두 .class 파일을 포함시킨다면 어떻게 될까?
java 실행
bin % java ClassPathTest
Error: Could not find or load main class ClassPathTest
Caused by: java.lang.ClassNotFoundException: ClassPathTest
ClassNotFoundException이 발생한다.
클래스패스는 따로 지정하지 않으면 현재 디렉토리로 설정되는데, 현재 디렉토리인 bin에 클래스파일이 없기 때문에 에러가 난 것이다.
그렇다면 어떻게 클래스패스 경로를 설정할 수 있을까?
총 2가지 방법이 있다.
- 환경변수 설정
- -classpath 옵션
환경변수 설정 방법부터 알아보자.
환경변수는 운영체제에 지정하는 변수로 JVM은 환경변수의 값을 참고해서 동작하게 된다.
자바는 환경변수 CLASSPATH를 사용해서 클래스패스를 설정할 수 있다.
터미널에 vi ~/.zshrc를 입력하고 다음과 같이 환경변수를 지정하자.
export CLASSPATH=.:/Users/danuri/Desktop/bin/lib
1. 맨 앞에 . 은 현재 디렉토리를 말하는 것이고
2. mac 기준으로 콜론(:)은 and, 즉 여러 경로를 함께 클래스패스로 지정할 수 있다. (윈도우는 세미콜론(;)을 입력하면 된다)
3. /Users/danuri/Desktop/bin/lib는 우리가 추가로 지정하고자 하는 클래스패스 경로이다.
esc -> :wq로 변경 사항을 저장하고,
source ~/.zshrc를 입력해 변경 사항을 반영하자.
이제 터미널을 껐다 키면 클래스패스 환경변수를 사용할 수 있다.
bin % java ClassPathTest
Hello world
-classpath 옵션
클래스패스 환경변수가 global하게 클래스패스를 설정하는 방법이라면, 일시적으로 클래스패스를 지정해줄 수도 있다.
-classpath 옵션을 사용하면 바로바로 클래스패스를 지정할 수 있다.
bin % java -classpath /Users/danuri/Desktop/bin/lib ClassPathTest
Hello world
혹은 현재 디렉토리를 기준으로 상대경로를 지정할 수도 있다.
bin % java -classpath lib ClassPathTest
Hello world
또한, 이런 식으로 .class파일이 서로 다른 경로에 있을 때도, 아까 언급한 콜론(:)을 이용해서 클래스패스를 설정할 수 있다.
bin % java -classpath .:lib ClassPathTest
Hello world
(현재경로 : 현재경로/lib)
접근지시자
접근지시자는 멤버 또는 클래스에 사용되어, 해당하는 멤버 또는 클래스를 외부에서 접근하지 못하도록 제한하는 역할을 한다.
접근지시자가 사용되는 곳 - 클래스, 멤버변수, 메서드, 생성자
- private: 같은 클래스 내에서만 접근 가능
- default: 같은 패키지 내에서만 접근 가능 (접근지시자가 따로 지정되어 있지 않다면 defalut이다)
- protected: 같은 패키지 내에서, 그리고 다른 패키지의 자식클래스에서 접근 가능
- public: 접근 제한 없음
-> 특히 클래스는 public이나 (default) 접근지시자만 사용 가능하다.
<접근지시자를 사용하는 이유>
- 외부로부터 데이터를 보호하기 위해서
- 외부에는 불필요한, 내부적으로만 사용되는 부분을 감추기 위해서
-> 이를 접근지시자를 이용한 '캡슐화'라고 한다.
접근지시자를 사용하는 대표적인 예는 getter, setter이다. 다음 예시를 보자.
public class Study {
private int num;
private String name;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
1. public class
하나의 소스파일(.java)에는 public클래스가 단 하나만 존재할 수 있으며, 소스파일의 이름은 반드시 public클래스의 이름과 같아야 한다.
2. private int num;
멤버 변수를 private 접근지시자로 외부의 접근을 제한했다.
만약 특정 인스턴스의 멤버 변수를 s.num+=1 처럼 외부에서 자유롭게 접근할 수 있다면, 한 눈에 알아보기도 힘들고 유지보수도 어렵다. 그래서 대부분 멤버 변수의 경우 private으로 클래스 내부에서만 사용하도록 한다.
3. public int getNumI(), public void setNum(int num)
멤버 변수를 private하면 특정 인스턴스의 멤버 변수를 조회하거나 값을 변경하거나 할 수는 없을 것이다.
대신 멤버 변수 xxx에 대해 의미 있는 이름의 메서드인 public getXxx, setXxx 를 통해 멤버 변수에 접근하도록 한다.
직접 접근이 아닌 메서드를 통한 접근을 통해 보다 직관적으로 코드를 이해할 수 있다.
-> 클래스를 생성한다고 했을 때, 상속을 위해 변수를 protected로 풀어주는 경우를 제외하면, 보통 예시와 같은 방식을 가장 많이 사용한다.
'java > java' 카테고리의 다른 글
[Java] 예외 처리 (1) | 2021.08.12 |
---|---|
[Java] 인터페이스 (2) | 2021.07.27 |
[Java] 상속 (3) | 2021.07.12 |
[Java] 클래스 (1) | 2021.07.07 |
[Java] 제어문 (3) | 2021.06.29 |