패키지(package)
1. 패키지의 개념과 필요성
개발자 A,B가 있다고 가정했을 때 두 개발자 모두 Tool.class라는 자바 클래스 파일을 같은 이름으로 개발했다. 이렇게 되면 두 동일한 클래스가 한 다이렉토리 안에 있으면 파일이 중복 되는 문제가 발생한다. 따라서 서로 다른 디렉토리에 파일을 두어야 하는데 이 디렉토리를 자바에서는 패키지라 한다.
2. 자바의 모듈과 패키지, 클래스 경로명
패키지란 서로 관련 있는 클래스나 인터페이스의 컴파일된 클래스 파일들을 한 곳에 묶어 놓은 것이다. 하나의 패키지는 관련된 클래스 파일들이 들어있는 디렉터리로 보면 된다.
자바 JDK는 개발자들에게 많은 클래스들을 패키지 형태로 제공하는데, JDK 9부터는 패키지들을 모듈(module)이라는 단위로 묶어 제공한다.
클래스를 지칭할 때는 모듈명은 사용하지 않고, 패키지명을 포함하는 경로명으로 나타낸다. 예를 들어 Scanner 클래스를 표현할 때는 java.util.Scanner 과 같이 표현한다.
import와 클래스 경로
1. 패키지 사용하기, import 문
응용프로그램에서 다른 패키지에 있는 클래스를 사용하고자 한다면 패키지명을 포함하는 경로명을 사용하여 컴파일러가 클래스 파일의 위치를 정확히 찾을 수 있도록 해야한다. 만약 Scanner 클래스를 사용하기 위해서는 , 완전 경로명인 java.util.Scanner를 사용한다. 만약 그냥 Scanner만 이용한다면, 컴파일러가 Scanner 클래스가 어느 디렉터리에 있는지 찾을 수 없기 때문에 사용할 수 없다.
그러나 Scanner 클래스를 사용할 때마다 경로명을 계속 사용하면 번거롭고 코드가 길어지기 때문에 import 문을 사용하여 이런 불편함을 해소한다. import 문은 다른 패키지의 클래스를 사용할 때, 컴파일러에게 그 클래스의 경로명을 알려주는 문을 2가지 방법으로 사용할 수 있다.
- 첫째, 'import 패키지.클래스; '와 같은 형식으로 경로명을 알려줄 수 있다. import 문은 반드시 코드 앞부분에 작성되어야 한다.
- 둘째, 한 패키지에 있는 여러 클래스를 import 하고자 하는 경우, ' import 패키지.* '과 같이 사용하여 한 번에 선언할 수 있다.
패키지 만들기
1. 패키지 선언
자바 소스 파일(.java)이 컴파일되어 생기는 클새스 파일(.class)은 반드시 패키지에 소속되어야 한다. 클래스가 소속될 패키지 명은 package 키워드를 이용하여 소스 파일의 첫 줄에 선언한다.package UI public class Tool{ ... }
위와 같이 소스 코드가 실행되어 class 파일이 생성되면 UI라는 디렉터리에 Tool.class가 저장된다. 따라서 다른 패키지에 있는 클래스에서 Tool.class를 이용하고 싶다면 'import UI.Tool'을 소스 코드 맨 앞에 작성해야 한다.
2. 디폴트 패키지(default package)
만약 package 선언을 하지 않고 자바 클래스나 인터페이스를 작성하면, 자바 컴파일러는 크래스나 인터페이스를 디폴트 패키지에 소속시킨다. 디폴트 패키지는 현재 디렉터리이다.
3. 패키지 특징
- 패키지 계층 구조
클래스 파일들을 분류하여 패키지 계층 구조로 만들면 찾기도 쉽고 관리하기도 쉬워진다. 상속 관계에 있는 클래스나 인터페이스의 경우, 서브 클래스 파일을 슈퍼 클래스 파일이 저장된 패키지의 서브 디렉터리에 패키지를 만들어 저장하여 계층화시키면 더욱 관리하기 쉽다.- 패키지별 접근 제한
디폴트 접근 지정으로 선언된 클래스나 멤버는 동일 패키지 내의 클래스들이 자유롭게 접근하도록 허용한다. 패키지에 포함된 클래스들끼리는 자유롭게 접근하고, 다른 패키지의 클래스들은 접근을 막음으로써 패키지를 접근 권한의 범위로도 이용할 수있다.- 동일한 이름의 클래스를 다른 패키지에 작성 가능
같은 패키지 내에서는 동일한 이름을 가진 클래스나 인터페이스가 존재할 수 없다. 그러나 다른 패키지에 있으면 클래스 이름이 패키지명을 포함한 전체 경로명을 사용하기 때문에 가능하다.- 소프트웨어의 높은 재사용성
클래스와 인터페이스를 잘 분류하여 패키지로 관리하면, 나중에 같거나 유사한 기능을 수행하는 클래스나 인터페이스는 재작성할 필요 없이 프로그램에 포함하여 쉽게 사용할 수 있다.
모듈 개념
1. 모듈(module)
모듈은 패키지들을 담는 컨테이너로 모듈 파일(.jmod)로 저장한다. 모듈에는 패키지 뿐만 아니라 다른 이미지, 파일 등의 리소스들도 포함되어 있다.
2. 자바 플랫폼의 모듈화
자바 플랫폼이란 자바 프로그램의 개발 환경과 실행 환경을 함께 지칭하는 것으로 JDK/JRE 형태로 자바 개발자에게 제공된다. 오라클은 자바 API(사용자에게 제공하는 많은 클래스 라이브러리)를 모듈화하여, 패키지의 계층 구조로만 되어 있든 클래스들을 수십 개의 작은 모듈들로 재구성하였다. 모듈들은 개발자가 다운받은 JDK 안의 jmods 디렉터리에 들어 있다. jmods안에 있는 모듈 중 java.base.jmod는 io, util, lang, math의 패키지가 들어 있다.
3. 모듈 기반의 자바 실행 환경
자바 실행 환경(java run time enviroment)이란 자바 응용프로그램이 실행되는데 필요한 제반 환경으로서, 응용프로그램이 실행 중에 사용하는 자바 API 클래스와 자바 가상 기계 등으로 이루어진다. Java 9 이전까지는 자바 API의 모든 클래스들을 rt.jar이라는 하나의 단일체(monolithic)로 구성되었고, 자바 가상 기계는 응용프로그램 실행 도중, 필요한 클래스 파일을 rt.jar에서 풀어 메모리에 로딩하고 실행하였다. 따라서 자바 응용프로그램이 일부 클래스만 이용하더라도 rt.jar 전체가 설치되는 구조였다. 그러나 Java 9 이후 자바 API를 많은 수의 모듈로 분할하여 자바 응용프로그램을 컴파일 할 때 실행에 필요한 모듈들만으로 조립하여 구성하도록하였다. Java 9이상에서는 module(109MB 크기 정도)라는 비공개 파일을 가지고, JVM이 자바 응용프로그램을 실행할 때, 여기서 필요한 모듈을 끌어내어 실행 환경을 만든다. 또 하나의 방법으로는 jlink 프로그램을 이용하여 실행에 필요한 모듈만 묶어 커스텀 모듈을 만들어 사용한다(커스텀 JRE).
4. 자바 모듈화의 목적
자바 모듈화는 여러 목적이 있지만, 자바 컴포넌트들을 필요에 따라 조립하여 사용하기 위함이다. 세밀한 모듈화를 통해, 필요없는 모듈이 로드되지 않게 하여, 컴퓨터 시스템에 불필요한 부담을 줄인다. 특히 하드웨어가 열악한 소형 IoT 장치에서도 자바 응용프로그램이 실행되고 성능을 유지한다.
자바 JDK에서 제공하는 패키지
자바를 설치하면 자바 개발 도구인 JDK(java Development Kit)가 설치되며 이곳에는 개발자들이 사용할 수 있는 많은 클래스들이 패키지에 담기고 다시 모듈에 담겨 제공된다. 자바에서 제공하는 이 기본 클래스들을 자바 API라고 한다. 이러한 자바 API가 없으면 개발자가 화면 출력, 키 입력, 네트워킹 등 모든 기능을 직접 구현해야 한다. JDK의 표준 패키지는 모듈로 나누어져 JDK를 설치한 디렉터리 밑의 jmods 디렉터리에 담겨 있다.
주요 패키지
- java.lang : 이 패키지에는 System을 비롯하여, 문자열, 수학 함수, 입출력 등과 같이 자바 프로그래밍에 필요한 기본적인 클래스와 인터페이스를 제공한다. 이 패키지의 클래스들은 특별히 import 문을 사용하지 않아도 자동 임포트된다.
- java.util : 날짜, 시간, 벡터, 해시맵 등 다양한 유틸리티 클래스와 인터페이스를 제공한다.
- java.io : 키보드, 모니터, 프린터, 파일 등에 입출력 하는 클래스와 인터페이스를 제공한다.
- java.awt와 javax.swing : 자바 AWT(Abstract Windowing Toolkit)과 swing 패키지로서 GUI 프로그래밍에 필요한 클래스와 인터페이스를 제공한다.
자바 API에 대한 정보는 여기서 얻을 수 있다.
Object 클래스
Object는 java.lang 패키지에 속한 클래스이며, 모든 클래스에 강제로 상속된다. Object만이 아무 클래스도 상속받지 않는 유일한 클래스로 계층 구조 상위 클래스이다. 따라서 Object 클래스에는 모든 클래스에서 상속받아 사용할 공통 기능이 구현되어 있다.
1. 객체 속성
Object는 모든 객체에게 공통적으로 있어야 할 메소드를 포함한다. Class 클래스는 주어진 객체의 클래스에 관한 정보를 담는 클래스이다. Object의 getClass() 메소드를 호출하면 바로 이 Class 객체를 리턴하는데, 객체의 getName() 메소드를 이용하면 obj 레퍼런스가 가리키는 객체의 클래스 타입을 알아 낼수 있다. hashCode() 메소드는 객체가 생성될 때 객체를 유일하게 구분할 수 있는 정수 id값(해쉬코드)를 알아내는 메소드이다.
2. 객체를 문자열로 변환, toString() 메소드
객체를 문자열로 변환하는 메소드가 Object의 toString()이다. toString() 메소드는 객체의 클래스의 이름을 얻어와서 '@'를 연결하고 다시 객체의 해시코드 값을 16진수로 변환하여 연결한 문자열을 리턴한다.Point a = new Point(2,3); System.out.print(a.toString()); //결과 : Point@15db9742(클래스 이름 @ 해시코드 16진수)
또한 '객체 + 문자열 ' 연산이나 객체를 출력하는 경우, toString()이 자동으로 호출된다. 뿐만 아니라 개발자는 필요시 Object의toString() 메소드를 오버라이딩하여 자신만의 문자열을 리턴할 수 있다.
3. 객체 비교와 equals() 메소드
기본 타입의 값을 비교하기 위해서는 == 연산자를 사용하지만, 객체를 비교를 위해서는 반드시 equals() 메소드를 사용해야한다.
- == 연산자
객체 비교에 ==연산자를 사용하면 두 객체의 내뇽물이 같은지 비교하는 것이 아니라, 두 레퍼런스가 같은지, 즉 두 레퍼런스가 동일한 객체를 가리키는지 비교한다.- boolean equals(Object obj)
Object의 equals(Object obj)는 인자로 건네진 객체 obj와 자기 자신을 비교하여 두 객체의 내용이 같은지를 비교하는 메소드이다. 사실, 내용의 동일성은 전적으로 클래스 작성자가 정의할 문제이기 때문에, 클래스 작성자가 클래스에 equals() 메소드를 오버라이딩 하는 것이 원칙이다.(나는 주로 String 비교할 때 많이 사용했던 것 같다..)
Wrapper 클래스
이름이 Wrapper인 클래스는 존재하지 않지만, int, char, double 등 8개의 기본 타입을 객체로 다루기 위해 JDK에 만들어진 8개의 클래스를 통칭하여 Wrapper 클래스라 한다. Byte, Short, Integer, Long, Character, Double, Float, Boolean 클래스가 기본 타입에 해당되는 값을 객체로 다룰 수 있는 하는 Wrapper 클래스이다. 자바는 객체 지향 언어이므로 객체를 대상으로 처리하는 경우가 많은데 Wrapper 클래스를 이용하여 기본타입을 객체로 만들어 사용함으로써 기본 타입을 사용하여 객체를 다룰 수 있게 되었다.
- Wrapper 클래스의 객체 생성
Wrapper 객체는 기본 타입의 값을 인자로하여 정적 메소드인 valueOf()를 호출하여 생성한다.Integer i = Integer.valueOf(10); Character c = Character.valueOf('c');
Wrapper 객체를 생성할 때 생성자를 이용하는 방법(new Integer(10)) 과 같은 방법은 쓰지 않는다.
- Wrapper 클래스의 활용
Wrapper 클래스는 많은 메소드를 제공하나, 대부분은 기본 타입 값을 문자열로 변환하거나, 문자열을 기본 타입 값으로 변환한는 것들이 주를 이루고 있다.
※ Wrapper 객체에 들어 있는 기본 타입 값 알아내기
Wrapper 객체에 들어 있는 기본 타입의 값을 알아내기 위해 intValue, doubleValue, .. 기본 타입Value()를 사용한다.
※ 문자열을 기본 타입으로 변환
Wrapper 클래스는 문자열을 기본 타입으로 변환하는 메소드를 제공한다. ex) parseInt(), parseDouble(), parseBoolean()
이 메소드 모두 static 타입이므로 Wrapper 클래스의 이름으로 바로 메소드 호출한다.
※ 기본 타입 값을 문자열로 변환
Wrapper 클래스는 기본 타입 값을 문자열로 변환하는 메소들르 제공한다.String s1 = Integer.toString(123); // 정수 123을 문자열 "123"으로 변환 String s2 = Integer.toHexString(123); // 정수 123을 16진수의 문자열 "7b"로 변환 ...
- 박싱(boxing)과 언박싱(unboxing)
기본 타입을 Wrapper 객체로 변환하는 것을 박싱이라 하고, 반대의 경우를 언박싱이라 한다.Integer ten = Integer.valueOf(10); // 박싱 int n = ten.intValue(): // 언박싱
박싱과 언박싱은 JDK1.5부터 자동으로 이루어지며, 이를 자동 박싱(auto boxing), 자동 언박싱(auto unboxing)이라 한다.
Integer ten = 10; // 자동 박싱 int n = ten; // 자동 언박싱
String 클래스
- String의 특징과 객체 생성
java.lang 패키지에 포함된 클래스로서 String 클래스는 문자열을 나타낸다. 스트링리터널("")은 자바 컴파일러에 의해 모두 String 객체로 처리된다.
※ 스트링 리터널과 new String()
스트링 리터럴과 new String()으로 생성된 스트링 객체는 서로 다르게 관리된다. 스트링 리터럴은 자바 내부에서 리터럴 테이블로 특별히 관리하여, 동일한 리터럴을 공유시킨다. new String()으로 생성된 스트링은 new를 이용하여 생성되는 다른 객체와 동일하게 힙 메모리에 생성된다. 만약 리터럴로 생성된 객체가 동일한 레퍼런스를 가리키면 같은 레퍼런스를 공유한다. 그러나 new로 생성된것은 힙 메모리에서 관리되어 독립적으로 생성된다.
※ 스트링 객체는 수정이 불가능하다.
릴터럴이든 new String()으로 생성했던, 일단 생성된 스트링 객체는 수정이 불가능하다. concat() 메소드로 두 스트링 객체를 이어붙여 새로운 객체를 생성할 수는 있지만, 기존의 객체는 수정이 되지 않는다.- String 활용
※ 문자열 비교 : int compareTo(String anotherString)
compareTo() 메소드는 현재 스트링과 매개변수로 주어진 anotherString의 스트링을 사전 순으로 비교하여, 두 문자열이 같으면 0, 현재 문자열이 사전에서 먼저 나오면 음수를, 뒤에 나요면 양수를 리턴한다.
※ 문자열 연결 : String concat(String str)
자바에서는 + 연산자로 문자열을 연결할 수 있다. + 연산은 피연산자에 문자열이 하나라도 있으면 문자열 연결로 처리한다. String 클래스의 concat() 메소드를 이용해도 문자열을 연결할 수도 있다.
※ 공백 제거: String trim()
trim()은 문자열 앞뒤에 있는 공백 문자를 제거한 새로운 문자열을 리턴한다. (\t 도 제거된다.)
※ 문자열의 문자 : char charAt(int index)
charAt() 메소드를 이용하면 특정 위치에 있는 문자를 알아낼 수 있다.
※ 이 외의 메소드
split() : 문자열을 분리하여 배열에 저장한 후 배열 리턴
replace : 문자열을 대치(바꿔준다)시킨다.
substring() : 인덱스를 지정해주면 그 인덱스부터 끝까지 서브 스트링을 리턴
StringBuffer 클래스
- StringBuffer의 생성과 특징
StringBuffer 클래스도 java.lang 패키지에 포함되어 있으며, String 클래스와 같이 문자열을 다룬다. String 객체의 경우 내부의 문자열을 수정할 수 없지만, StringBuffer 객체는 문자열을 저장하는 가변 버퍼를 가지고 있기 때문에 저장된 문자열의 수정이 가능하다. 문자열의 크기가 늘어나면 내부 버퍼 크기를 자동 조절한다.
- StringBuffer 활용
간단한 문자열을 처리하는 것은 String 클래스를 이용하고, 문자열의 길이가 길거나 문자열이 수시로 변하는 경우 StringBuffer 클래스를 이용하는 것이 바람직하다.
StringTokenizer 클래스
- StringTokenizer의 생성과 특징
StringTokenizer 클래스는 java.util 패키지에 포함되어 있으며, 하나의 문자열을 여러 개의 문자열로 분리하기 위해 사용된다. 문자열을 분리할 때 사용되는 기준 문자를 구분문자(delimiter)라고 하고, 구분 문자로 분리된 문자열을 토큰(token)이라고 한다. 오라클에서는 StringTokenizer보다 String의 split 메소드를 이용하라고 권장한다.
StringTokenizer 클래스의 생성자를 통해 문자열이 전달되며, 생서자에서 문자열 분리가 바로 이루어진다.
Math 클래스
- Math의 특징
Math 클래스는 java.lang 패키지에 포함되어 있으며 기본적인 산술 연산을 제공한다. 모든 멤버 메소드는 static 타입이므로 바로 클래스 타입으로 바로 사용하면 된다.
- Math 클래스를 활용한 난수 발생
Math 클래스에서 가장 많이 사용하는 메소드는 난수를 발생하는 random()이다. 이 메소드는 0.0보다 크고 1.0보다 작은 임의의 double 값을 리턴한다. 다음은 1부터 100까지 난수를 리턴하는 과정이다.int n = (int)(Math.random()*100+1); //100을 곱한뒤 1을 더한 후 int 타입으로 강제 변환시켜 1~100을 표현한다.
java.util.Random 클래스를 이용하여 난수를 발생시킬 수 있다.
Random r = new Random(); int n = r.nextInt(); // 음수, 양수, 0 을 포함하여 자바 정수 범위의 난수 발생 int m = r.nextInt(100); // 0~99(0과 99포함)사이의 정수 난수 발생
Calendar 클래스
- Calendar 클래스의 특징
Calendar 클래스는 java.util 패키지에 있는 추상 클래스로서 년, 월, 일, 요일, 시간, 분, 초, 밀리초까지 프로그램이 실행되는 동안 개발자가 기억하고자 하는 시간과 날짜 정보를 저장하고, 필드를 인자로 하여 set(), get() 메소드를 이용하여 날짜나 시간을 알아내거나 설정한다. 주의할 점은 Calendar로 컴퓨터의 현재 시간을 알아낼 수는 있지만, Calendar 객체에 날짜와 시간을 설정한다고 해서 현재 컴퓨터의 시간을 바꾸지는 못한다.
위의 표는 set(), get() 메소드를 이용할 때 사용할 필드이다.- Calendar 객체 생성 - 현재 날짜와 시간
Calendar 클래스는 추상 클래스이므로, new Calendar()를 사용하지 않고 getInstance() 메소드를 통해 Calendar 객체를 생성한다.Calendar now = Calendar.getInstance();
getInstance()가 리턴한 now 객체는 현재 날짜와 정보를 가진다.
- 날짜와 시간 알아내기
Calendar 객체에서 날짜와 시간을 알아내기 위해서는 get() 메소드에 위 표의 필드를 이용한다.int year = now.get(Calendar.YEAR); int month = now.get(Calendar.MONTH)+1; //1월이면 0을 리턴하여 1을 더한다.
get(Calendar.MONTH)는 1월 달이면 0을 리턴하기 때문에 month에다 1을 더한다.
- 날짜와 시간 설정하기
set() 메소드는 Calendar 객체에 날짜와 시간을 설정하는 메소드이다.Calendar firstDate = Calendar.getInstance(); firstDate.clear(); // 현재 날짜와 시간 정보를 지운다. firstDate.set(2022,0,1); // 2022년 1월 1일 월은 1을 빼야지 정하고자 하는 월이 설정됨 firstDate.set(Calendar.HOUR_OF_DAY, 20); // 저녁 8시로 설정 firstDate.set(Calendar.MINUTE, 30); //30분으로 설정