▶ 패키지(Package)
- 패키지(package) : 관련 있는 클래스나 인터페이스들을 묶은 것이다.
- 클래스를 찾아서 사용하기 쉬워지며 서로 다른 내용의 동일 이름의 충돌을 막을 수 있고 접근을 제어할 수 있다.
- 자바가 제공하는 라이브러리도 기능별로 패키지로 묶여서 제공되고 있다.
기초적인 기능 제공 패키지 : java.lang
네트워크 담당 기능 패키지 : java.net
- 그러나 사용자가 직접 패키지를 만들어 사용할 수도 있다. src 폴더 아래에 패키지 폴더를 생성하면, 그 아래 소스 파일 맨 위에 package 키워드를 기재해야 한다.
package (패키지명); //끝에 세미콜론 필수
public class (클래스명) {
...
}
- 사용자 라이브러리 패키지의 예는 아래와 같다.
package graphics;
//Drawable.java 파일로 저장
public interface Drawable {
...
}
package graphics;
//Shape.java 파일로 저장
public abstract class Shape {
...
}
package graphics;
//Circle.java 파일로 저장
public class Circle extends Shape implements Drawable {
...
}
package graphics;
//Rectangle.java 파일로 저장
public class Rectangle extends Shape implements Drawable {
...
}
- 패키지를 이용하면 개발자는 다양한 장점을 가질 수 있다.
개발자들은 클래스들이 서로 연관되어 있음을 쉽게 알 수 있다.
개발자들은 그래픽을 제공하는 클래스들을 쉽게 찾을 수 있다.
패키지마다 독립적인 이름 공간을 가지므로 다른 패키지의 동일한 이름의 클래스가 있더라도 충돌을 일으키지 않는다.
- 각각의 패키지는 접근에 제약을 가할 수 있으므로 동일 패키지 안의 클래스들은 서로 간에 자유롭게 사용할 수 있고 다른 패키지는 그러지 못하게 설정할 수 있다.
- 위에서 지정한 패키지는 실제로 자바의 java.awt 패키지에 있는 클래스와 동일한 이름의 클래스를 가지고 있다. 그러나 자바는 서로 다른 패키지에서 동일한 이름의 클래스를 허용한다.
기존의 클래스 이름 : java.awt.Rectangle
사용자 클래스 이름 : graphics.Rectangle
- 단, 패키지 이름이 같으면 동일한 이름이 허용되지 않으며, 이를 위한 규칙이 존재한다.
패키지의 이름은 클래스나 인터페이스의 이름과의 중복을 피하기 위해 일반적으로 소문자만 사용한다.
패키지 이름으로 인터넷 도메인 이름의 역순을 사용한다. 기업에서는 “회사명.부서명.프로젝트이름”으로 짓는 경우가 많다. 예를 들어, A회사의 Network 부서의 wifi라는 프로젝트이름을 가지고 패키지를 짓는다면 network.A.wifi 가 패키지명이 될 것이다.
자바 언어 자체의 패키지는 java나 javax로 시작한다.
▶ 패키지 사용하기
- 패키지 안에 포함된 클래스나 인터페이스는 패키지 멤버라고 불린다.
- 위에서 설명했듯이 패키지 내에서는 클래스와 인터페이스 간의 참조가 자유롭지만 다른 패키지 간의 멤버에 서로 접근할 때는 제약이 가해진다. 따라서 제약 조건인 아래의 세 가지 방법을 통해 외부 패키지로 접근할 수 있다.
경로까지 포함하는 완전한 이름으로 참조하는 방법
원하는 패키지 멤버만을 import 하는 방법
패키지 전체를 import 하는 방법
- 완전한 이름으로 참조 : 외부 패키지에 있는 클래스를 사용하려면 클래스의 완전한 이름을 써주어야 한다. 예를 들어 아까 만들었던 graphics 패키지의 Rectangle 클래스를 외부 패키지에서 사용한다면 아래와 같이 기재해야 한다.
graphics.Rectangle rect = new graphics.Rectangle();
자주 사용하지 않는 클래스의 경우 이 방식을 주로 사용한다.
- 패키지 멤버를 import : 외부 패키지의 특정한 멤버를 import 하려면 다음과 같은 문장을 사용한다.
import graphics.Rectangle;
...
Rectangle rect = new Rectangle();
- 전체 패키지 import : 하나의 패키지 안의 모든 멤버를 사용하고자 할 때 사용한다.
import graphics.*;
...
Circle circle = new Circle();
Rectangle rect = new Rectangle();
- 똑같은 이름의 클래스를 가지는 패키지가 동시에 import 된 경우, 모호성을 제거하기 위해 정식 이름을 사용하여야 한다.
import A;
import B;
...
A.ClassOrder = new A.ClassOrder(); //패키지 A의 ClassOrder 클래스 사용
B.ClassOrder = new B.ClassOrder(); //패키지 B의 ClassOrder 클래스 사용
▶ 계층 구조의 패키지
- 하나의 패키지 안에 또 다른 패키지가 있을 수 있다. 그러나 상위 패키지라는 개념이 자바에는 적용되지 않는다.
예를 들어 java.awt 패키지 안에는 font 패키지가 있으나 java.awt 패키지만 import해서는 font 패키지를 사용할 수 없다. 즉, font 패키지와 awt 패키지 모두 사용하고 싶다면 아래와 같은 방법이어야 한다.
java.awt.*;
java.awt.font.*;
쉽게 말해, java.awt 패키지와 java.awt.font 패키지는 서로 다른 패키지이다.
▶ 정적 import 문장
- 클래스 안에 정의된 정적 상수나 정적 메소드를 사용하는 경우에는 일반적으로 클래스 이름을 앞에 적어서 사용한다.
예를 들어, java.lang.Math 클래스 안에는 PI가 상수로 정의되어 있고, sin(), cos(), tan()와 같은 수많은 정적 메소드들이 정의되어 있다. 이들을 사용하려면 아래와 같이 클래스 이름을 앞에 붙여야 한다.
double r = Math.cos(Math.PI*theta);
- 정적 import 문장을 사용하면 클래스 이름은 생략하여도 된다.
import static java.lang.Math.*;
...
double r = cos(PI*theta);
- 너무 남용하면 읽기 어려운 코드가 되니 주의해야 한다.
▶ 소스 파일과 클래스 파일 관리
- 자바는 “계층 디렉토리 구조”를 이용하여 소스 파일과 클래스 파일을 관리한다.
- 즉, 패키지의 계층 구조를 반영한 디렉토리 구조에 소스들을 저장한다.
- 실제 자바 파일은 (기반 디렉토리)\(패키지명)\(클래스명).java 로 저장된다.
- 여기서 기반 디렉토리란 작업 디렉토리가 된다. 예를 들어, 이클립스에서 설정했던 워크스페이스(workspace)가 작업 디렉토리이다.
- 패키지의 멤버의 완전한 이름과 파일의 경로 이름과는 일치하여야 한다.
완전한 이름 : graphics.Rectangle
파일의 경로 이름 : graphics\Rectangle.java
- 소스 파일을 컴파일하면 컴파일러는 각 클래스들을 서로 다른 출력 파일로 저장한다. 출력 파일의 이름은 클래스 이름과 같고, 확장자는 “.class”이다.
- 소스 파일들과 마찬가지로 클래스 파일도 패키지 이름을 반영하는 디렉토리 구조에 저장된다. 참고로 클래스 파일들에 대한 경로는 반드시 자바 소스 파일에 대한 경로와 같을 필요는 없다.
소스 파일 경로 → C:\source\com\company\graphics\Rectangle.java
클래스 파일 경로 → C:\class\com\company\graphics\Rectangle.class
- 단, 소스와 클래스 파일을 서로 다른 위치에 저장하려면 컴파일러와 자바 가상 기계(JVM)가 이 파일들을 찾을 수 있도록 설정하여야 한다.
- 위에 서술한 클래스 파일 경로의 일부분 “C:\class”는 실행에 필요한 클래스 파일들이 저장되는 디렉토리이다. 이를 “클래스 경로(class path)”라고 하며, 시스템 변수 CLASSPATH에 저장되어 있어야 한다.
- 자바 컴파일러와 자바 가상 기계(JVM)는 모두 .class 파일에 대한 경로를 만들 때, 클래스 경로에 패키지 이름을 붙여서 만든다. 즉, 클래스 경로가 “C:\class”로 설정하고 패키지 이름이 com.company.graphics 라면 컴파일러와 JVM이 클래스 파일을 찾는 디렉토리는 다음과 같다.
C:\class\com\company\graphics
- 클래스 경로의 디폴트 값으로 컴파일러와 JVM은 현재 디렉토리와 자바 플랫폼 클래스들을 포함하고 있는 JAR 파일을 탐색한다.
▶ JAR 파일
- 클래스 파일은 JAR(Java archive) 파일 형태로 저장될 수 있다.
- JAR 파일은 여러 개의 클래스 파일을 디렉토리의 계층 구조를 유지한 채로 압축하여서 가지고 있을 수 있다.
- 실행 파일(.exe)을 만들 때도 JAR 파일이 이용된다.
▶ 자바에서 지원하는 패키지
java.applet |
애플릿을 생성하는 데 필요한 클래스 |
java.awt |
그래픽과 이미지를 위한 클래스 |
java.beans |
자바빈즈 구조에 기초한 컴포넌트를 개발하는 데 필요한 클래스 |
java.io |
입력과 출력 스트림을 위한 클래스 |
java.lang |
자바 프로그래밍 언어에 필수적인 클래스 |
java.math |
수학에 관련된 클래스 |
java.net |
네트워킹 클래스 |
java.nio |
새로운 네트워킹 클래스 |
java.rmi |
원격 메소드 호출(RMI) 관련 클래스 |
java.security |
보안 프레임워크를 위한 클래스와 인터페이스 |
java.sql | 데이터베이스에 저장된 데이터를 접근하기 위한 클래스 |
java.util | 날짜, 난수 생성기 등의 유틸리티 클래스 |
javax.imageio | 자바 이미지 입출력 API |
javax.net | 네트워킹 애플리케이션을 위한 클래스 |
javax.swing | 스윙 컴포넌트를 위한 클래스 |
javax.xml | XML을 지원하는 패키지 |
▶ 자주 사용되는 java.lang 패키지
- 위의 표에 나와있듯 java.lang 패키지는 자바 프로그래밍 언어에 필수적인 클래스를 포함하고 있다.
클래스 이름 |
설명 |
Object |
기초적인 메소드를 제공하는 모든 클래스의 최상위 클래스 |
Math |
각종 수학 함수들을 포함하는 클래스 지수나 로그, 제곱근, 삼각함수 등과 같은 기본적인 수치 연산을 위한 메소드들을 제공한다. |
Wrapper |
Integer와 같이 기초 자료형을 감싸서 제공하는 랩퍼 클래스 |
String, StringBuffer |
문자열을 다루는 클래스 |
System |
시스템 정보를 제공하거나 입출력을 제공하는 클래스 |
Thread | 스레드 기능을 제공하는 클래스 |
Class | 객체를 생성한 클래스에 대한 정보를 얻기 위한 클래스 |
- Class 클래스 : 실행 중인 자바 애플리케이션 안에 포함된 클래스들과 인터페이스를 나타낸다. Class는 생성자가 없다. 대신에 해당 객체는 자바 가상 기계에 의하여 자동적으로 생성된다. 객체 자체를 출력, 객체의 이름만 출력 등을 수행하는 메소드가 포함된다.
- System 클래스 : 실행 시스템과 관련된 속성과 메소드를 제공한다. 예시로 우리가 자주 사용하는 콘솔 출력 메소드인 System.out.println() 이 바로 System 클래스가 제공하는 메소드 중의 하나이다. System 클래스 안에 들어 있는 out은 PrintStream 타입의 객체로 정적 변수로 선언되어 있으며 모니터를 나타낸다. 반면, in은 InputStream 타입의 객체로 정적 변수이며 키보드를 나타낸다.
필드 |
static PrintStream err |
표준 오류 출력 스트림 |
static InputStream in |
표준 입력 스트림 |
|
static PrintStream out |
표준 출력 스트림 |
|
주요 메소드 |
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) |
지정된 소스 배열을 목적지 배열로 복사한다. |
static long currentTimeMillis() |
밀리초 단위로 현재 시각을 반환한다. |
|
static void exit(int status) |
현재 실행 중인 자바 가상 기계를 중단한다. |
|
static String getenv(String name) |
지정된 환경 변수의 값을 얻는다. |
|
static String getProperty(String key) |
키에 의해서 지정된 시스템의 특성을 얻는다. |
|
static long nanoTime() |
나노초 단위로 현재 시각을 반환한다. |
- Wrapper 클래스 : 기초 자료형을 객체로 포장할 때 사용하는 클래스이다.
기초자료형 |
랩퍼 클래스 |
byte |
Byte |
short |
Short |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
char |
Character |
boolean |
Boolean |
void |
Void |
랩퍼 클래스에서 가장 많이 사용되는 메소드는 기초 자료형을 문자열로 변환하거나, 문자열을 기초 자료형으로 변환하는 메소드이다.
Integer 클래스 제공하는 일부 메소드 | |
static int intValue() | int형으로 변환한다. |
static double doubleValue() | double형으로 변환한다. |
static float floatValue() | float형으로 변환한다. |
static int parseInt(String s) | 문자열을 int형으로 변환한다. |
static String toBinaryString(int i) | int형의 정수를 2진수 형태의 문자열로 변환한다. |
static String toHexString(int i) | int형의 정수를 16진수 형태의 문자열로 변환한다. |
static String toOctalString(int i) | int형의 정수를 8진수 형태의 문자열로 변환한다. |
static String toString(int i) | int형의 정수를 10진수 형태의 문자열로 변환한다. |
static Integer valueOf(String s) | 문자열 s를 Integer 객체로 변환한다. |
static Integer valueOf(String s, int radix) | 문자열 s를 radix 진법의 Integer객체로 변환한다. |
이 메소드들은 많이 사용되고, 정적 메소드이므로 객체를 생성하지 않고 클래스의 이름에 도트 연산자를 붙여서 사용할 수 있다.
자바는 Wrapper 객체와 기초 자료형 사이의 변환을 자동으로 하여 주는 “오토 박싱(auto-boxing)"기능을 제공한다.
Integer box;
box = 10; //정수를 자동으로 Integer 객체로 포장한다.(boxing)
System.out.println(box+1); //box는 자동으로 int형으로 변환된다.(unboxing)
- StringBuffer 클래스 : 변경 가능한 문자열을 저장하는 클래스이다.
String 클래스는 주로 상수 문자열, 즉 변경이 불가능한 문자열을 나타낼 때 사용된다. String 클래스의 경우 빈번하게 문자열을 변경하는 경우에는 비효율적일 수 있다. 예를 들어 문자열 연산자인 + 연산자를 사용할 경우, 연산을 할 때마다 새로운 객체가 생성되고 기존의 String 객체도 힙 영역에 남아있게 되므로 기존 객체를 사용하지 않으면 메모리 공간을 낭비하게 된다.
이 때 변경 가능한 문자열을 위한 위 상황의 해결책으로 StringBuffer나 StringBuilder 클래스가 제공된다. 두 클래스는 유사한 메소드를 가지고 있으나 속도 면에서 차이가 있다. 이는 나중에 알아보도록 하고, 가장 큰 차이는 StringBuffer는 다중 스레드 환경에서 안전하다는 것이고, 다중 스레드 환경이 아닐 때는 StringBuilder가 더 효율적이다. 따라서 스레드를 사용하지 않는다면 StringBuilder 객체를 사용하는 것이 좋다.
StringBuffer와 StringBuilder 객체 모두 내부적으로 문자열을 저장하는 메모리를 가지고 있다. 이 메모리를 버퍼(buffer)라고 하며, 가변적이기 때문에 문자열 연산에서 빼진 문자열은 저장하지 않고 지운다. 즉, 버퍼의 크기는 자동적으로 조정된다.
- StringBuffer 클래스 설명 (메소드의 경우 StringBuilder 클래스의 메소드명과 일치하므로 필요할 때 StringBuilder 클래스의 해당 메소드이름을 호출하여도 된다.)
생성자 |
StringBuffer() |
버퍼가 비어 있는 StringBuffer 객체를 생성한다. |
StringBuffer(String s) |
매개변수로 넘겨 받은 문자열을 초기값으로 버퍼에 저장한 StringBuffer 객체를 생성한다. |
|
메소드 |
StringBuffer append(String s) |
인수는 먼저 문자열로 변환되어서 문자열 뒤에 추가된다. |
StringBuffer append(char[] str) |
||
StringBuffer append(char[] str, int offset, int len) |
||
StringBuffer delete(int start, int end) |
지정된 문자를 삭제한다. |
|
StringBuffer deleteCharAt(int index) |
||
StringBuffer insert(int offset, char[] str) |
offset은 시작 위치를 의미하며, offset부터 두 번째 매개변수로 주어진 배열을 문자열로 변환한 뒤 삽입한다. |
|
StringBuffer insert(int index, char[] str, int offset, int len) |
||
StringBuffer replace(int start, int end, String s) |
start부터 end까지의 위치를 문자열 s로 변경한다. 이 때 start위치는 포함되나 end 위치는 포함되지 않는다. |
|
void setCharAt(int index, char c) | 해당 인덱스의 문자를 매개변수로 받은 문자(c)로 설정 | |
StringBuffer reverse() | 지정된 문자들의 순서를 역순으로 한다. |
▶ java.util 패키지
- Random 클래스 : 난수를 얻는데 사용된다.
48 비트 길이의 시드(seed)를 사용하여 알고리즘으로는 변형된 선형 합동 수식을 이용한다.
동일한 시드를 이용하여서 두 개의 Random 객체가 생성된다면 동일한 난수를 발생하게 된다.
생성자 | Random() | 새로운 난수 발생기 객체를 생성한다. |
Random(longseed seed) | 주어진 시드를 사용하는 새로운 난수 발생기 객체를 생성한다. | |
메소드 | protected int next(int bits) | 다음 난수를 반환한다. |
boolean nextBoolean() | boolean 형의 다음 난수를 반환한다. | |
void nextBytes(byte[] bytes) | byte형의 난수를 발생하여서 주어진 배열을 채운다. | |
double nextDouble() | double 형의 0.0과 1.0 사이의 난수를 반환한다. | |
float nextFloat() | float 형의 0.0과 1.0 사이의 난수를 반환한다. | |
int nextInt() | int형의 난수를 반환한다. | |
int nextIng(int n) | 0과 n사이의 int형의 난수를 발생한다. | |
long nextLong() | long 형의 난수를 발생한다. | |
void setSeed(long seed) | 시드를 설정한다. |
Random 예시
import java.util.Random; public class RandomTest { public static void main(String[] args) { Random random = new Random(); for(int i = 0; i < 10; i++) { System.out.println(random.nextInt(100)); //0~100사이의 난수를 발생한다. } } }
- Arrays 클래스 : 배열을 다루는 다양한 메소드들을 가지고 있다. 대표적으로 정렬 및 탐색과 같은 메소드가 있고, 배열을 리스트로 보게 하는 정적 팩토리 메소드도 제공한다. 이 클래스는 다음에 배울 자바 컬렉션 프레임 워크에 속한다.
메소드 |
|
static List asList(Object[] a) |
주어진 배열을 고정 길이의 리스트로 변환한다. |
static int binarySearch(int[] a, int key) |
주어진 값을 int형의 배열에서 이진 탐색한다. |
static int binarySearch(Object[] a, Object key) |
Object 타입의 배열에서 key를 이진 탐색하여 해당 key의 인덱스를 반환한다. |
static int[] copyOf(int[] original, int len) |
주어진 배열을 새로운 크기의 배열에 길이 len만큼 복사한다. (0~len) |
static int[] copyOfRange(int[] original, int from, int to) |
배열에서 주어진 구간의 값들을 새로운 배열로 복사한다. |
static boolean equals(int[] a, int[] a2) |
주어진 두 개의 배열이 같으면 true를 반환한다. |
static void fill(int[] a, int val) | 주어진 val 값을 가지고 배열을 채운다. |
static void sort(int[] a) | 지정된 int형의 배열을 정렬한다. |
위의 메소드는 double 형의 배열, float 형의 배열 등의 다양한 타입의 배열에도 타입만 다르게 하여 사용가능하다.
정적메소드이므로 "클래스이름.메소드이름" 으로 호출해야 한다.
추가로 java.lang.reflect 패키지 안에 Array 라는 클래스가 존재한다. 따라서 import 할 때 스펠링을 잘보고 Arrays 클래스와 Array 클래스를 구별하는데 주의해야 한다.
- Date 클래스 : 밀리초 단위로 현재 시각을 나타낸다. Date 객체를 연도, 월, 일로 변환하는 메소드가 있다. 현재는 국제화에 맞지 않아 권장되지 않는다.
Date date = new Date(); //현재 날짜를 Date 객체로 생성한다.
- Calendar 클래스 : 추상 크래스로서 날짜와 시간에 대한 정보를 가지고 있고 특정 시각을 연도, 월, 일 등으로 변한하는 메소드도 가지고 있다. 시각은 1970년 1월 1일부터 흘러온 시간으로 나타낸다.
Calendar calendar = Calendar.getInstance(); //현재 시각을 나타내는 Calendar 객체 얻는 방법
int 형의 정적 상수들이 선언되어 있고 이 상수들을 이용하여서 특정 시각에서 날짜와 시간에 대한 정보를 추출할 수 있다. 상수에 대한 정보는 아래의 사이트를 참조하면 자세히 나와있다.
https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
- StringTokenizer 클래스 : 문자열을 분석하여 토큰으로 분리시켜 주는 기능을 제공한다.
“토큰”이란 문법적으로 더 이상 나눌 수 없는 기본적인 언어요소를 의미하며, 키워드, 연산자 또는 구두점이 될 수 있다. 예를 들어 “오늘은 2017년 6월 12일입니다.”라는 문자열에서 “2017”, “6”, “12”만 따로 가져오고 싶을 때 이 클래스를 사용하면 된다.
생성자 |
StringTokenizer(String str) |
주어진 문자열을 위한 StringTokenizer 객체를 생성한다. 구분자의 디폴트 값은 공백(“ ”)이다. |
StringTokenizer(String str, String delim) |
주어진 문자열을 구분자 delim을 기준으로 분할하는 StringTokenizer 객체를 생성한다. |
|
StringTokenizer(String str, String delim, boolean returnDelims) |
returnDelims는 분리자를 포함하여 분할할 거면 true를 포함하지 않고 분할할 거면 false로 설정하면 된다. |
|
메소드 |
int countTokens() |
문자열에 존재하는 토큰의 개수를 반환한다. |
boolean hasMoreTokens() |
다음 토큰을 가지는지를 반환한다. |
|
String nextToken() |
다음 토큰을 반환한다. |
|
String nextToken(String delim) |
다음 토큰을 반환하고 분리자를 delim으로 변경한다. |
StringTokenizer 예시
import java.util.*; public class StringTest { public static void main(String[] args) { StringTokenizer st = new StringTokenizer(“I just wanna be a programmer”); while(st.hasMoreTokens()) { //공백으로 분할했을 때 토큰이 남아있다면, System.out.println(st.nextToken()); //다음 토큰을 가져온다. } } }
결과
I
just
wanna
be
a
programmer
'Programming Language > JAVA' 카테고리의 다른 글
36. Generic - 제네릭 클래스, 제네릭 프로그래밍 (9) | 2017.07.23 |
---|---|
35. Exception, try-catch-finally - 예외, 예외 처리 (0) | 2017.07.23 |
33. JTable - 테이블 (0) | 2017.07.22 |
32. JOptionPane, JDialog - 대화 상자 (0) | 2017.07.22 |
31. JMenuBar - 메뉴바 설정하기 (0) | 2017.07.13 |