JANGUN


JAVA 프로그래밍


지음 : 김희천



목차

제 1 장 Java 언어 소개
제 2 장 Java 기본 문법
제 3 장 객체지향 프로그래밍
제 4 장 패키지와 예외처리
제 5 장 java.lang 패키지
제 6 장 멀티 스레드 프로그래밍
제 7 장 java.io 패키지와 스트림
제 8 장 AWT 개요 및 Container 클래스와 배치 관리자
제 9 장 AWT 컨트롤 클래스와 이벤트 처리하기
제 10 장 Applet 프로그래밍
제 11 장 JavaFX
제 12 장 JDBC 프로그래밍
제 13 장 네트워크 프로그래밍
제 14 장 제네릭과 람다식
제 15 장 java.nio 패키지의 활용
제 16 장 컬렉션


제 1 장 Java 언어 소개

∙ Java 언어의 기원
- Sun Microsystems의 제임스 고슬링
- 1990년 그린 프로젝트와 Oak 언어
- 1995년 Java와 HotJava 발표
- 1996년 1월 JDK 1.0 발표 (2014년 JDK 8 )
- 2009년 Oracle이 Sun을 인수함

∙ Java 언어의 특징 : Java 는 고수준의 프로그래밍 언어로 다음과 같은 특징을 가진다.
1. 단순함 : C/C++언어와 유사
2. 완전한 객체지향 언어
3. 분산처리 기능 : 웹 또는 네트워크 프로그래밍이 용이
4. 멀티 스레드
5. 동적 실행
6. 아키텍쳐 중립적 : 플랫폼에 독립적
7. 이식성
8. 강건함
9. 보안성
10. 엄격한 자료형의 검사
11. 예외 처리 기능 제공

∙ Java 프로그램의 실행

- 바이트 코드 : Java 소스를 컴파이한 결과물 (*.class), 클래스파일이라고도 함, Java VM에서 실행 가능한 코드

∙ Java 플랫폼
- Java 플랫폼은 다른 플랫폼과 다르게 소프트웨어 플랫폼을 말하며 여러 다른 하드웨어에 설치될 수 있다.
- Java 플랫폼은 Java VM 과 Java API 로 구성된다.
- Java VM 은 Java 프로그램의 실행 환경을 제공하는 가상의 기계로 Java 프로그래미의 구동 엔진. Java 플랫폼의 기초가 되며 여러 하드웨어 플랫폼에 설치될 수 있다.
- Java API 는 프로그램에 사용되도록 이미 만들어져 제공되는 것으로 유용한 기능을 제공하는 소프트웨어 컴포넌트들이다. 프로그램의 개발에 필요한 클래스 라이브러리 패키지들이 계층 구조로 분류되어 있음
- 플랫폼 독립적인 바이트코드는 컴퓨터상에서 직접 수행될 수 있는 네이티브 코드보다 느릴 수 있으나 컴파일러와 가상기계의 발전을 통해 성능을 유사한 수준으로 높일 수 있다. 예를 들어 반복적으로 자주 사용되는 부분을 네이티브 코드로 작성해 주는 가상기계가 존재한다.


∙ Java VM
- Java 프로그램을 실행시켜 주는 가상의 기계로 ‘구동 엔진’ 또는 ‘실행 환경’으로 볼 수 있다.
- new 연산자에 의해 할당되었던 메모리를 자동으로 수집해 주는 가비지 컬렉션을 수행한다.
∙ Java API
- Java API 는 관련이 있는 클래스와 인터페이스들을 묶은 패키지들로 구성된다.
- 패키지들은 계층 구조로 분류되며 상위 패키지와 하위 패키지를 구분하기 위해 ‘.표기법’을 사용한다.
- 패키지 java.lang 은 최상위 패키지 java 에 포함되어 있는 서브 패키지 lang 을 의미한다.

∙ Java 프로그램 설치
- JDK 설치 (http://www.oracle.com/) 및 환경 변수 (PATH 수정, JAVA_HOME 생성)
- Eclipse 설치 (http://www.eclipse.org/)


제 2 장 Java 기본 문법

∙ 주석
- 프로그램의 이해를 위한 설명문이다.
- 한 줄짜리 주석은 //로 시작하며 그 뒤의 내용은 실행과 무관하다.
- 여러 줄의 주석은 /*와 */ 사이에 그 내용을 삽입한다.

∙ 식별자
- 클래스, 변수 및 메소드의 이름으로 프로그래머가 만든 단어이다.
- 다음과 같은 규칙을 지켜야 한다.
가. 대소문자가 구분된다.
나. 길이에 제한이 없다.
다. 영문 대소문자, 한글, 숫자, 언더스코어(_), 달러($) 문자 등으로 구성되나, 시작 문자는 숫자가 될 수 없다.
라. public, class, while 과 같은 키워드와 true, false, null 과 같은 리터럴을 식별자로 사용할 수 없다.
마. 관습상 한 단어의 식별자(변수와 메소드)는 모두 소문자로 만들며, 두 단어 이상으로 된 식별자의 경우에는 두 번째 단어부터 단어의 시작 문자를 대문자로 만든다. 예를 들면 myCar 와 같다.
바. 관습상 클래스 이름의 경우에 첫 문자를 대문자로 한다.
사. 관습상 상수에 해당하는 식별자는 모두 대문자로 만들며 단어의 구분을 위해 언더스코어(_)를 사용한다. 예를 들면 NUM_GEARS 와 같다.

∙ 키워드
- 의미가 미리 정해진 단어
- 프로그램에서 정해진 의미로만 사용해야 함


∙ 변수와 자료형
- 변수를 선언할 때, 저장되는 값의 자료형을 선언
- 메소드를 선언할 때, 반환 값의 자료형을 선언
- 자료형에 따라 적용 가능한 연산이 다른다.

∙ 기본형과 참조형
- 변수는 값을 저장하기 위한 기억 공간을 할당받는다.
- 기본형 변수에는 자료형의 값을 저장한다.
- 참조형 변수에는 객체가 위치해 있는 주소 값을 저장한다.
- 참조형 변수를 사용하려면 실제 데이터 값을 보관하기 위한 메모리 공간을 생성한 후 사용해야 한다.

∙ Java 의 기본형 자료형


∙ 정수형
- byte, short, int, long 의 네 종류가 있다.
- L 이나 l 로 끝나는 정수형 리터럴은 long 형이며 나머지는 int 형이다.
- 정수형 리터럴의 경우 0 으로 시작하면 8 진수, 0x 로 시작하면 16 진수를 의미하고, 0b 로 시작하면 2 진수이다.

∙ 문자형
- 2 바이트 길이의 유니코드를 사용한다.
- 문자 리터럴을 표현할 때는 단일 따옴표를 사용한다.
- 유니코드를 이용하여 문자 리터럴을 표현할 수 있다. 이때 \u 다음에 4 개의 16 진수를 사용하는데 ‘\uxxxx’와 같이 표현한다. 예) char c = ‘\u0108’; // 유니코드 문자 Ĉ 를 표현한다.
- 부호 없는 정수와 호환된다. 예) char c = ‘\u0041’; // ‘A’를 대입하는 것과 같다.
System.out.println(‘A’+1); // ‘A’+1 의 출력 결과는 66 이다.
System.out.println((char)65); // (char)65 의 출력 결과는 ‘A’이다.

∙ 실수형
- float 와 double 이 있다.
- F 나 f 로 끝나는 실수형 리터럴은 float 형이며 나머지는 모두 double 형이다.
예 double d1 = 123.4;
double d2 = 1.234e2; // d1 과 같으면 e 는 10 의 거듭제곱을 표현한다.
float f1 = 123.4f;

∙ 참조형
- 기본형을 제외한 모든 자료형 (참조 값(주소)을 가지는 자료형
- 배열, 클래스 형 등
- 참조형 변수는 저장 공간에 참조 값을 저장함, 실제 데이터는 별도의 공간에 저장됨
- 기본형 변수는 저장 공간에 값 자체를 저장함

∙ 묵시적 자료형의 변환
- 작은 타입에서 큰 타입으로는 자동으로 또는 묵시적인 형변환이 일어난다.
예) double d = 5; // int 값 5 가 double 값 5.0 으로 형변환된 후 변수에 저장된다.
예) System.out.println(“j=”+10); //int 값 10 이 String 값 “10”으로 형변환된 후 앞의 “j=”와 합쳐져 “j=10”이 출력된다.

∙ 명시적 자료형의 변환
- 큰 타입에서 작은 타입으로 변환할 때는 명시적인 형변환을 해야 한다. float f = 5.5 //5.5 는 double 값이며 floa 형 변수에 저장될 수 없으므로 오류이다.
예 float f = (float)5.5 //명시적 형변환에 의해 5.5 가 float 값으로 변환된 후 저장된다.

∙ Java 언어와 변수
- 변수로는 다음의 네 종류가 존재한다.
가. 인스탄스 변수(정적이 아닌 필드) : 클래스 정의에 포함된 정적이 아닌 필드이다. 객체는 이러한 정적이 아닌 필드를 소유하게 된다. 이러한 필드(또는 변수)는 개별 객체의 고유 상태를 저장하기 위한 것이다.
나. 클래스 변수(정적 필드) : 클래스 정의에 포함된 것으로 static 으로 선언된 정적 필드이다. 클래스의 객체가 여럿 만들어진다 해도 정적인 필드는 클래스에 하나만 존재하며 객체들 사이에서 공유되는 변수가 된다.
다. 지역 변수 : 메소드 정의에 포함되어 메소드 내부에서 사용되는 임시 변수이다. 이것은 메소드 실행이 시작될 때 만들어지고 메소드 종료와 함께 사라지는 변수이다.
라. 파라미터 : 메소드 호출시 넘겨지는 값을 저장하기 위한 변수이다. 특별한 지역 변수라고 할 수 있다.

- 일반적으로 필드라 함은 인스탄스 변수 또는 클래스 변수를 말하며 멤버 변수라고도 부른다.
- 변수를 선언할 때 초기화하는 것이 좋다.
- 클래스 안에 선언된 필드의 경우에는 선언과 동시에 초기값을 주지 않더라도 다음과 같이 자동으로 초기화된다. (boolean-false, char-\u0000, int-0, double-0.0, object-null, array-null, String-null)
- 지역 변수의 경우는 자동으로 초기값이 주어지지 않는다. 따라서 지역 변수를 사용하기 전에 반드시 값을 지정할 필요가 있다.

∙ 상수의 선언
- 상수는 값이 초기화된 후 변하지 않는 변수이다.
- 키워드 final 을 사용하여 변수를 선언하면 상수가 된다.
예 final int cConst = 3;
예 final int MAX_SCORE = 100; // 상수의 이름으로 대문자를 사용하는 경우가 많다.

∙ 명령행 인자 사용하기
- 프로그램을 실행시킬 때 프로그램 이름 뒤에 나열되는 단어들이 main 함수의 인자가 된다.
- >java CommandInputTest Kim 123 // main(String args[]) – args[0] (“Kim”) , args[1] (“123”)

∙ 연산자의 종류


∙ 문장의 종류
- 수식문
- 변수 선언문
- 제어문 : 실행 흐름을 바꾸는 문장
- 기타 : 블록문, 레이블문, 예외처리문, 동기화문

∙ 제어문의 종류
- 선택문 : 조건에 따른 문장의 선택 (if, switch)
- 반복문 : 조건에 따른 문장의 반복 (for, while, do-while)
- 점프문 : 분기문 (return, break, continue)

∙ for-each 반복문
- 배열과 List 나 Set 과 같은 컬렉션에 속하는 원소를 처리할 때, 간단하고 읽기 쉽게 for 문을 작성할 수 있다.
- 형식은 for ( 변수선언 : 배열 ) { 문장 …}

∙ 배열
- 배열은 같은 자료형의 값을 정해진 개수만큼 가지고 있는 객체이다.
- 배열의 길이는 배열이 생성될 때 정해지며 그 길이는 바뀌지 않는다.
- 배열에 포함되어 있는 하나의 항목을 원소라고 한다.
- 숫자 인덱스를 사용하여 배열에 포함된 특정 원소를 다룰 수 있다.
- 배열 객체는 배열의 길이를 가지는 내장 속성 length 를 가지고 있으므로 ‘배열이름.length’를 사용할 수 있다.

∙ 배열의 선언과 생성
- 배열을 선언할 때 대괄호를 사용하다.
예) int[] anArray; // 좋은 표현 int anArray[]; // 올바른 표현이나 권장되지 않는다.
- 배열을 선언할 때 크기를 지정할 수 없다.
- 배열의 원소를 다루기 위해서는 배열 선언 후에 생성 과정을 거쳐야만 한다.
- 배열의 생성은 배열의 크기를 정하고 각 원소에 메모리를 할당하는 것이다.
- new 연산자 : 배열의 크기를 정하고 메모리 공간 확보, 메모리의 주소값을 리턴, 원소가 숫자인 경우 0, 참조형인 경우 null로 자동 초기화
예) int[] anArray; // 배열의 선언
예) anArray = new int[10]; // 배열의 생성
예) int[] anArray = new int[10]; // 배열의 선언과 생성
- 배열의 초기화는 배열의 선언과 생성을 동시에 하는 방법으로 초기값을 지정한다.
예 int[] anArray = {100, 200, 300, 400, 500, 600, 700, 800, 900, 1000}
- 2 차원 배열을 선언하기 위해서는 두 개의 대괄호를 사용한다.
- 2 차원 배열은 배열을 원소로 가지는 배열을 의미하며 각 원소는 크기가 다른 배열이 될 수 있다.

∙ 문자열 - 문자열을 표현하는 자료형으로 String 클래스가 존재한다.
- 문자열 리터럴을 표현하기 위해 이중 따옴표를 사용한다.
- String 형 변수는 참조형이나 기본형처럼 다룰 수 있다.
예 String s1 = “Java”;
String s2; s2 = “Java Application”;
String s3 = new String(“Java Applet”);
∙ 문자열의 + 연산자
- ‘문자열+문자열’은 두 문자열을 연결하는 수식이다.
- ‘문자열+다른 유형’은 다른 유형을 문자열로 형변환한 후 두 문자열을 연결한다.
예) System.out.print(“결과=”+1+1); // “결과=”+1 은 “결과=1”이며 “결과=1”+1 은 “결과=11”이다.
예) System.out.print(1+1+“이다”); // 1+1 은 2 이며 2+“이다”는 “2 이다”이다.

∙ Scanner 클래스
- 키보드나 파일로부터 다양한 자료를 입력 받을 때 사용
- 기본적으로 공백 문자로 구분되는 단어 단위로 입력됨
- System.in은 키보드 입력을 위한 객체
예) Scanner sc = new Scanner (System.in);
String name = sc.next(); // next() ; Finds and returns the next complete token from this scanner
- Scanner의 입력용 메소드 : boolean hasNext(), String next(), boolean hasNextInt(), int nextInt(), boolean hasNextDouble(), double nextDouble(), boolean hasNextLint(), String nextLine();


제 3 장 객체지향 프로그래밍

∙ 추상화
- 사물을 표현할 때 복잡하고 구체적인 모든 사실이 아니라 전형적이고 필요한 부분만을 가지고표현하는 것이다.
- 실세계의 사물이나 개념을 Java 프로그램에서 추상화하여 표현할 때 클래스를 사용한다.
- 클래스에서는 표현 대상의 상태를 나타내기 위해 필드를 포함하고 상태 제어를 위한 메소드를 함께 포함한다.

∙ 객체와 클래스
- 클래스는 객체를 만들기 위한 모형 또는 틀이다.
- 하나의 특정 클래스를 통해 만들어진 모든 객체들은 같은 종류에 포함된다고 할 수 있다.
- 공통적인 특징을 가지는 객체들을 추상화하기 위한 수단
- 객체의 상태는 필드(데이터)로, 행위는 메소드로 구현됨
- 객체는 특정 클래스의 인스탄스이다.
- 객체는 유일하게 식별되는 존재이며 어떠한 두 객체도 완전히 동일할 수는 없다.
- 예를 들어 붕어빵을 만들기 위한 틀은 클래스에 해당하고 그 틀을 통해 만들어진 붕어빵은 객체이다.

∙ 클래스 정의
- 클래스를 정의할 때, 개별 객체의 상태 정보를 저장하는 필드와 개별 객체의 행동 양식을 규정하는 메소드를 포함할 수 있다.
- 클래스는 생성자를 포함할 수 있으며, 생성자는 메소드의 특별한 경우로 볼 수 있다.
- 필드를 멤버 변수라고 부르고, 메소드를 멤버 메소드라고 부르기도 한다.
- 클래스 정의를 위한 문법은 다음과 같다. 대괄호 부분은 선택 사항으로 생략가능하다.

- 클래스의 정의는 데이터 필드와 메소드를 정의하는 것이다.
- 메소드는 저장된 데이터를 이용해 기능을 수행한다.
- 객체의 상태는 데이터 필드로, 행위는 메소드로 구현된다.
- 키워드 extends 다음에는 슈퍼 클래스의 이름이 나온다. Java 언어에서는 클래스의 다중 상속을 허용하지 않으므로 하나의 슈퍼 클래스만을 이용할 수 있다.
- 키워드 implements 다음에는 인터페이스의 이름이 나온다. 인터페이스는 다중 상속이 가능하므로 콤마 ‘,’로 구분하여 인터페이스의 이름을 나열할 수 있다.
- 클래스는 객체의 자료형

∙ Java 프로그래밍
- 클래스가 프로그램 구성의 기본 단위
- 데이터(필드)와 알고리즘(메소드)이 클래스에 캡슐화되어 있음
- 객체가 만들어지고 객체들 간의 상호작용이 프로그램이 동작함

∙ 클래스의 접근 제어자
- 정의된 클래스를 사용할 수 있는 범위를 제어하기 위한 키워드로 public, 생략, protected, private 이 존재한다.
- 클래스의 접근 제어자는 클래스의 가시성을 나타낸다.
- 접근성을 의미하는 것은 아니나 final, abstract 키워드가 class 키워드 왼편에 나올 수 있다.
- public 클래스는 어디서나 사용 가능한 클래스를 의미한다.
- 접근 제어자가 생략된 경우를 ‘패키지 접근 수준’이라 하는데 같은 패키지에서 사용할 수 있는 클래스를 의미한다.
- protected 클래스와 private 클래스는 다른 클래스의 내부에 위치하는 클래스를 정의하는 경우에만 가능하다. 클래스 정의가 다른 클래스의 내부에 위치하는 경우 이 클래스를 내부(nested) 클래스라 하고, 그렇지 않은 경우 톱레벨 클래스라고 한다.
- 톱레벨 클래스의 접근 제어자는 public 과 생략만 가능하다.

∙ final 클래스와 abstract 클래스
- final 과 abstract 키워드는 클래스의 접근 범위를 의미하는 것은 아니나 교재에서는 접근 제어자의 하나로 다루었다.
- final 클래스는 상속될 수 없는 클래스를 정의하기 위한 것이다. 즉 final 클래스는 다른 클래스의 슈퍼 클래스가 될 수 없다.
- abstract 클래스는 객체를 생성시킬 수 없는 클래스로 상속되어 사용되는 클래스이다.
- 형식만 정의되고 몸체가 정의되지 않은 메소드를 추상 메소드라 하며, 추상 메소드를 포함하는 클래스는 반드시 abstract 클래스이어야 한다.
- final 이면서 abstract 인 클래스는 의미적으로 모순이므로 존재할 수 없다.

∙ 생성자
- 객체를 생성하기 위해 클래스에 생성자를 정의할 필요가 있다.
- 객체를 생성할 때 생성자가 자동으로 호출되며 일반 메소드처럼 임의로 호출할 수 없다.
- 생성자의 기능은 객체가 가지는 필드들의 값을 초기화하는 것이다.
- 생성자의 이름은 클래스의 이름과 같아야 하며 리턴 타입(반환형)을 명시해서는 안된다.
- 인자가 없는 생성자를 기본(default) 생성자라 한다.
- 클래스 정의에서 어떠한 생성자도 정의하지 않았다면, 컴파일러는 기본 생성자를 자동으로 만들어 준다.
- 슈퍼 클래스를 상속받아 클래스를 정의한 경우, 생성자가 실행될 때 슈퍼 클래스의 인자 없는 생성자가 자동으로 호출된다.
- 클래스에 여러 생성자가 정의될 수 있으며 인자에 의해 구분되어야 한다.
- 일반적으로 생성자의 접근 제어자는 public 이다.
예) Circle c = new Circle(5); // new 연산자를 이용하여 객체를 생성(메모리 할당)하고 생성자가 호출(데이터 초기화)되면서 객체의 참조값을 변수에 대입

∙ 클래스의 사용과 객체의 생성
- 클래스 유형은 참조형이다.
- 참조형 변수를 사용하려면 실제 데이터 값을 보관하기 위한 메모리 공간을 생성한 후 사용해야 한다.
- 객체가 사용할 메모리 공간을 할당하고 초기값을 지정하는 것을 객체 생성이라고 하며 이때 상응하는 생성자가 호출된다.

∙ 데이터 필드의 접근 제어자
- 필드의 접근 제어자는 객체가 가지고 있는 필드의 사용 범위를 제어하기 위한 것이다. (정보은닉)
- Circle 유형의 객체 c 가 존재하고 c 가 r 이란 이름의 필드를 가질 때, c.r 을 사용할 수 있는 범위를 뜻한다.
- 필드의 접근 제어자로는 public, protected, 생략 및 private 가 있다.
- public 필드는 클래스를 참조할 수 있는 곳이라면 어디서나 사용할 수 있음을 의미한다.
- protected 필드는 필드를 포함하고 있는 클래스와 같은 패키지에서 그리고 그 클래스의 서브 클래스에서 사용할 수 있음을 의미한다. 부모 클래스와 자식 클래스가 반드시 같은 패키지에 존재하는 것은 아니기 때문이다.
- 접근 제어자가 생략된 경우는 필드를 포함하고 있는 클래스와 같은 패키지에서만 사용할 수 있음을 의미한다.
- private 필드는 같은 클래스 내부에서만 사용할 수 있음을 뜻한다. 즉 클래스의 외부에서는 private 필드를 사용할 수 없다.
- 접근성을 의미하는 것은 아니나 final, static 키워드가 필드 선언에 나올 수 있다.
- final 필드는 상수를 선언하기 위한 것으로 선언과 동시에 초기화되어야 한다.
- static 필드는 객체가 독립적으로 소유하는 필드가 아니고 클래스의 모든 객체가 공유하는 변수를 의미한다. static 필드를 정적 필드 또는 클래스 변수라고 한다.
- 부모 클래스와 자식 클래스의 객체는 static 필드를 공유한다.
- 모든 객체는 정적이 아닌 필드를 배타적으로 소유한다.

∙ 메소드의 접근 제어자
- 객체를 통해 메소드를 호출할 때, 메소드의 접근 제어자는 메소드를 호출할 수 있는 범위를 제어하기 위한 것이다.
- 메소드의 접근 제어자로는 public, protected, 생략 및 private 이 있으며 필드의 접근 제어자와 의미가 같다.
- 접근성을 의미하는 것은 아니나 final, static, abstract 및 synchronized 키워드가 메소드 선언에 나올 수 있다.
- final 메소드는 서브 클래스가 상속을 받을 수 있지만 서브 클래스에서 오버라이딩할 수 없는 메소드를 의미한다.
- abstract 메소드는 몸체의 구현이 없이 선언된 메소드를 의미한다. abstract 메소드를 가지는 클래스는 반드시 abstract 클래스로 정의되어야 한다.
- abstract 메소드는 서브 클래스에서 몸체가 만들어져야 하므로 abstract 이면서 final 메소드는 존재할 수 없다.
- static 메소드는 객체와 상관없이 호출되는 메소드로 객체를 생성하지 않아도 클래스 이름을 통해 호출될 수 있는 메소드이다. 예 Integer.parseInt(“123”);
- static 메소드를 정적 메소드 또는 클래스 메소드라고 하며 정적이 아닌 메소드를 인스탄스 메소드라고 한다.
- static 메소드는 특정 객체가 소유하고 있는 필드를 다룰 수 없으므로 this 나 super 를 사용할 수 없다. 즉 static 메소드에서는 static 이 아닌 필드나 메소드를 사용할 수 없다.
- synchronized 메소드는 멀티 스레딩에서 동기화가 필요한 메소드를 의미한다. 여러 스레드가 하나의 공유 자원을 처리하면서 동시에 수행될 때 synchronized 메소드는 한 순간에 하나의 스레드만이 실행시킬 수 있다.

∙ 메소드 오버로딩
- 인자의 개수나 인자의 자료형이 다르면 같은 이름의 메소드를 한 클래스에서 중복 정의할 수 있음 (인자의 개수나 인자의 자료형으로 구분할 수 있어야 함_
- 메소드를 호출할 때, 가장 가까운 메소드가 호출됨

∙ 객체 초기화
- 객체 초기화란 객체를 생성할 때, 객체가 가지는 데이터 필드의 값을 초기화하는 것이다.
- 데이터 필드는 자동으로 초기값이 주어질 수 있음
- 인스탄스 필드는 필드 선언과 함께 수행되는 일반 필드의 초기화, 일반 초기화 블록, 생성자 순으로 초기화된다.
- 정적 필드는 필드 선언과 함께 수행되는 static 필드의 초기화, 정적 초기화 블록, 생성자 순으로 초기화된다.
- 마지막으로 수행되는 초기화 작업에 의해 필드의 초기값이 결정된다.

∙ 메소드 오버로딩과 다중 생성자
- 하나의 클래스에 같은 이름의 메소드가 여러 개 정의되는 것을 말한다.
- 오버로딩된 메소드들은 인자의 개수와 자료형에 따라 구별되어야 한다.
- 메소드가 호출되면 메소드의 이름, 인자의 개수와 자료형이 정확하게 일치하는 것이 선택되어 실행된다.

∙ 클래스의 재사용
- 합성 : 기존 클래스를 새로운 클래스의 멤버로 사용 (has-a 관계)
- 상속 : 기존 클래스(부모)를 사용하여 새로운 클래스(자식)을 정의, 프로그램의 확장성 증대, 기존 클래스의 확장 또는 특화, (is-a 관계)

∙ 클래스의 상속
- 상속은 부모 클래스와 자식 클래스 간의 관계이다.
- 상속은 가장 중요한 객체지향 개념의 하나로 기존 클래스를 이용하여 새로운 클래스를 정의하는 방법이다.
- 상속은 프로그램 구조화를 위한 좋은 방법이다.
- 상속을 주는 클래스를 슈퍼 클래스, 베이스 클래스, 상위 클래스 또는 부모 클래스라고 한다.
- 상속을 받는 클래스를 서브 클래스, 파생 클래스, 하위 클래스 또는 자식 클래스라고 한다. 자식 클래스는 부모 클래스의 모든 특성을 상속받으며 추가적으로 자신만의 필드와 메소드를 정의할 수 있다.
- Java 언어에서 부모 클래스를 상속받기 위해 키워드 extends 를 사용한다.
예) class Manager extends Employee { … }
- 클래스의 상속은 단일 상속만 가능 (인터페이스 상속의 경우는 다중 상속 가능)

∙ 메소드의 오버라이딩
- 서브 클래스가 슈퍼 클래스에서 정의된 메소드를 그대로 상속받지 않고 새롭게 정의하는 것이다.
- 메소드 오버라이딩을 메소드 재정의라고도 부르며 서브 클래스에서 슈퍼 클래스의 메소드를 재정의할 때는 메소드의 이름과 반환형 및 인자가 정확히 일치해야 한다. 또 접근 제어자는 일치하거나 접근 범위를 넓게 해야 한다.

∙ this 와 super
- 메소드는 인스탄스 메소드와 정적 메소드로 구분된다.
- 인스탄스 메소드를 호출하려면 그것을 실행하기 위한 객체가 필요하다.
- 예를 들어 c.getArea( )는 객체 c 가 가지고 있는 반지름으로 면적을 계산한다.
- this 와 super 는 정적인 아닌 메소드, 즉 인스탄스 메소드에서만 사용된다.
- 인스탄스 메소드가 실행될 때 this 는 메소드를 실행시키는 현재 객체의 참조값을 가진다. (숨은 인자로 this가 메소드에 전달됨)
- this 를 사용하여 객체의 멤버에 접근할 수 있다. 인스탄스 메소드나 생성자에서 사용 가능 (클래스 메소드에서 사용할 수 없음)
- super 도 현재 객체의 참조값을 가지나 자료형이 직계 상위 클래스의 유형이다.
- 서브 클래스와 슈퍼 클래스에서 같은 이름의 필드를 정의하고 있다면, 서브 클래스에서 슈퍼 클래스로부터 상속받은 같은 이름의 필드를 참조할 때 super 를 사용한다.
- super는 자식 클래스에서 인스탄스 메소드나 생성자에서 사용됨, 부모 클래스에서 오버로딩 당한 메소드를 호출하거나 상속되었으나 감춰진 필드에 접근할 때 필요함
예) super.메소드(인자), super.필드

∙ this()와 super()
- this()는 생성자의 몸체 맨 앞에서 사용되며 같은 클래스의 다른 생성자를 호출하는 것이다.
- super()는 생성자의 몸체 맨 앞에서 사용되며 슈퍼 클래스의 생성자를 호출하는 것이다. 상속받은 데이터 필드를 초기화하기 위한 것으로 생성자 몸체에서 부모 클래스 생성자의 명시적 호출이 없다면, super()가 자동 호출됨

∙ 추상 메소드
- 몸체의 구현이 없이 형식만 존재하는 메소드 (반환경, 이름, 인자 선언만 존재)
- 메소드 정의에 abstract 키워드 사용해야 함, 자식 클래스에 상속되어 몸체의 구현 필요
- 상반된 의미의 final과 함께 사용할 수 없음

∙ 추상 클래스
- 추상 메소드를 포함하는 클래스는 반드시 추상 클래스라야 함
- 물론 데이터 필드나 일반 메소드를 포함할 수 있음
- 객체 생성을 할 수 없음 (구체적이지 못한 불완전한 클래스라는 의미)
- 클래스 정의에 abstract 사용해야 함
- 의미적으로 유사한 클래스를 묶고자 할 때 사용
- 공통으로 사용할 데이터 필드와 메소드를 정의
- 기능적으로 구현하기 어려운 메소드가 존재
- 추상 클래스는 자식 클래스로 상속되어 사용됨
- 자식 클래스에서 추상 메소드를 구현, 그러면 자식 클래스는 객체 생성이 가능
- 자식 클래스가 추상 메소드를 구현하지 않으면 계속해서 자식 클래스도 추상 클래스로 남음
- 추상 클래스는 일반 클래스와 인터페이스의 중간적 성격을 가짐

∙ 인터페이스
- 인터페이스의 이름은 클래스의 이름과 마찬가지로 참조형의 이름에 해당한다.
- 추상 클래스와 유사하여 인터페이스는 객체를 생성시킬 수 없다.
- 100% 추상 클래스 (모든 메소드가 추상 메소드, 데이터는 클래스 상수만 가능, default 메소드와 static 메소드는 몸체의 구현이 필요함)
- 인터페이스는 서브 클래스에 의해 구현될 수 있고 다른 인터페이스에 의해 상속될 수 있다.
- 인터페이스는 유사한 객체들이 가지는 공통적 행동 양식만을 정의하기 위한 것이다. 즉 실제 행위를 표현하는 메소드의 몸체를 정의하지 않고 행동 양식만을 정의하기 위해 메소드의 형식만을 정의한다.
- 인터페이스의 접근 제어자는 public 이어야 하며 생략하더라도 그러하다.
- 인터페이스에서 선언된 모든 메소드는 abstract 메소드이어야 하며 생략하더라도 그러하다. 따라서 인터페이스 내부에서 몸체를 가지는 메소드를 정의할 수 없다.
- 인터페이스에서 선언된 모든 메소드는 묵시적으로 public 접근 제어 수준을 가지며 생략하더라도 그러하다.
- 인터페이스에서 필드를 선언할 수 있으며 묵시적으로 public static final 이며 생략하더라도 그러하다.
- 인터페이스 간에도 상속 관계가 있을 수 있으며, 하위 인터페이스는 상위 인터페이스를 상속받을 수 있다. 다중 상속도 가능하다.
- 하위 클래스는 상위 인터페이스를 상속받을 수 있으며 키워드 implements 를 사용한다. 다중 상속도 가능하다.
- 하위 클래스는 상위 인터페이스에서 선언된 모든 메소드의 몸체를 구현해야 하며 이것을 구현 관계라고 부를 수 있다.
- 인터페이스의 이름은 보통 형용사임 (Runnable, Serializable, Comparable)
- 정의할 때 키워드 class 대신에 interface를 사용 (abstract는 생략하는 것이 보통임)
- 메소드는 자동으로(생략 가능) public abstract임 (수행할 수 있는 기능의 형식만 나열한 것)
- default 메소드와 static 메소드도 가능 (이 경우 몸체를 구현해야 함, 자동으로 public임)
- 필드는 자동으로 public static final임 (클래스 상수만 가능함)

∙ 인터페이스의 사용
- 추상 클래스와 마찬가지로 자식 클래스에 상속되어 사용됨 (인터페이스를 상속받는 자식 클래스는 모든 추상 메소드를 구현해 주어야 함)
- 의미적으로는 관련이 없으나 기능적으로 유사한 클래스들을 묶을 때 사용할 수 있음
예) 대소 비교가 가능한 객체들의 자료형을 묶을 때
- 인터페이스를 상속받아 자식 인터페이스를 정의할 수 있음 (인터페이스의 확장)
- 여러 인터페이스를 상속받는 다중 상속이 가능
- 상속 : 자식 인터페이스가 부모 인터페이스를 상속받는 경우, extends를 사용
예) interface A extends OtherInterface1 { … }
- 구현(or상속) : 자식 클래스가 부모 인터페이스를 상속받는 경우, 자식은 부모가 나열한 기능을 구현해야 함, implements를 사용
예 ) class MovablePoint implements Movable { … }

∙ 디폴트 메소드
- 인터페이스에서 선언하는 메소드에 기본 구현을 넣을 수 있음 (자식 클래스에서 그대로 사용하거나 몸체를 다시 정의해 줄 수 있음)
- default를 사용하고 몸체를 구현해 줌
- 인터페이스에 나열된 기능을 확장할 때, 기존 코드의 수정을 피하기 위함 (추상 메소드가 추가된다면 기존 인터페이스를 구현한 클래스를 수정해야 함)

∙ 추상 클래스/인터페이스/클래스의 형 변환
- 인터페이스와 클래스는 모두 사용자 정의형
- extends와 implements에 따라 상위/하위 자료형 관계가 설정됨
- 상위 유형의 변수는 하위 객체의 참조값을 가질 수 있음
- 상위 유형의 변수가 가리키는 객체의 실제 유형에 따라 수행되는 메소드가 결정됨(동적 바인딩) (변수의 선언 유형으로 정하지 않음)
예) SuperClass super1= new SubClass();
super.method(); // SubClass에서 찾음

∙ 다형성
- 다형성이라는 개념은 같으면서도 다른 것 혹은 다르면서도 같은 것을 다루기 위한 것이다.
- 하나의 객체가 다양한 형상이나 다양한 기능을 가진다는 뜻 (하나의 클래스에서 오버로딩된 메소드들은 유사하지만 조금씩 다른 기능을 수행함, 자식 클래스에서 재정의된 메소드는 부모 유사하지만 다른 기능을 수행함)
- 하나의 슈퍼 클래스로부터 상속받은 서브 클래스들의 기능이 유사하지만 세부적으로 달라질 수 있다.
- 하나의 클래스에서 오버로딩된 메소드들은 유사하지만 조금씩 다른 기능을 수행한다.
- 다형성은 메소드 오버라이딩, 메소드 오버로딩 및 메소드의 동적 바인딩을 통해 구현될 수 있다.
- Java 프로그램에서는 extends 와 implements 에 따라 상하위 자료형이 정해지며 상위 자료형의 변수에 하위 유형의 객체가 대입될 수 있다.
- 상위 유형의 변수는 실행 중에 다른 유형의 하위 객체를 가리킬 수 있으며, 실제 객체의 유형에 따라 수행되는 메소드가 결정된다.
- 다형성을 사용하면 보다 가독성이 좋고 유지보수가 효율적인 프로그램을 작성할 수 있다.
- 왜냐하면 다형성은 같은 클래스를 상속받는 여러 서브 클래스들로부터 생성된 객체들을 슈퍼 클래스의 관점에서 제어하면서도 서브 클래스들이 갖는 고유 기능대로 동작하게끔 할 수 있기 때문이다.

∙ 형 변환
- 상속 관계에 있는 클래스 간에는 타입 변환이 가능함 (전혀 다른 두 클래스 간에는 타입 변환이 금지됨)
- 하위 클래스에서 상위 클래스로의 형 변환은 문제없음 (상위 유형의 변수는 하위 객체의 참조값을 가질 수 있음)

∙ 클래스의 다형성
- 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 오버라이딩할 수 있음
- 부모와 자식에서 같은 이름의 메소드가 다른 기능을 수행 (같은 이름과 매개 변수 및 반환형을 가지나 몸체가 다름)

∙ 인터페이스의 다형성
- 자식 클래스들에서 상위 인터페이스의 메소드를 다르게 구현함

∙ 열거형
- 열거형은 미리 정의된 상수값을 만들기 위한 자료형
- enum을 사용하여 정의
- 열거형으로 선언된 변수에는 미리 지정된 값만 대입 가능
- 상수값을 배열로 리턴하는 static 메소드로 values()를 제공
예) enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }
- 열거형 정의에 필드와 메소드를 포함할 수 있음
- 상수 선언이 필드나 메소드보다 먼저 정의되어야 하며 세미콜론(;)으로 끝나야 함
- 생성자는 열거형과 같은 이름을 가지며 접근 제어자는 생략 또는 private이어야 함
- 열거형의 생성자는 상수값을 설정(객체 생성)할 때 자동 호출됨
- 열거형에서 상수는 마치 하나의 객체와 같음

∙ 익명 클래스
- 일회성으로 1개의 객체를 생성하기 위한 클래스 (클래스 정의와 동시에 객체를 생성할 수 있음)
- 독립된 클래스 정의문 없이 바로 객체를 생성하는 용도로만 사용되는 클래스를 의미
- 슈퍼 클래스를 상속받는 서브클래스로 익명 클래스를 만들어서 객체를 생성하는 방법
- 인터페이스를 구현하는 클래스로 익명 클래스를 만들어서 객체를 생성하는 방법
예) '익명객체변수' = new '슈퍼클래스/인터페이스'() { (익명 클래스의 몸체) }


제 4 장 패키지와 예외처리

∙ 패키지
- 관련이 있는 클래스와 인터페이스의 묶음 (클래스와 인터페이스는 패키지의 멤버로 존재)
- 전체적으로 계층 구조의 클래스 라이브러리 (패키지(폴더와 유사) 단위로 계층적으로 분류됨)
- 용도 : 찾아 사용하기 쉽도록, 이름 충돌을 피하도록, 그리고 접근을 제어하기 위해 관련이 있는 타입들을 패키지로 만들어 관리한다.
- 타입이란 클래스와 인터페이스를 말하며, 패키지는 관련이 있는 클래스들과 인터페이스들의 묶음이다.
- Java 의 기본 API 는 패키지 단위로 계층적으로 분류되어 있다. 전체적으로 폴더의 계층 구조와 같으며 하나의 패키지가 하나의 폴더에 해당한다.
- Java 프로그램에서 상위 패키지와 하위 패키지를 구분하기 위해 ‘.’(도트) 표기법을 사용한다.
예 java.lang.String
- 기본적인 클래스들은 java.lang 패키지에 존재하며 입출력을 위한 클래스들은 java.io 패키지에 포함되어 있다.
- 사용자가 만든 패키지를 배포할 때는 전체 폴더를 하나의 jar 파일로 압축하여 배포하는 것이 일반적이다.

∙ 시스템 패키지 :
- Java가 제공하는 클래스 라이브러리 (JDK와 함께 설치됨)
- 일반적으로 jar 파일로 압축되어 있음
예) C:\Program_Files\Java\jdk1.8.0_121\jre\lib\rt.jar
예를 들어 java\lang\Boolean.class가 존재함
- 가장 기본이 되는 최상위 시스템 패키지는 java임
- 대부분의 시스템 패키지는 java.으로 시작됨
- Java프로그램에서 상위와 하위 패키지의 구분을 위해 도트(.)를 사용
예) java.lang, java.io, java.awt, java.util 등
- Java언어의 기본 클래스는 java.lang에 존재
- 프로그램에서 클래스를 사용할 때는 java.io.IOException과 같이 사용함

∙ 사용자 정의 패키지
- 패키지 정의 문법 : package 패키지 이름; // 1개 이상의 클래스나 인터페이스 정의
- package 구문은 소스 코드 맨 앞에 위치해야 함
- 패키지 이름은 관례상 소문자로 작명 (하위 패키지는 .으로 구분하여 작성)
- 컴파일하면 패키지가 만들어지고(또는 기존 패키지에) 클래스 파일(.class)이 패키지에 저장됨
예) 패키지 만들기
package com.vehicle;
public class Car {
String szType = "승용차";
}
- 컴파일 결과로 Car.class가 만들어짐
- Car.class는 com.vehicle 패키지에 저장됨
- com.vehicle은 어디에? 컴파일 할 때 –d옵션 사용하여 지정함
예) - javac Car.java –d D:\javaClasses // 이 경우 D:\javaClasses\com\vehicle\Car.class
- Eclipse를 사용한 패키지 정의 (메뉴 [File/New/Package]를 선택 - 패키지에 해당하는 폴더가 만들어지고, 생성된 패키지에서 클래스를 만들면 됨)
- 메뉴 [File/New/Class]를 선택하여 클래스 이름과 함께 패키지 이름을 입력함

∙ 패키지 선언
- 패키지를 만들어 클래스나 인터페이스를 포함시키려면 소스 코드의 맨 위에 package 구문을 넣어준다.
- 패키지 선언이 있으므로 Graphic.class 는 graphics 패키지에 저장된다.
- '클래스 경로' 의 위치는 컴파일 명령에서 –d 옵션을 사용하여 지정할 수 있다.

∙ 패키지 사용
- 같은 패키지에 있거나 public인 외부의 클래스를 사용하려면 패키지를 포함한 완전한 클래스 이름을 사용해야 함
예 ) § graphics.Rectangle myRect = new graphics.Rectangle( );
§ java.util.Scanner s = new java.util.Scanner(System.in);

∙ import 구문
- import 패키지 이름.클래스이름; 또는 import 패키지이름.*;
- import 구문은 소스 코드 맨 앞에 위치함 (package 구문이 있다면 그 다음에 위치)
- 프로그램에서 패키지 이름을 생략하고 클래스나 인터페이스를 사용할 수 있게 함
- Java 소스에서 외부 패키지에 존재하는 public 클래스나 인터페이스를 사용하기 위해서는 ‘import 구문을 사용한 후 클래스 이름만을 사용’하거나 ‘패키지 이름을 포함한 완전한 클래스 이름을 사용’해야 한다.
- 완전한 클래스 이름을 사용한다는 것은 IOExcepton 클래스를 사용할 때 java.io.IOException 과 같이 작성하는 것이다.
- import 구문을 사용할 때는 패키지 전체를 포함시키거나 패키지 이름을 포함한 완전한 클래스 이름을 사용한다.
- Java 의 모드 소스에는 명시적으로 작성하지 않더라도 ‘import java.lang.*’ 구문이 포함되어 있다. 지금까지 자주 사용했던 System 클래스나 String 클래스가 이 패키지에 포함되어 있다.

∙ 클래스 찾기
- 컴파일하거나 실행 할 때, 필요한 클래스를 찾아야 함
- 컴파일러가 A.class가 위치한 경로 또는 A.class를 포함하고 있는 jar 파일의 존재를 알아야 함
- JVM은 다음에서 클래스를 찾음
1) Java 기본 패키지 : [Java설치폴더]\lib\*.jre
2) Java 확장 패키지 : [Java설치폴더]\lib\ext\*.jre
3) 사용자 클래스도 찾을 수 있음 : 사용자 클래스는 환경 변수 CLASSPATH에 지정된 경로 또는 jar 파일에 서 찾음

∙ 환경 변수 CLASSPATH
- 컴파일러는 CLASSPATH에 지정된 경로에서 클래스를 찾음
- CLASSPATH의 경로는 jar 파일을 포함할 수 있음
- Java 프로그램을 컴파일 또는 실행할 때 필요한 클래스나 패키지는 CLASSPATH 환경 변수에 포함되어 있는 경로상에서 찾을 수 있어야 한다.
- import 구문을 사용하여 com.example.graphics.Rectangle 클래스를 사용한다고 선언하였다면 com 폴더를 포함하고 있는 '클래스 경로'가 CLASSPATH 환경 변수에 포함되어 있어야 한다.
- '클래스 경로' 가 D:\javaClasses 라면 CLASSPATH 환경 변수가 다음과 같아야 한다.
>set CLASSPATH=경로 1;경로 2;D:\javaClasses;경로 3
- CLASSPATH 환경 변수는 jar 파일을 포함할 수 있다.
- Java 의 기본 패키지는 jar 파일 형태로 제공되며 CLASSPATH 환경 변수에 그 위치가 지정되어 있지 않아도 무방하다.

∙ 에러와 예외
- Java 프로그램을 실행하는 도중에 에러 또는 예외가 발생할 수 있다.
- 에러(error)는 심각한 오류로 더 이상의 진행이 불가능한 상황이다.
- 예외(exception)는 경미한 오류로 예외처리를 통해 정상적인 상황으로의 복구가 가능하다.
- Java 에서 오류는 Error 클래스로 예외는 Exception 클래스로 표현된다.
- Exception 클래스는 특정 예외를 나타내는 서브 클래스들로 분류된다.
- ‘RuntimeException 을 제외한 나머지 예외’를 발생시킬 가능성이 있는 메소드를 호출하는 경우 반드시 프로그램상에서 예외처리를 해주어야 한다. 이러한 예외를 checked–Exception 이라 한다.
- RuntimeException 은 자주 발생할 수 있기 때문에 이것을 처리하는 예외처리 구문을 넣을지는 프로그래머의 재량이다.

∙ 예외 발생
- 메소드를 수행할 때 예외가 발생하면 예외 객체를 만들어 던짐
- 예외처리 코드가 없으면, 메시지가 출력되면서 종료됨
- 예외처리 코드가 있으면, 계속 수행됨
- 예외 객체 : Exception 클래스 또는 하위 클래스로 표현됨, 예외 객체는 예외 발생 정보를 가지고 있음


∙ 예외처리
- 예외처리란 프로그램 실행 도중 예외 상황이 발생할 때 적절한 조치를 취하여 프로그램이 중단되지 않고 계속 진행하게 하는 것이다.
- 실제로 예외가 발생하면 예외 상황의 정보를 담고 있는 Exception 객체가 만들어져 throw 된다. 예외가 던져진다고 할 수 있다. (ex) throw new MyException( );
- throw된 예외 객체를 catch하여 예외를 처리함
- checkedException이 발생할 수 있는 경우, 반드시 명시적인 예외 처리가 필요함
- RuntimeException의 경우, 예외처리를 안해도 됨 (잘못 작성된 프로그램 때문에 발생됨, ArithmeticException, NullpointException, IndexOutOfBoundsException 등)
- 예외처리를 위한 구문으로 try–catch 또는 try–catch–finally 가 있다.

∙ 예외처리 방법
- 직접 처리 : 던져진 예외 객체를 잡아 처리하는 것, try-catch 구문 또는 try-catch-finally 구문을 사용하여 예외를 처리함, 일반 코드와 예외 처리가 분리되어 가독성이 좋아짐
- 간접 처리 : 예외 발생 가능성이 있는 메소드의 선언에서 인자 다음에 throws 예외이름을 사용, 그 메소드를 호출하는 메소드에게 예외처리를 전달 또는 위임하는 것

∙ try-catch 구문

- 예외 객체를 throw하는 문장 또는 예외를 발생시킬 수 있는 메소드 호출문이 try 블록 안에 위치해야 한다.
- 실제 예외를 처리하는 문장을 catch 블록 안에 위치시킨다.
- catch 블록은 예외 유형의 1개 인자를 전달받는 메소드와 유사한 형태로 특정 유형의 예외 객체를 인자로 전달받을 수 있다. 즉 try 블록에서 던져진 예외 객체를 잡아서 처리할 수 있다.
- 여러 종류의 예외가 발생할 수 있다면 catch 블록도 여러 개를 만들 수 있다.
- 예외가 발생하면 try 블록이 즉시 종료되고 상응하는 예외를 처리하는 catch 블록 중 가장 적합한(발생된 예외 자료형 또는 상위 유형) 하나만 선택되어 실행된다.
- 예외가 발생하지 않으면 catch 블록은 실행되지 않음
- Java API 설명 문서에서 InputStream 클래스에서 정의된 read() 메소드에 관한 내용을 살펴보면 throws IOException 이라고 쓰인 것을 볼 수 있다. 즉 read() 메소드를 실행하면 IOException 이 발생할 수도 있다는 것이다.
- try–catch–finally 구문에서 finally 블록은 예외 발생과 상관없이 최종적으로 항상 실행되는 블록이다. finally 블록은 생략 가능하다.
- finally 블록의 용도는 대개 할당받아 사용했던 리소스를 되돌려 주는 일을 확실히 하기 위한 것이다. 예를 들어 open 되었던 파일을 close 하는 명령은 finally 블록에 위치하는 것이 좋다.

∙ 예외의 전파
- 예외를 발생시킬 수 있는 메소드를 호출하는 쪽에 예외 처리를 위임하는 것
- System.in.read( )와 같이 예외를 발생시킬 수 있는 메소드 호출문은 try 블록 안에 두어 예외를 처리하는 것을 예외의 직접 처리라고 한다.
- 예외의 전파는 예외를 직접 처리하지 않고 예외를 간접적으로 처리하는 것이다.
- 메소드의 형식에서 괄호 다음에 ‘throws '예외 이름'을 사용하면 몸체에서 예외를 발생시킬 수 있는 메소드 호출이 있더라도 직접 처리할 필요가 없다.
예) public char getInput( ) throws IOException {
nInput = System.in.read( ); //예외 발생 가능
}
- throws 절이 있는 메소드를 호출하는 메소드에서 예외 처리를 해야 함
예) try {
c = obj.getInput( );
}
catch(IOException ex ) {
}
- 아래와 같은 예외를 발생시킬 수 있는 메소드를 사용할 때는 반드시 예외 처리가 필요함
public FileInputStream(String name) throws FileNotFoundException // FileInputStream 클래스의 생성자
public int read() throws IOException // InputStream 클래스/Reader 클래스의 메소드

∙ 사용자 정의 예외
- 사용자가 직접 예외 클래스를 작성할 수 있음
- 일반적으로 Exception 클래스를 상속받음
- 필요할 때 예외 객체를 throw함


제 5 장 java.lang 패키지

∙ java.lang 패키지
- java.lang 패키지는 Java 프로그래밍에 필요한 기본 클래스들을 제공한다.
- import 구문을 쓰지 않더라도 모든 Java 소스 코드에 자동으로 포함되는 패키지이다.
- 주요 클래스들은 다음과 같다.
가. Object:모든 클래스의 최상위 클래스
나. String, StringBuffer 클래스:문자열 처리 관련 클래스
다. Process, Runtime, Thread, ThreadGroup 클래스:프로세스 및 스레드 제어와 관련된 클래스
라. Math, StrictMath 클래스:수학 관련 메소드나 상수를 제공하는 클래스
마. Exception, Throwable, Error 클래스:예외처리와 관련된 클래스
바. System, Package, Class, ClassLoader:시스템, 패키지 및 클래스에 대한 정보를 제공하는 클래스들
사. Boolean, Character, Byte, Short, Integer, Long, Float, Double:기본형을 객체로 표현한 클래스(wrapper 또는 포장 클래스라고 함)

∙ Object 클래스
- 모든 클래스는 묵시적으로 Object 클래스를 상속받는다. 따라서 모든 객체는 Object 클래스에서 정의된 메소드를 사용할 수 있다.
- 주요 메서드
가. protected Object clone( ) // 객체를 복제하여 반환
나. public boolean equals(Object obj)
다. public int hashCode( ) 객체를 식별하는 정수값을 반환
라. public String toString( )

∙ Object 클래스의 ‘String toString()’ 메소드
- 객체를 String 유형으로 변환할 때 사용되는 메소드이다.
- 객체를 “클래스이름@객체의 16 진 해시 코드”의 문자열로 변환하여 리턴한다.
- 실제 정의는 아래와 같다. hashCode()도 Object 클래스에서 정의된 것으로 객체의 해시 코드를 리턴하는 메소드이다. 해시 코드는 객체 식별을 위해 유일하게 할당되는 정수이다.
- 객체를 String 으로 변환할 때 다른 표현을 사용하려면 해당 자식 클래스에서 toString( ) 메소드를 재정의해야 한다.
- println( ) 메소드는 인자를 String 형으로 변환한 후 출력하는데 그때 toString( ) 메소드를 사용한다. 실제 출력되는 결과는 myObject 가 속한 클래스가 Object 클래스의 toString( ) 메소드를 그대로 상속받는지 아니면 재정의했는지에 따라 다르다.
- 문자열의 + 연산, System.out.print( ) 등에서 필요함
- 자식 클래스에서 재정의할 수 있음 (String, Integer 클래스 등에서 재정의되어 있음)

∙ Object 클래스의 ‘boolean equals(Object obj)’ 메소드
- 객체를 다른 객체와 같은지 비교(객체 변수의 참조값)하여 true 또는 false 를 리턴하는 메소드이다.
- 이 메소드를 사용하여 a.equals(b)를 수행한 결과는 a==b 와 동일하다. 즉 a 와 b 가 동일한 객체를 참조하고 있다면 true 를 그렇지 않으면 false 를 리턴한다.
- toString( ) 메소드와 마찬가지로 동등의 의미를 바꾸고자 한다면 해당 자식 클래스에서 equals( ) 메소드를 재정의해야 한다. (String, Integer 클래스 등에서 재정의되어 있음)

∙ Objet clone( )
- 객체를 복제하여 리턴함
- ‘Cloneable 인터페이스를 구현한 클래스’의 객체만 clone( ) 메소드를 호출할 수 있음
- 예외(CloneNotSupportedException)처리를 해 주어야 함

∙ String 클래스
- String 유형은 문자열을 표현하고 처리하기 위한 클래스이다.
- String 유형의 변수는 참조형이지만 기본형 변수처럼 사용할 수 있다.
- String 클래스는 immutable 이다. 즉 일단 String 객체가 만들어지면 내용을 변경할 수 없다. 문자열의 내용을 변경하는 메소드는 this 객체를 변경하는 것이 아니고 변경된 새로운 String 객체를 만든다. (즉, String 객체는 내용이 변하지 않는 상수 객체)
- 문자열을 빈번하게 변경하는 프로그램에서는 String보다 StringBuffer를 사용하자

∙ String 클래스에서 문자열 비교를 위한 메소드
- String 클래스는 equals() 메소드를 재정의하였으며 두 객체가 저장하고 있는 문자열의 내용이 같으면 true 를 리턴한다.
- 다음과 같은 메소드를 사용할 수 있다.
가. int compareTo(String anotherString):anotherString 과 비교하여 같으면 0 을 리턴하고 사전 순서에서 this 객체가 먼저면 양수, 그렇지 않으면 음수값을 리턴한다.
나. int compareToIgnoreCase(String anotherString):대소문자를 무시하고 비교한다.
다. boolean equals(Object anObject):Object 클래스의 equals() 메소드를 재정의 한 것이다. this 객체와 anObject 가 같은 문자열을 표현하면 true 를 리턴하고 다르면 false 를 리턴한다.
라. boolean equalsIgnoreCase(String anotherString):대소문자를 무시하고 비교한다.

∙ String 클래스에서 문자열 검색을 위한 메소드
가. int indexOf(String str), int indexOf(String str, int fromIndex):문자열 str 이 처음 등장하는 위치를 찾아 리턴한다. 위치는 0 부터 (문자열의 길이-1) 사이이다. fromIndex 를 추가하면 fromIndex 부터 찾는다. 일치하는 문자열이 없으면 -1 을 리턴한다.
나. int lastIndexOf(String str), int lastIndexOf(String str, int fromIndex):indexOf()와 유사하나 문자열 str 이 등장한 마지막 위치를 찾는다. fromIndex 가 주어지면 fromIndex 로 지정된 위치에서부터 문자열의 앞으로 찾기 시작한다.

∙ String 클래스에서 문자열 추출을 위한 메소드
가. char charAt(int index):index 위치에 있는 문자를 리턴한다.
나. String substring(int beginIndex):beginIndex 위치부터 마지막 위치까지의 문자열을 리턴한다.
다. String substring(int beginIndex, int endIndex):beginIndex 위치부터 (endIndex-1)까지의 문자열을 리턴한다.

∙ String 클래스에서 문자열 변환을 위한 메소드
- 원본 문자열은 변경되지 않고, 새로운 객체가 만들어진다.
가. String replace(char oldChar, char newChar):문자열에 등장하는 oldChar 문자를 newChar 문자로 변환한 문자열을 리턴한다.
나. String trim():문자열 앞과 뒤에 나오는 화이트 스페이스(white space)인 공백, 탭 문자 등을 제거한 문자열을 리턴한다.
다. String toUpperCase(), String toLowerCase():문자열의 모든 문자를 대문자(toUpperCase)나 소문자(toLowerCase)로 변환하고 변환된 문자열을 리턴한다.
라. String concat(String str):this 객체의 문자열 뒤에 str 을 연결한다. 실제로 두 문자열을 연결할 때 + 연산자가 많이 쓰인다.

∙ 다른 자료형을 문자열로 변환하기
- String 클래스는 모든 다른 자료형을 String 으로 변환해 주는 static 메소드인 String.valueOf()를 제공한다.

∙ String 클래스의 기타 메소드
가. boolean startsWith(String suffix):suffix 에 지정된 문자열로 시작하면 true를 리턴하고 그렇지 않으면 false 를 리턴한다.
나. boolean endsWith(String prefix):prefix 에 지정된 문자로 끝나면 true를 리턴하고 그렇지 않으면 false 를 리턴한다.
다. char[] toCharArray():문자형 배열로 변환하여 리턴한다.
라. int length():문자열의 길이를 리턴한다.

∙ StringBuffer 클래스
- String 객체는 한번 만들어지면 수정할 수 없지만, StringBuffer 객체는 문자열을 필요에 따라 수정할 수 있는 자료 구조이다.
- 내부적으로 문자열을 저장하기 위한 크기가 조절되는 버퍼를 사용함
- 내부적으로 문자열 저장을 위한 버퍼를 가지며 버퍼의 용량이 모자라면 자동으로 늘어난다.
- 중요한 메소드는 append()와 insert()이다.
예) StringBuffer(); // 초기 버퍼의 크기는 16
StringBuffer(int length);
StringBuffer(String str);

∙ StringBuffer 클래스의 메소드
가. StringBuffer(String str):StringBuffer의 생성자로 문자열 str 을 저장한다. 초기 버퍼의 용량은 (str의 길이+16)이다.
나. int capacity():객체의 버퍼 크기를 리턴한다.
다. int length():문자열의 길이를 리턴한다.
응. char charAt(int index), int indexOf(String str), String substring(int start, int end)
라. StringBuffer append(String s):문자열 s 를 현재 객체의 버퍼 뒤에 추가하여 연결하고, 객체의 참조를 리턴한다. append() 메소드는 기본 자료형, Object, String, StringBuffer 및 char[]의 인자를 가질 수 있도록 오버로딩되어 있다.
마. StringBuffer delete(int start, int end):버퍼의 start 위치에서 (end-1)까지의 문자들을 삭제한다.
바. StringBuffer replace(int start, int end, String str):start 위치에서 (end-1)까지의 문자들을 str 로 교체한다.
사. StringBuffer insert(int offset, String str):offset 으로 지정된 위치에 문자열 str 을 삽입한다. 기본형, String, StringBuffer 및 char[]의 인자를 가질 수 있도록 오버로딩되어 있다.
아. StringBuffer reverse():문자들의 순서를 역순으로 만든다.

∙ StringBuffer/StringBuilder 클래스
- String 클래스로 객체를 생성하고 나면 그 객체는 내용 변경이 불가능하다. 기존에 가리키던 문자열은 메모리에 그대로 두고 변경된 문자열로 새로운 String 객체를 생성한 후에 다시 객체변수에 대입한다.
- 문자열을 빈번하게 변경해야 하는 경우네는 String 클래스를 사용하지 않는 것이 바람직하다. (메모리 낭비, 실행속도 저하)
- String 클래스는 기존 문자열이 저장된 것을 그대로 두고 새롭게 공간을 할당받지만,
- StringBuffer 클래스나 StringBuilder 클래스는 값이 변경될 때 기존 공간에 추가되는 부분만큼만 할당받아 사용하기 때문에 메모리 낭비가 발생하지 않는다.
- 변경이 자주 발생하고 동시성 제어를 고려할 필요가 있다면 StringBuffer 클래스를 사용
- 변경이 자주 발생하면서 동시성 제어를 고려할 필요가 없다면 StringBuilder 클래스를 사용하는 것이 효과적이다.

∙ Wrapper 클래스
- 기본 자료형을 사용하지 않고 객체를 사용해야 하는 경우가 있다. 각 기본형에 대응되는 wrapper 클래스들이 제공된다.
- 이러한 클래스들은 기본형의 값을 객체로 포장(boxing, wrapping)한다.
- 객체가 요구되는 곳에 기본형의 값을 사용하면 컴파일러는 상응하는 wrapper 클래스를 사용하여 포장한다. 기본형이 요구되는 곳에 숫자를 표현한 객체를 사용하면 컴파일러는 포장을 푼다.
- 숫자를 표현한 포장 클래스 Byte, Short, Integer, Long, Float, Double 은 Number 클래스의 서브 클래스이다.
- 이 클래스를 사용하는 이유는 다음과 같다.
가. 메소드의 인자로 객체가 필요하다.
나. 클래스가 제공하는 상수를 사용할 때 : Interger.MIN_VALUE,􀀁Interger.MAX_VALUE 등
다. 기본형, wrapper 형 및 String 사이의 변환 기능과 진법 변환 기능을 사용한다.
라. 클래스가 제공하는 다양한 메소드를 사용할 때

∙ Number 클래스
- Byte, Short, Integer, Long, Float, Double의 추상 부모 클래스
- 주요 메서드
가. byte byteValue( ), short shortValue( ), … // 객체를 해당 기본형의 숫자로 변환(unboxing)
나. int compareTo(Byte anotherByte), … // 객체들의 크기를 비교
다. boolean equals(Object obj) // 같은 유형이고, 값이 같으면 true

∙ String과 기본형 데이터 간의 변환
- 포장 클래스가 제공하는 static 메소드를 사용
- String을 int형으로 변환 : int n = Interger.parseInt("123");
- int형을 String형으로 변환 : String s1 = Integer.toString(310); 또는 String s2=String.valueOf(312);

∙ Integer 클래스
- Interger, String, int 사이의 변환 기능을 제공
- 다른 클래스들도 유사한 기능을 제공
가. static int parseInt(String s); // String -> int
나. static String toString(int i); // int ->String
다. static Integer valueOf(int i); // int -> Integer
라. String toString( ); // Integer -> String
마. static Integer valueOf(String s); // String -> Integer

∙ 박싱
- 기본형 데이터를 포장 클래스의 객체로 변환하는 것
예) Double radius = new Double(2.59); //생성자
Double radius = Double.valueOf(10.4); //valueOf() 메소드
Double radius =2.59; //자동 boxing
- 자동 박싱(boxing) : 기본형에서 포장 클래스의 객체로 자동 변환 (인자에 전달되거나 변수에 대입될 때)

∙ 언박싱
- 포장 클래스의 객체를 기본형 데이터로 변환하는 것
예) double r = radius.doubleValue( ); //객체.기본형Value( )
예) double r = radius; //자동 unboxing
System.out.println(new Integer(3) % 2); //자동 unboxing
- 자동 언박싱(unboxing) : 포장 클래스의 객체에서 기본형으로 자동 변환 (인자에 전달되거나 변수에 대입될 때)

∙ System 클래스
- 운영체제 시스템과 관련된 기능 제공
- System 클래스는 표준 입출력, 시스템 속성과 환경 변수의 사용, 배열 복사 등과 같은 유용한 클래스 필드와 메소드를 제공한다.
- 모든 멤버가 static 이므로 객체를 생성할 필요가 없다.

∙ 표준 입출력 스트림
가. System.in:InputStream 유형의 표준 입력 스트림으로 키보드 입력을 받아들인다.
나. System.out:PrintStream 유형의 표준 출력 스트림이다. 화면에 데이터를 출력할 때 사용한다.
다. System.err:PrintStream 유형의 표준 에러 출력 스트림이다. 오류 메시지를 화면에 출력할 때 사용한다.

∙ 키보드로부터 입력받기
- System.in.read()는 1 바이트를 읽어 정수를 리턴한다.
- 만약 ‘0⤶’를 입력하면 먼저 ‘0’을 읽어 이것의 ASCII 값인 48 을 리턴한다. 이것을 char 형으로 출력하려면 형변환을 해야 하고 int 값 0 으로 만들려면 ‘0’을 빼주어야 한다.
- System.in.available()은 남아 있는 바이트 수를 리턴하는데 ‘⤶’를 어떻게 해석하는가는 운영체제에 따라 다를 수 있다.


제 6 장 멀티 스레드 프로그래밍

∙ 프로세스와 스레드
- 하나의 CPU 를 가지는 컴퓨터 시스템에서 여러 프로세스가 수행중일 수 있다. 이 상황을 ‘멀티 프로그래밍’이라 하며 프로세스들은 시분할 기법을 통해 CPU 를 공유하게 된다.
- 프로세스는 실행중인 프로그램을 말한다.
- 하나의 프로세스는 하나의 독립적 실행 단위로 메모리 따위의 리소스를 배타적으로 소유한다.
- 스레드는 실행 중인 프로그램 내에 존재하는 소규모 실행 흐름
- 스레드를 경량 프로세스라 하는데 프로세스 내부에 존재하는 소규모 실행 단위로 프로세스보다 적은 리소스를 요구한다.
- 통상적으로 하나의 Java 애플리케이션은 하나의 프로세스로 만들어져 수행되고, 하나의 프로세스에는 적어도 하나의 스레드(main 스레드)가 존재한다.
- 하나의 프로세스에 여러 스레드가, 프로세스 내의 자원을 공유하며 수행될 수 있는데 이것을 ‘멀티 스레딩’이라 한다.
- Java 프로그램은 하나의 프로세스로 만들어져 수행됨, 하나의 프로세스 내부에서 여러 스레드가 실행될 수 있음

∙ 멀티 스레드
- Java 프로그램은 하나의 스레드(main 스레드)로 시작됨
- main 스레드에서 자식 스레드를 만들어 시작시킬 수 있음
- 그러면 여러 스레드가 동시에 독립적으로 실행됨


∙ 스레드 생성하기
- Java 프로그램에서 스레드를 생성하는 방법은 Thread 클래스를 이용하는 것과 Runnable 인터페이스를 이용하는 방법이 있다.
- 스레드를 생성하고 start() 메소드를 시작시키면 자동으로 run() 메소드가 시작된다. 스레드의 실행 코드를 포함하는 것이 run() 메소드이다.

∙ Thread 클래스 이용하기
- Thread 클래스를 상속받는 클래스를 정의하고 이 클래스에 run() 메소드를 정의한다.
- Thread 클래스에는 이미 run() 메소드가 정의되어 있으나 아무것도 하지 않는 메소드이다. 따라서 상속받는 클래스에서 run() 메소드를 재정의해야 한다.
- 스레드의 생성과 관리를 위한 메소드를 제공
- 스레드 생성을 위해 Thread 유형의 객체가 필요함
- 생성자 : Thread( ), Thread(String name), Thread(Runnable target), Thread(Runnable target, String name) (Runnable 인터페이스를 구현하려면 run()을 구현해야 함)

∙ 스레드 생성과 실행
- Thread 유형의 객체 t를 생성
- t.start( )를 호출하면 스레드 실행이 시작됨
- 이것은 run( ) 메소드를 호출함 (void run() 메소드에 스레드의 실행 코드가 있음)
- run()을 정의하는 두 가지 방법이 있음 ( Thread 객체를 생성하는 두 가지 방법)

∙ 스레드 생성 방법1 : Thread 클래스의 상속
- Thread 클래스를 상속받는 클래스 A를 정의
- 여기서 run( ) 메소드를 재정의
- A 유형의 객체를 생성하고 시작시킴
예) class MyThread1 extends Thread {
public void run( ) {
for (int i = 0; i < 10; i++)
System.out.println(getName( ));
}
}
public class ThreadTest1 {
public static void main(String args[ ]) {
Thread t1 = new MyThread1( ); t1.start( );
Thread t2 = new MyThread1(); t2.start();
System.out.println("main");
}
}

∙ 스레드 생성 방법2 : Runnable 인터페이스를 구현
- Runnable 인터페이스를 구현하는 클래스 B를 정의
- 여기서 run( ) 메소드를 구현
- 스레드 객체를 생성할 때, B 유형의 객체를 인자로 전달
- Runnable 인터페이스를 구현한 클래스를 만들고, 이것의 객체를 Thread 생성자의 인자로 사용한다.
- Runnable 인터페이스에는 run() 메소드 하나만이 선언되어 있다.
- 아래 예에서 HelloRunnable 클래스는 다른 클래스를 상속받을 수도 있으므로 첫 번째 방법보다 유연성이 좋다.
예) class MyThread2 implements Runnable {
public void run( ) {
for(int i = 0; i < 10; i++)
System.out.println(Thread.currentThread( ).getName( ));
}
}
public class ThreadTest2 {
public static void main(String[ ] args) {
Thread t1 = new Thread(new MyThread2( ), "thd0"); t1.start();
Thread t2 = new Thread(new MyThread2(), "thd1"); t2.start();
System.out.println("main");
}
}

∙ 스레드 실행
- 다중 스레드 프로그램의 실행 결과를 예측할 수 없음
- 실행 결과는 매번 다를 수 있음
- 각 스레드는 정해진 순서 없이 독립적으로 실행됨
- main 스레드는 다른 스레드와 무관하게 종료됨

∙ 스레드의 상태
- 스레드 객체를 통해 start()가 호출되면 스레드의 실행이 시작된다.
- 스레드의 실행은 run() 메소드의 실행이며 run()이 종료되면 스레드도 종료된다.
- 보통 1 개의 CPU 를 사용하여 여러 스레드가 동시에 수행되기 때문에 스레드는 CPU 를 얻어 실행되고 최종적으로 종료될 때까지 여러 상태 변화를 겪는다.
가. Startable 상태:스레드 객체가 생성되었으나 start() 메소드가 실행되기 직전의 상태이다.
나. Runnable 상태:start() 메소드가 호출되었고 CPU 자원의 획득을 기다리는 상태이다.
다. Running 상태:실제 CPU 를 얻어 실행 중인 상태이다. Runnable 상태에서만 Running 상태로 들어갈 수 있다.
라. Not Running 상태:Running 상태에서 실행 도중에 CPU 자원을 잃고 중단된 상태이다. (Blocked, Waiting, Timed_Waiting)
마. Dead 상태:run() 메소드가 종료되어 스레드가 종료된 상태이다.

- Running 상태에서 sleep(), join() 또는 wait() 메소드를 실행하면 Not Running 상태로 바뀐다. Running 상태에서 yield() 메소드를 실행하면 Runnable 상태로 바뀐다. wait()에 의해 NotRunning 상태로 들어간 스레드는 notify()에 의해 Runnable 상태로 바뀔 수 있다.

∙ 스레드의 상태 제어와 메소드
- 스레드에는 우선순위가 주어지는데 기본적으로 그것을 생성시켜 준 부모 스레드의 우선순위와 같다.
- 다음은 Thread 클래스에서 정의되어 있는 스레드의 상태 제어와 관련된 메소드이다.
가. public final void setPriority(int newPriority):this 스레드의 우선순위를 변경한다. 높은 우선순위를 가지는 스레드가 CPU 를 얻을 확률이 높다.
나. public static void sleep(long millis) throws InterruptedException:현재 실행중인 스레드가 정해진 시간 동안 실행을 멈추고 NotRunning 상태로 들어간다.
다. public static void yield():현재 실행중인 스레드가 자발적으로 잠시 실행을 멈추고 Runnable 상태로 들어간다. CPU 를 다른 스레드에게 양보하는 것이다.
라. public final void join() throws InterruptedException:this 스레드가 종료될 때까지 기다린다. 현재 실행중이었던 스레드는 NotRunning 상태로 들어간다.
마. public void interrupt():this 스레드를 인터럽트시킨다. this 스레드가 wait(), join(), sleep()에 의해 중단된 상태였다면 그 상태에서 깨어나 Runnable 상태가 된다.
- Object 클래스에서 정의된 다음 메소드도 스레드의 상태 제어와 관련이 있다.
가. public final void wait(long millis) throws InterruptedException:현재 실행중인 this 스레드를 정해진 시간 동안 중지시킨다. 다른 스레드가 이 스레드에 대해 notify() 메소드를 실행시켜 주면 이 스레드가 깨어날 수 있다. 이 메소드는 synchronized 메소드의 내부에서만 호출될 수 있다.
나. public final void notify():wait() 호출에 의해 중단되었던 스레드를 깨워준다. 이 메소드는 synchronized 메소드의 내부에서만 호출될 수 있다.

∙ 스레드 간의 간섭
- 여러 스레드가 하나의 자원을 공유하여 동시에 사용하면 데이터의 무결성에 문제가 생기는데 이것을 간섭이라고 한다.
- 두 사람이 독립적으로 하나의 공유 문서를 수정한다면 문제가 생길 것이다.
- 간섭은 서로 다른 스레드가 동일한 데이터를 다룰 때 결과가 왜곡되는 것이다.
- c 의 값을 증가시키려면 c 의 값을 읽고, 증가된 값을 계산하고, 결과를 저장하는 단계를 거친다.
- 스레드 A 가 increment()를 실행하고 거의 동시에 스레드 B 가 decrement()를 실행할 때 다음과 같은 과정이 발생할 수도 있다.
1. 스레드 A 가 c 의 값 0 을 읽는다.
2. 스레드 B 가 c 의 값 0 을 읽는다.
3. 스레드 A 가 값을 증가시켜 1 을 계산한다.
4. 스레드 B 가 값을 감소시켜 -1 을 계산한다.
5. 스레드 A 가 1 을 c 에 저장한다.
6. 스레드 B 가 –1 을 c 에 저장한다.
- 한 번씩 증가와 감소가 수행되면 최종적으로 0 이 저장되어야 하나 결과적으로 스레드 A 가 수행한 작업이 무효가 되었다.
- 그림 6 에는 하나의 Counter 객체를 공유하는 두 스레드가 존재한다.
- 한 스레드는 10,000 번의 증가를 수행하고 다른 스레드는 10,000 번의 감소를 수행한다.
- 스레드 간섭으로 인해 공유자원의 최종 필드 값으로 0 을 보장할 수 없고 실행할 때마다 결과가 다를 것이다.

∙ 스레드의 동기화
- 스레드 동기화란 여러 스레드가 하나의 객체에 접근할 때, 객체의 데이터가 일관성을 유지하도록 한 순간에 하나의 스레드만이 공유 객체에 접근할 수 있게 하는 것이다.
- Java 언어는 동기화를 위해 synchronized 메소드 또는 synchronized 블록을 제공한다.
- 한 스레드가 공유된 객체의 synchronized 메소드를 실행 중이라면 다른 스레드가 동일 객체에 접근할 수 없다. 따라서 한 번에 한 스레드만이 공유자원에 접근할 수 있게 한다.
- 방법 : 상호 배제 원칙

∙ synchronized 메소드
- 한번에 하나의 스레드에 의해서만 실행 가능
- synchronized 메소드를 실행하려면 메소드를 호출한 객체에 대한 lock을 얻어야 함
- 다른 스레드는 동일 객체에 대해 synchronized 메소드를 실행할 수 없게 됨
- public synchronized void func( ) { ... }
- 일부 블록만 동기화하는 것도 가능함
- synchronized (객체) { ... } // 객체는 공유자원으로 대개 this


제 7 장 java.io 패키지와 스트림

∙ 스트림
- 스트림은 순서가 있고 길이가 정해져 있지 않은 일련의 데이터를 의미한다.
- 데이터 생산자(소스)와 데이터 소비자 사이의 데이터가 지나는 통로
- 데이터 소스(또는 생산자)로부터 읽기 위해 입력 스트림을, 데이터 목적지(또는 소비자)에 쓰기 위해 출력 스트림을 사용한다.
- Java 언어에서 모든 입출력은 스트림을 통해 이루어짐
- 스트림을 통해 입출력을 제어함, 입력 스트림은 데이터 소스를 의미, 출력 스트림은 데이터 목적지를 의미
- 스트림을 이용하면 데이터 소스나 데이터 목적지의 종류와 상관없이 동일한 방법으로 프로그램을 작성할 수 있다.
- 데이터 소스와 데이터 목적지는 디스크 파일, 주변 장치, 네트워크 소켓, 배열, 또는 프로그램이 될 수 있다.
- 프로그램은 입력 스트림으로부터 데이터를 읽을 수 있음 (데이터 소스가 설정되어야 함)
- 프로그램은 출력 스트림으로 데이터를 쓸 수 있음 (데이터 목적지가 설정되어야 함)

- 스트림이 지원하는 데이터의 종류는 바이트, 문자, 객체가 있다.
- 바이트 스트림은 byte 단위로 데이터를 다룸 (xxxInputStream과 xxxOutputStream)
- 캐릭터 스트림은 char 단위로 데이터를 다룸 (xxxReader과 xxxWriter)
- 기본 스트림은 입출력 기능을 제공하는 스트림
- 보조 스트림은 입출력 외의 추가 기능을 제공하는 스트림

∙ 스트림 관련 클래스
- java.io 패키지


∙ Java 의 입력 스트림과 출력 스트림
- 입력 스트림을 입력 데이터의 소스, 출력 스트림을 출력 데이터의 목적지로 생각할 수 있다.
- 바이트 단위 입력 스트림의 루트 클래스는 InputStream 클래스이고 출력 스트림의 루트 클래스는 OutputStream 이다. 문자 단위 입력 스트림의 루트 클래스는 Reader 이고, 출력 스트림의 루트 클래스는 Writer 이다.
- InputStream 과 OutputStream 은 추상 클래스로 프로그램에서 스트림 객체를 생성할 때는 이것의 하위 클래스를 사용해야 한다.

∙ 싱크 스트림과 처리 스트림
- 싱크 스트림은 데이터의 전달 기능만 담당하는 스트림이다.
- 프로그램에서는 입출력 장치의 종류에 따라 다른 싱크 스트림 클래스를 사용한다.
- 파일로부터의 입력이 필요할 때 FileInputStream 이나 FileReader 클래스를 사용하고 출력할 때는 FileOutputStream 이나 FileWriter 클래스를 사용한다.
- 처리 스트림은 데이터의 처리와 가공 기능을 가진 스트림이다.
- 처리 스트림만으로는 데이터를 주고받을 수 없다.
- 스트림에서 데이터를 처리하는 방법으로는 버퍼링, 파이핑 또는 객체직렬화 등이 있다.
- 버퍼링 기능을 제공하는 바이트 단위 입출력 스트림은 BufferedInputStream 과 BufferedOutputStream 클래스이다.
- 버퍼링 기능을 제공하는 문자 단위 입출력 스트림은 BufferedReader 또는 Buffered-Writer 클래스이다.

∙ 스트림 사용하기
- 어떤 스트림 클래스를 사용할 것인가? 입력? 출력?
- 데이터 생산자와 소비자를 결정 (기본 스트림을 반드시 사용해야 함)
- 문자 단위? 바이트 단위?
- 보조 스트림이 필요한가? 보조 스트림은 기본 스트림과 함께 사용되어야 함
1. 입력용인지 출력용인지를 결정
2. 데이터 생산자 또는 데이터 소비자의 종류를 결정
3. 바이트 단위인지 문자 단위인지를 결정
4. 데이터의 특별한 처리가 필요한지를 결정

∙ 바이트 스트림
- 1 바이트의 입출력을 수행하는 스트림이다.
- 모든 바이트 스트림 클래스는 InputStream 이나 OutputStream 의 서브 클래스이다.
- InputStream 클래스의 ‘int read()’ 메소드는 한번에 1 바이트를 읽고 int 값을 리턴한다. 스트림의 끝에 도달하면 –1 을 리턴한다.
- OuputStream 클래스의 ‘void write(int)’ 메소드는 1 바이트를 출력 스트림으로 내보낸다.
- 스트림이 더 이상 필요하지 않으면 close 하는 것이 중요하다.
- 읽기나 쓰기 연산은 IOException 예외를 발생시킬 수 있으므로 close() 메소드를 호출하는 문장을 finally 블록에 위치시키는 것이 좋다.

∙ 보조 스트림
- 기본 스트림의 성능을 높이거나 보조 기능을 제공하는 스트림
- 입출력 기능을 직접 수행하지는 못함
- 보조 스트림을 생성할 때 기본 스트림을 매개 변수로 이용함 (기본 스트림은 항상 있어야 함)
- 프로그램에서는 보조 스트림을 사용해 입출력
예) FileInputStream fis = new FileInputStream( );
BufferedInputStream bis = new BufferedInputStream(fis);

∙ 보조 스트림의 종류
- 버퍼링 기능의 제공 : BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter
- Java의 기본 자료형을 그대로 읽기/쓰기 위한 기능의 제공 : DataInputStream, DataOutputStream
- 다양한 출력 양식의 제공 : PrintStream, PrintWriter
- 텍스트 파일을 라인 단위로 읽는 메소드를 제공 : LineNumberReader
- 바이트 스트림과 캐릭터 스트림의 호환 : InputStreamReader, OutputStreamWriter

∙ LineNumberReader 클래스
- 텍스트 파일을 라인 단위로 읽어 들이는 메소드 제공
- BufferedReader의 서브 클래스
- 주요 메소드 : String readLine( ), int getLineNumber();

∙ InputStream 클래스
- 입력용 바이트 스트림 클래스의 최상위 클래스
- 주요 메소드
가. abstract int read( ); // 입력 스트림으로부터 1바이트를 읽어 정수로 리턴함, 읽어들일 데이터가 없을 경우에는 -1 을 리턴한다. 읽는 도중 에러가 발생하면 IOException 을 던진다. abstract 메소드이므로 서브 클래스에서 구현되어야 한다.
나. int read(byte[ ] b); // 입력 스트림으로부터 읽어서 byte배열에 저장, 읽어 들인 바이트 개수를 리턴함
다. int read(byte[ ] b, int off, int len); // 입력 스트림으로부터 데이터를 읽어서 바이트 배열 b 에 저장하고 읽어들인 데이터의 byte 수를 리턴한다. off 는 읽은 데이터를 저장할 배열의 시작 위치이고 len 은 읽어들일 최대 길이이다.
라. int available( ); // 다음 번 read()할 때 블로킹 없이 읽을 수 있는 데이터 길이, 입력 스트림에서 블로킹 없이 바로 읽어들일 수 있는 데이터의 길이를 byte 단위로 리턴한다.
마. long skip(long n); // 입력 스트림에서 n바이트를 건너 뜀, n byte 를 건너뛰고 실제 건너뛴 byte 수를 리턴한다.
바. void close():현재 스트림을 닫고 스트림과 관련된 자원을 시스템에 되돌려준다.
사. void mark(int readlimit):스트림에서 현재 위치를 표시한다. mark()로 표시한 후 reset() 메소드를 호출하면 스트림의 현재 위치가 재설정된다. 만일 표시 후에 readlimit 바이트를 초과하는 데이터를 읽어들이면 reset() 메소드를 호출하더라도 표시된 위치로 되돌아갈 수 없다.
아. void reset():mark()를 호출한 뒤에 사용할 수 있으며 mark()로 표시한 위치로 스트림에서 현재 위치를 이동시킨다.

∙ OutputStream 클래스
- 출력용 바이트 스트림 클래스의 최상위 클래스
- 주요 메소드
가. void write(int b); // 1바이트의 데이터를 출력 스트림으로 보냄
나. void write(byte[ ] b); // byte 배열의 내용을 출력 스트림으로 보냄
다. void write(byte[ ] b, int off, int len); // 바이트 배열 b 의 내용을 출력 스트림으로 내보낸다. off 는 배열 b 에서 실제 출력할 내용의 시작 위치를 의미한다. 즉 write(b)는 write(b, 0, b.length)와 같다.
라. void close():출력 스트림을 닫고 할당받은 자원을 시스템에 되돌려준다.
마. void flush():출력 스트림의 버퍼에 남아 있는 데이터를 데이터 소비자에게 강제로 내보낸다.
사. abstract void write(int b):b 의 데이터를 출력 스트림으로 보낸다. 1 byte 데이터를 쓰는 메소드이기 때문에 b 에 들어 있는 상위 24 비트는 무시된다.
- 2 바이트 Unicode 단위로 입출력을 수행하는 스트림이다.
- 모든 문자 단위 스트림 클래스는 Reader 나 Writer 의 서브 클래스이다. Reader 와 Writer 는 InputStream 이나 OutputStream 클래스와 마찬가지로 추상 클래스이므로 프로그램에서 객체를 생성할 때는 서브 클래스를 이용한다.

∙ Reader 클래스
- 입력용 캐릭터 스트림 클래스의 최상위 클래스
- 추상 클래스이며 이것의 하위 클래스는 xxxReader
- 주요 메소드
가. int read(); // 1개 문자(2바이트)를 읽어 리턴함
나. int read(char[] cbuf); // 문자를 읽어 char 배열에 저장함, 읽어 들인 문자의 개수를 리턴함
다. boolean ready(); // 스트림이 읽힐 준비가 되었으며 true를 리턴함
라. abstract void close(); // 입력 스트림을 닫고 자원을 반납함

∙ Writer 클래스
- 출력용 캐릭터 스트림 클래스의 최상위 클래스
- 추상 클래스이며 이것의 하위 클래스는 xxxWriter
- 주요 메소드
가. void write(int c); // 1개의 문자(2바이트)를 출력함
나. void write(char[ ] cbuf);
다. void write(String str)
라. voidwrite(String str, int off, int len);
마. abstract void close();

∙ InputStreamReader 클래스
- 바이트 스트림을 캐릭터 스트림으로 바꾸기 위한 클래스 (바이트 단위로 읽은 후 문자로 바꾸어 처리함)
- 생성자는 InputStreamReader(InputStream in)
- int read(); // 1개 문자를 읽어 리턴함
예) InputStreamReader isr = new InputStreamReader(System.in);
try {
while((i = isr.read( )) != '끝') {
System.out.print((char) i);
}
} catch ( … … //

∙ File 클래스
- 파일과 디렉토리의 추상적 경로를 표현한 클래스이다.
- 절대 경로는 파일을 찾기 위한 완전한 이름으로 윈도우 계열에서는 "드라이브 문자:\\”로 시작한다. 예 “C:\\windows\\notepad.exe”
- 상대 경로는 현재 디렉토리를 기준으로 해석되는 경로이다.
- File 클래스는 파일의 입출력 기능을 제공하지 않는다. 이름과 경로의 조회, 파일 또는 디렉토리인지 검사, 파일이나 디렉토리의 생성과 삭제 기능 등을 제공한다.

∙ File 클래스의 생성자
가. File(String pathname):pathname 경로명을 가지는 파일이나 디렉토리를 표현하는 File 객체를 생성한다. File myFile = new File("c:\\temp\\data.txt");
나. File(String parent, String child):parent 를 부모 디렉토리로 하는 파일 또는 디렉토리를 표현하는 File 객체를 생성한다.

∙ File 클래스의 메소드
가. boolean exists():파일이나 디렉토리가 존재하는지 검사한다.
나. boolean isDirectory(), boolean isFile():객체가 디렉토리인지 또는 파일인지 검사한다.
다. String getName():객체의 이름을 리턴한다. 이름은 경로에서 마지막 이름이다.
라. boolean createNewFile():파일이 존재하지 않으면 생성시킨다.
마. boolean delete():파일 또는 빈 디렉토리를 삭제한다.
바. boolean mkdir(), boolean mkdirs():하나의 디렉토리 또는 경로상의 모든 디렉토리를 생성한다.
사. String[] list(), File[] listFiles():디렉토리에 존재하는 파일과 서브 디렉토리들을 String 배열로 또는 File 객체들의 배열로 리턴한다.
아. String getParent(), File getParentFile():객체의 부모 디렉토리를 String 또는 File 로 리턴한다.
자. String getPath( ), long length( )
차. static File[ ] listRoots( ); // 루트 디렉터리들을 File 배열로 반환

∙ RandomAccessFile 클래스
- 파일에 대해 읽기나 쓰기 연산을 지원하는 클래스이다.
- 파일의 내용에 대해 랜덤 액세스를 허용한다. 즉 읽거나 쓰는 위치를 임의로 변경할 수 있다.
- 파일을 액세스하기 위해 파일을 오픈하고, 특정 위치로 파일 포인터를 옮기고, 읽기 또는 쓰기를 수행한다.
- 파일 포인터에서 시작하여 바이트 단위로 읽기 또는 쓰기를 수행할 수 있다.
- 읽거나 쓴 바이트 수만큼 파일 포인터가 이동한다.
- 파일을 데이터 생산자로 하는 입력스트림 또는 파일을 데이터 소비자로 하는 출력 스트림과 유사하다.
- 파일의 임의 위치에서 읽기/쓰기가 가능 (파일을 오픈하고, 위치를 지정하고, 읽기/쓰기를 함)
- 읽고 쓰는 위치는 파일 포인터가 가리킴
- byte 단위로 읽고 쓰며, 파일 포인터가 이동됨 (랜덤 엑세스 파일을 커다란 byte 배열로 볼 수 있음)

∙ RandomAccessFile 클래스의 생성자
가. RandomAccessFile(File file, String mode), RandomAccessFile(String file, String mode):File 객체나 String 으로 주어진 파일을 읽기 또는 쓰기 위해 랜덤 액세스 파일 스트림을 생성한다. mode 가 “r”이면 읽기 전용으로 “rw”이면 읽기와 쓰기를 위해 파일을 오픈하는 것이다.

∙ RandomAccessFile 클래스의 메소드
가. void seek(long pos):pos 에 지정된 위치로 파일 포인터를 이동시킨다. 파일 포인터는 byte 단위로 표시된다.
다. int read(byte[] b), int read(byte[] b, int off, int len):최대 b.length 바이트를 배열 b 에 읽어들이거나 파일로부터 최대 len 바이트를 읽어서 배열의 off 위치에서부터 저장한다. 읽을 데이터가 없으면 -1 을 리턴한다.
라. void write(byte[] b), void write(byte[] b, int off, int len):지정된 배열에서 b.length 또는 len 바이트를, 현재 파일 포인터의 위치 또는 len 의 위치부터 시작하여, 파일에 쓴다.
마. void close():랜덤 액세스 파일을 닫고 관련 자원을 모두 돌려준다.

∙ 파일을 다루는 클래스
- FileInputStream과 FileReader 는 데이터 생산자가 파일인 입력용 싱크 스트림이다.
- FileOutputStream과 FileWriter 는 데이터 소비자가 파일인 출력용 싱크 스트림이다.

∙ FileInputStream과 FileOutputStream 클래스
- 파일로부터 데이터를 읽기/쓰기 위한 입력/출력용 기본 스트림
- 바이트 단위의 입력/출력
- FileInputStream 클래스의 생성자 : 기존 파일과 연결된 입력 스트림 객체를 생성
예) FileInputStream(File file), FileInputStream(String name)
- FileOutputStream 클래스의 생성자 : 파일을 만들고, 이것과 연결된 출력 스트림 객체를 생성
예) FileOutputStream(Stringfile), FileOutputStream(File file, boolean append)

∙ FileReader와 FileWriter 클래스
- 텍스트 파일을 다루기 위한 기본 스트림
- 문자 단위의 입력/출력
- 생성자 : FileReader(File file); FileReader(String fileName); FileWriter(File file); FileWriter(String fileName); FileWriter(File file, boolean append);

∙ Console 클래스
- 콘솔 입출력을 제공하는 클래스 ; 키보드 입력과 화면 출력을 편리하게 지원
- 명령 프롬프트 창에서 실행해야 함
- System.console( )을 사용하여 콘솔 객체를 생성함
- 주요 메소드
가. String readLine(); // 한 라인을 읽음
나 char[ ] readPasssword(); // 입력할 때 화면에 보이지 않음

∙ 버퍼링을 제공하는 클래스
- 버퍼링은 입출력 효율을 높이기 위해 데이터를 모았다가 한꺼번에 입출력하는 것이다.
- 입력 스트림은 버퍼에서 데이터를 읽는다.
- 출력 스트림은 데이터를 버퍼에 쓴다.
- 입력시 버퍼가 비어 있거나, 출력시 버퍼가 꽉 차면 실제 입출력을 수행한다.
- 버퍼링을 제공하는 4 개의 클래스로 BufferedInputStream, BufferedOutputStream, BufferedReader 및 BufferedWriter 클래스가 존재한다.
- 객체를 생성할 때 생성자의 인자로 싱크 스트림을 전달해야 한다. 즉 싱크 스트림을 감싸서 생성해야 한다.
- 라인 단위 입력을 위해 BufferedReader 는 ‘String readLine()’을, 라인 단위 출력을 위해 PrintWriter 는 ‘void println(String)’을 제공한다.

∙ PrintStream 과 PrintWriter 클래스
- 다른 싱크 스트림을 감싸서 사용해야 하는 처리 스트림이다.
- 다양한 출력 양식을 제공하는 ‘format(String format, Object... args)’ 메소드를 제공한다.
- 객체를 생성할 때 autoFlush 속성을 true 로 하면 버퍼가 차거나 필요한 경우 버퍼를 flush 한다.

∙ InputStreamReader 와 OutputStreamWriter 클래스
- InputStreamReader 는 바이트 스트림으로 읽어들인 데이터를 지정된 ‘charset’으로 디코딩하여 문자열로 변환시키는 기능을 한다. 즉 바이트 스트림을 문자 스트림으로 변환한다.
- OutputStreamWriter 는 반대로 문자단위 출력 스트림을 바이트 출력 스트림으로 변환해준다.


제 8 장 AWT 프로그래밍의 기본

∙ 그래픽 사용자 인터페이스(GUI)
- 그래픽 요소를 이용하여 사용자가 프로그램과 대화하는 방식의 인터페이스
- 텍스트 기반 or명령 행 인터페이스와 비교됨
- GUI 프로그래밍을 위해 필요한 것
가. GUI 컴포넌트 : 윈도우, 메뉴, 버튼, 레이블, 콤보박스, 체크박스, 텍스트필드, 스크롤바 등
나. 컨트롤, 컨테이너와 배치 관리자
다. 이벤트 발생과 처리 : 사용자 상호작용

∙ AWT
- AWT 는 Abstract Window Toolkit 의 약자이며 JFC(Java Foundation Classes)의 일부이다.
- JFC(Java Foundation Class) 는 Java 언어로 GUI(graphical user interface) 프로그래밍을 제공하기 위한 표준 API 이다. GUI를 만들거나 그래픽 처리를 위한 클래스 라이브러리, AWT, Swing, Java2D, 룩앤필 지원 API 등을 제공 (JavaFX, 3D, Sound, Image 관련 API도 있음)
- AWT는 자바에서 처음 제공한 GUI용 API
- 운영체제의 윈도우 시스템을 사용함
- 중량 컴포넌트로 외양이 운영체제마다 다름
- 주 패키지는 java.awt

∙ java.awt
- java.awt 패키지는 사용자 인터페이스를 만들고 그래픽 처리나 이미지 작업을 위한 모든 클래스를 포함한다.
- java.awt 패키지에는 컴포넌트, 배치 관리자, 그래픽 처리와 관련된 클래스들을 포함한다.
- 윈도우, 버튼 또는 스크롤바와 같이 화면상에 보이는 사용자 인터페이스 객체를 컴포넌트라고 한다.
- AWT 의 컴포넌트들은 클래스 형태로 제공된다.

∙ 컴포넌트와 이벤트
- 사용자가 컴포넌트를 다룰 때 어떤 컴포넌트는 이벤트를 발생시킬 수 있다.
- 이벤트를 표현하는 클래스는 AWTEvent 와 그것의 서브 클래스들이다.

∙ 윈도우 프로그램 만들기
- AWT 프로그래밍을 하려면 java.awt 패키지를 import 해야 한다.
- Frame 클래스는 Window 클래스의 서브 클래스로 컨테이너이며 제목과 경계(또는 테두리)를 가진다.
- 프레임에 ‘다시 그리기’ 이벤트가 발생되면 paint() 메소드가 자동으로 호출된다.
- 이러한 메소드를 콜백 메소드라 하며 시스템에 의해 색칠하기가 유발된 경우 자동으로 호출되는 메소드이다.
- Window 클래스에서 상속된 paint() 메소드가 MyFrame 클래스에서 재정의되었다.
- Frame 클래스를 상속받아 클래스를 정의 (프레임은 보더, 타이틀, 최소/최대/종료 버튼과 같은 윈도우) 장식을 가짐
- 생성자에서 윈도우의 주요 속성을 지정
가. 제목을 인자로 받아 지정 super(title);
나. 가로와 세로 크기를 지정 setSize(400, 300);
다. 화면에 표시 setVisible(true);
라. 최상위 수준 컴포넌트에 지정함
- paint()메소드는 ‘다시 그리기’이벤트가 발생할 때 자동 호출되는 메소드

∙ AWT 패키지의 GUI 컴포넌트
- AWT 의 컴포넌트들은 클래스 형태로 제공된다.
- java.awt.Component 클래스는 추상 클래스로 모든 AWT 컴포넌트들의 루트 클래스이다. 단, 메뉴와 관련되어 있는 컴포넌트들의 루트 클래스는 java.awt.MenuComponent 이다.
- Component 클래스에는 컴포넌트들이 사용할 기본 메소드들이 정의되어 있다.
- AWT 의 컴포넌트들은 컨트롤과 컨테이너로 분류된다.


∙ 컴포넌트 클래스 계층구조


∙ Component 클래스
- 메뉴를 제외한 AWT 컴포넌트들의 최상위 추상 클래스
- 이름, 기준 좌표, 크기, 배경색/전경색, 폰트, visible 속성, Graphics 객체를 가짐
- 컴포넌트의 기본 메소드들을 정의 : void paint(Graphics), Container getParent()

∙ 컨테이너
- 다른 컴포넌트를 포함하는 컴포넌트 : 컨트롤은 컨테이너에 포함되어야 함
- 최상위 클래스는 추상 클래스인 Container : 하위 컨테이너를 위한 기본 메소드를 제공
- 자식 컴포넌트들의 배치(위치와 크기)를 담당 : 기본 배치 관리자를 가짐
예) void setLayout(LayoutManager lm) // 배치 관리자를 변경하는 방법
- 자식 컴포넌트를 리스트 형태로 관리함 : 컨테이너에 추가되는 컴포넌트들은 순서지정이 없다면 맨 뒤에 들어감
- Container 클래스의 자식을 추가하는 메소드
가. Component add(Component comp) // 마지막에 추가
나. Component add(Component comp, int index) // 지정된 위치(index)에 추가
다. void add(Component comp, Object􀀁constraints) // 마지막에 추가, constraint는 배치 관리자에게 주는 정보
- 최상위 수준 컨테이너 ; 컴포넌트 포함 관계에서 루트가 되는 컨테이너 (모든 GUI 컴포넌트는 1개의 컨테이너에 포함됨, Frame, Window, Dialog 등)
- 일반 컨테이너 : Panel, ScrollPane

∙ Container 클래스
- 컨테이너 용도의 클래스들 가운데 루트 클래스이다.
- 컨테이너는 컨트롤이나 다른 컨테이너를 포함할 수 있는 GUI 컴포넌트이다.
- 포함하는 컨테이너를 부모 컴포넌트, 포함되는 컴포넌트를 자식 컴포넌트라고 한다.
- 컨테이너의 포함 관계는 계층적 구성을 가진다.
- 모든 컨트롤은 하나의 컴포넌트에 포함되어야 화면에 나타날 수 있다.
- 컨테이너 클래스는 자식 컴포넌트의 크기와 위치를 정하여 배치해 주는 기능을 가진다.
- 모든 컨테이너는 기본 배치 관리자를 가진다.
- Window 와 Frame 의 기본 배치 관리자는 BorderLayout 이다.
- 기본 배치 관리자를 사용하지 않는 경우에는 수동으로 자식 컴포넌트들을 배치하여야 한다.
- 컨테이너에 포함되는 컴포넌트들은 순서가 있는 리스트의 형태로 관리된다.
- Container 클래스는 자식 컴포넌트들을 다루고 관리하는 데 필요한 기본 메소드들을 제공한다.

∙ Container 클래스의 메소드
가. Component add(Component comp), Component add(Component comp, int index):컴포넌트 comp 를 현재 컴포넌트의 자식 컴포넌트 리스트에 추가한다. index 는 리스트상에서의 위치를 의미한다. index 가 -1 이면 맨 뒤에 추가한다.
나. void add(Component comp, Object constraints):두 번째 인자는 배치 관리자에게 주는 정보로, 배치 관리자로 BorderLayout 을 사용할 때 두 번째 인자를 BorderLayout.EAST 로 하면 좌측에 배치한다.
다. Component add(String name, Component comp):첫 번째 인자는 배치관리에 사용되는 이름으로 BorderLayout 에서 add(“Center”, msgPanel) 또는 CardLayout 에서 add(“1”, new Label())과 같이 사용한다.
라. Component getComponentAt(Point p):주어진 좌표에 위치한 자식 컴포넌트를 리턴한다.
마. Component getComponent(int n):자식 리스트에서 지정된 위치에 있는 자식 컴포넌트를 리턴한다. n 이 0 이면 맨 앞에 있는 컴포넌트이다.
바. void setLayout(LayoutManager lm):배치 관리자를 설정한다.
사. void validate():자식 컴포넌트가 추가/삭제되거나 배치 정보에 변동이 생겼을 때 자식 컴포넌트들을 다시 재배치시킨다.
아. Insets getInsets():경계 영역에 대한 정보를 리턴한다.
자. void paint(Graphics g):컨테이너 내부를 색칠한다.

∙ 컨트롤
- 컨트롤은 사용자와의 실제 상호작용에 사용되는 GUI 컴포넌트를 의미한다.
- AWT 에서 컨트롤에 해당하는 클래스는 Button, Canvas, Checkbox, Choice, Label, List, Scrollbar, TextArea, TextField 와 Menu, MenuItem, MenuBar 등이다.

∙ 컨테이너와 배치 관리자
- 컨테이너는 Container 클래스와 그것의 서브 클래스에 해당한다.
- 컨테이너는 사용자와의 의사소통에 직접 간여하지 않고 다른 컴포넌트 또는 다른 컨테이너를 포함하고 있는 컴포넌트이다.
- 컨테이너는 그것에 포함된 컴포넌트들의 배치를 제어하기 위한 배치 관리자를 가진다.
- Window, Frame, FileDialog, Panel, ScrollPane 클래스 등이 컨테이너에 해당된다.

∙ Window 클래스와 Frame 클래스
- 컨테이너에 해당하는 클래스들로 새로운 창을 띄울 때 사용되는 최상위 계층 컨테이너이다.
- 모든 GUI 프로그램은 Window 나 Frame 클래스의 객체를 최소한 하나 이상 가져야 한다.

∙ Window 클래스
- 제목이나 테두리가 없고 메뉴바를 가지지 못하는 최상위 계층 윈도우이다.
- 다른 컨테이너의 사각영역에 포함될 수 없음
- Window 객체를 생성시키려면 Frame 이나 Dialog 와 같은 것을 소유자로 지정해야 한다.
- 기본 배치 관리자는 BorderLayout 이다.
- 윈도우가 열리거나 닫히거나 할 때 WindowEvent 를 발생시킬 수 있다.
- 생성자 : Window(Frame owner), Window(Window owner)

∙ Frame 클래스
- 테두리와 제목이 있으며 메뉴바를 가질 수 있는 최상위 계층 컨테이너이다.
- 부모 컴포넌트를 가지지 못함
- 계층 구조에서 Window의 서브 클래스
- 기본 배치 관리자는 BorderLayout 이다.
- 생성자 : Frame(), Frame(String title)

∙ Panel 클래스
- 가장 단순한 컨테이너로 기본 배치 관리자는 FlowLayout 이다.
- 컴포넌트들을 분리 배치하고 각각에 서로 다른 배치 관리자를 사용할 때 이용된다.
- 다른 컨테이너에 포함되어야 하며, 다른 자식 패널이나 자식 컴포넌트를 포함할 수 있다.
- 그림 1 의 예에서 Frame 은 Label 컴포넌트를 포함하는 Panel 과 3 개의 Button 을 포함하는 Panel 을 포함하고 있다.

∙ ScrollPane 클래스
- 자동으로 스크롤 기능을 제공하는 클래스이다.
- 하나의 자식만을 포함할 수 있다.
- 여러 컴포넌트를 포함시키려면 하나의 Panel 을 포함시킨 후, Panel 에 컴포넌트를 포함시킨다.
- 특별한 배치 관리자를 사용하며 바꿀 수 없다.
- 스크롤 기능을 사용하면 자식 컴포넌트 전체가 보이지 않고, 일부만 보일 수 있으며 view port 란 ScrollPane 에서 스크롤바를 제외하고 자식 컴포넌트가 차지하는 공간을 뜻한다.
- ScrollPane 클래스의 메소드는 다음과 같다.
가. Adjustable getHAdjustable(), Adjustable getVAdjustable():수평/수직 스크롤바의 상태를 표현하는 객체를 리턴한다.
나. Dimension getViewportSize():ScrollPane 에서 보이는 view port 의 크기를 리턴한다.
다. int getHScrollbarHeight(), int getVScrollbarHeight():수평/수직 스크롤바의 길이를 리턴한다.
라. Point getScrollPosition():view port 의 (0,0)에 해당하는 좌표를 리턴한다.
마. void setScrollPosition(Point p):지정된 좌표가 view port 의 (0,0)에 위치하도록 스크롤한다.

∙ 익명 클래스
- 아래 프로그램을 실행시켜 보면 Window 는 단지 사각형으로 보이며, 소유자로 지정된 Frame 객체가 종료되면 함께 종료된다.
- 밑줄 친 부분은 익명 클래스가 정의된 것인데, 여기서는 익명 클래스가 Window 의 서브 클래스가 되며 paint() 메소드를 재정의하고 있다.

∙ 메뉴 클래스의 계층 구조


∙ 풀다운 메뉴의 사용
- MenuBar 클래스는 Frame 에 붙여지는 풀다운 메뉴를 표현한다.
- 풀다운 메뉴는 윈도우의 제목 표시줄 밑에 붙는 것을 말한다.
- 프레임에 메뉴바를 붙일 때 Frame 클래스의 setMenuBar(MenuBar)를 이용한다.
- MenuBar 에는 Menu 를 붙일 수 있다.
- Menu 에는 MenuItem 이나 서브 메뉴로서 Menu 를 붙일 수 있다.
- 제목 표시줄 밑의 메뉴바를 가짐
- 메뉴 만들기 과정
가. MenuBar 객체 생성
나. MenuBar에 추가할 Menu객체를 생성
다. Menu에 추가할 또다른 서브 Menu객체나 MenuItem 객체를 생성하고 Menu에 붙임 - add()
마. 생성한 Menu를 Menubar에 추가 add()
바. 프레임에 MenuBar를 붙임 - setMenuBar()

∙ 팝업 메뉴의 사용
- 팝업 메뉴는 윈도우의 내부 영역에서 오른쪽 마우스 버튼을 클릭해 나타나는 메뉴이다. 컨테이너 내부에서 어디든 나타남
- PopupMenu 를 Frame 에 붙일 수 있다.
- PopupMenu 는 Menu 의 서브 클래스이다. 따라서 PopupMenu 에 Menu 가 붙을 수 있고 MenuItem 이 바로 붙을 수도 있다.
- 팝업 메뉴를 보이게 하려면 이벤트 처리를 통해서 show() 메소드를 호출해야 한다.
- 메뉴 만들기
가. PopupMenu 객체를 생성한다
나. PopupMenu에 MenuItem이나 서브 Menu객체를 추가
다. PopupMenu를 Frame에 추가
라. PopupMenu를 보이게 함 show()

∙ FileDialog 클래스
- 파일을 저장하거나 불러오기를 할 때 파일을 선택하기 위해 사용되는 대화상자이다.
- FileDialog 는 Modal 대화상자이기 때문에 사용자의 입력을 독점한다.
- 즉 이 대화상자를 닫기 전까지는 같은 프로그램의 다른 윈도우를 사용할 수 없다.
- FileDialog 는 Window 와 Dialog 의 서브 클래스이다.

∙ 컴포넌트를 수동으로 배치하기
- 자식 컴포넌트의 위치과 크기를 수동으로 설정하는 것이다.
- myContainer.setLayout(null)을 사용하여 컨테이너의 배치 관리자를 제거한 후 설정한다.
- 크기 지정에 setBounds() 또는 setSize()를, 위치 지정에 setLocation()을 이용한다.
- 부모 컴포넌트의 크기가 바뀔 경우 자식 컴포넌트의 위치와 크기를 재조정할 필요가 있다.

∙ 배치 관리자의 사용 (컴포넌트의 자동 배치)
- 배치 관리자를 사용하면 부모 컨테이너의 크기가 바뀔 때 자식 컴포넌트의 크기와 위치가 자동으로 재조정된다.
- 모든 컨테이너는 기본 배치 관리자를 가지며 그것에 따라 자식 컴포넌트를 자동으로 배치한다.
- setLayout(LayoutManager)를 사용하면 배치 관리자를 다른 것으로 변경시킬 수 있다.
- 일관성 있는 배치 관리 방법을 제공하는 클래스
- 모든 컨테이너는 기본 배치 관리자를 가짐 (배치 관리자를 변경할 수 있음)
- 자식 컴포넌트의 크기와 위치를 자동으로 조정함 (컨테이너의 크기가 바뀌면 자식 컴포넌트들의 크기와 위치가 자동 재조정됨)


∙ BorderLayout 클래스
- 북/남/동/서/중앙의 다섯 영역에 컴포넌트를 꽉 채우는 배치 관리자이다.
- 북/남은 수평으로, 동/서는 수직으로 펼쳐지며 나머지를 중앙이 채운다.
- 각 영역에는 하나의 컴포넌트만이 들어갈 수 있다.
- 컨테이너에 BorderLayout 을 사용하도록 지정하고 컴포넌트를 추가
- 컨테이너 크기를 확장하면 남북의 컴포넌트는 수평으로 동서는 수직으로 확장됨

∙ FlowLayout 클래스
- 자식 컴포넌트들을 한 줄씩 차례대로 왼쪽에서 오른쪽으로 일렬로 배치하는 역할을 한다.
- 한 줄이 다 차면 자동으로 다음 줄로 이동된다.
- 이 때 각 컴포넌트는 각각 preferred Size(선호크기, 최적합크기)로 배치된다.
- Panel 에 버튼을 추가할 때 자주 사용된다.
- FlowLayout(int align)을 사용하면 객체를 만들 때, 정렬방식을 정해줄 수 있다. 기본 정렬방식은 중앙 정렬이다.

∙ GridLayout 클래스
- 자식 컴포넌트들을 배치할 영역을 바둑판 형식으로 분할한 후 각 격자 안에 하나의 컴포넌트를 배치한다.
- 자식 컴포넌트들의 크기가 동일해진다.
- GridLayout(int rows, int cols) 생성자를 사용하여 행과 열의 개수를 지정한다.

∙ CardLayout 클래스
- 컨테이너에 포함된 컴포넌트들을 각각 하나의 카드로 간주하고 한 번에 하나의 카드만을 화면에 나타나도록 한다.
- next()를 이용하면 컨테이너에 들어간 순서대로 자식 컴포넌트를 보이게 할 수 있다.
- 컨테이너에 컴포넌트를 추가할 때 ‘add(String name, Component comp)’을 이용했다면 이름을 사용하여 자식 컴포넌트를 보이게 할 수 있다.
- 메소드
가. void first(Container parent) // 컨테이너의 첫 번째 카드를 보여줌
나. void next(Container parent)
다. void show(Container parent, String name) // add( )할 때 이름을 준 경우 사용


제 9 장 AWT 컨트롤 클래스와 이벤트 처리하기

∙ 컨트롤
- 사용자와의 실제 의사소통에 사용되는 GUI 컴포넌트를 의미한다.
- 메뉴와 관련된 컴포넌트도 포함된다.
- 모든 컨트롤은 반드시 컨테이너에 포함되어야 한다.

∙ 중량 컴포넌트와 경량 컴포넌트
- 컴포넌트들을 경량 컴포넌트와 중량 컴포넌트로 나눌 수 있다.
- AWT 에서 GUI 컴포넌트는 결국 운영체제 고유의 UI 컴포넌트, 즉 플랫폼에 종속적인 GUI 라이브러리를 이용한 peer 컴포넌트로 매핑된다.
- 이러한 방식의 컴포넌트를 중량 컴포넌트라 하며 수정 없이 다른 플랫폼에서 사용될 수 있으나, 모양이 다르게 표현될 수 있다.
- 반면 경량 컴포넌트는 운영체제, 플랫폼과 상관없이 Java 로 직접 처리되는 컴포넌트이다.
- 경량 컴포넌트는 플랫폼에 독립적이어서 항상 모양이 같게 표현된다.

∙ Button 클래스
- 제목(이름)이 달린 버튼을 표현하는 클래스이다.
- 버튼을 클릭했을 때 다양한 행동을 취하도록 프로그래밍할 수 있다.
- 생성자와 메소드는 다음과 같다.
가. Button(), Button(String label)
나. void setLabel(String label), String getLabel()

∙ Canvas 클래스
- 빈 사각 영역을 나타내는 클래스로 다른 컨테이너에 포함되어야 한다.
- 그림을 그리거나 문자를 출력하거나 사용자 정의 컨트롤을 만들 때 사용한다.

∙ Checkbox 클래스
- on(선택된 상태) 또는 off 상태를 가지는 체크박스를 표현한다.
- CheckboxGroup 을 이용하여 그룹으로 묶을 수 있으며 이때 하나만 선택될 수 있다.
- 생성자
가. Checkbox( ), Checkbox(String label)
나. Checkbox(String label, boolean state) // state가 true이면 선택된 상태
다. Checkbox(String label, boolean state, CheckboxGroup group) // 같은 그룹의 체크박스들은 라디오 버튼처럼 동작, 하나의 체크박스만이 on 상태

∙ Choice 클래스
- 콤보박스를 표현한다.
- 여러 항목들 가운데 하나를 선택할 수 있게 하며 팝업 메뉴와 유사하다.
- 항목들은 위부터 0, 1, 2 ... 의 색인으로 구분된다.
- 현재 선택된 항목이 제목으로 표시된다.
- 메소드 : void addItem(String item) / void insert(String item, int index) / String getItem(int index) / int getSelectedIndex() / String getSelectedItem()

∙ List 클래스
- 스크롤이 되는 여러 텍스트 항목을 제시하며 이 중 하나 또는 다수를 선택하게 한다.
- 선택할 아이템이 매우 많을 때 사용, 다중 선택 가능, 스크롤 가능
- 생성자 : List(), List(int rows, boolean multipleMode)
- 메소드 : void add(String item), void add(String item, int index), String getItem(int index), int getSelectedIndex(), int[] getSelectedIndexes(), String getSelectedItem(), String[] getSelectedItems()

∙ List 컴포넌트와 이벤트
- 한 항목이 선택되거나 해제되면 ItemEvent 가 발생한다.
- 사용자가 리스트에서 한 항목을 더블클릭하면 ActionEvent 가 발생한다.
- 한 항목이 선택된 상태에서 엔터키를 치면 역시 ActionEvent 가 발생한다.
- ItemEvent 나 ActionEvent 를 처리하고자 한다면 List 컴포넌트에 addItemListener()나 addActionListener()를 이용해 이벤트를 등록해야 하며, 그런 경우에 이벤트가 ItemListener 또는 ActionListener 객체에 전달된다.

∙ Label 클래스
- 특정 영역에 한 줄의 문자열을 보이게 하는 클래스이다.
- 프로그램에서 문자열을 바꿀 수는 있으나 직접 편집할 수는 없다

∙ TextComponent
- 텍스트의 편집을 허용하는 컴포넌트로 TextArea 와 TextField 클래스의 슈퍼 클래스이다.
- 텍스트의 편집가능 여부, 텍스트 편집, 편집 위치의 변경, 부분 텍스트의 선택 등을 지원하는 메소드를 제공한다.
- 메소드 : int getCaretPosition(), void setCaretPosition(int position) // (편집 위치를 알려주는) 캐럿의 위치를 조회/설정, String getSelectedText() , String getText(), void select(int start, int end), void setText(String t)

∙ TextArea 클래스
- 여러 줄의 텍스트를 편집할 수 있는 컴포넌트이다.

∙ TextField 클래스
- 한 줄의 텍스트를 편집할 수 있게 하는 컴포넌트이다.
- 생성자 : TextField(String text, int columns)
- 메소드 : void setColumns(int cols), int getColumns(), void setEchoChar(char c), char getEchoChar() (비밀번호 등을 입력할 때 echo char을 '*' 등으로 설정), void setText(String text)

∙ TextField 클래스와 이벤트
- TextField 컴포넌트에서 사용자가 키보드를 타이핑할 때마다 KeyEvent 가 발생한다.
- KeyEvent 는 keyPressed/keyReleased/keyTyped 로 구분된다.
- 컴포넌트에 addKeyListener() 메소드를 이용해 KeyEvent 를 등록했었다면, 키 이벤트는 KeyListener 나 KeyAdapter 객체로 전달된다.
- 또 TextField 컴포넌트에서 사용자가 엔터키를 치면 ActionEvent 가 발생한다

∙ 이벤트와 이벤트 클래스
- 이벤트란 사용자가 GUI 컴포넌트를 다루면서 발생시키는 모든 종류의 사용자 행위를 말한다.
- 이벤트는 종류별로 클래스로 정의되어 있으며 이름은 ‘XxxEvent’와 같다. (MouseEvent, ActionEvent, ItemEvent 등)
- 이벤트 클래스는 종류에 맞는 정보와 메소드를 가진다.
- 이벤트와 관련이 있는 대부분의 클래스는 java.awt.event 패키지에 포함된다. AWT 컴포넌트에서 발생하는 다양한 이벤트를 처리하기 위한 인터페이스와 클래스 제공 (xxxEvent, xxxListener, xxxAdapter )

∙ 이벤트 기반 프로그래밍
- 사용자의 행위에 대해 반응함으로써 동작하는 프로그래밍 방식이다.
- 이벤트가 발생했을 때, 그것에 대해 등록된 코드를 실행하는 것을 ‘이벤트 처리’라 한다.
- 무한루프를 돌면서 사용자 행위가 발생했을 때, 해당 컴포넌트가 그것을 청취하여 응답하는 형태로 작동하도록 하는 프로그래밍을 이벤트 기반 프로그래밍이라 한다.
- 컴포넌트와 이벤트 발생 : GUI 컴포넌트에서 여러 이벤트가 발생할 수 있음 (Event Source)
- 컴포넌트마다 발생될 수 있는 이벤트가 정해져 있음 (
가. Button의 경우 발생 가능한 이벤트 : ActionEvent, ComponentEvent, FocusEvent, KeyEvent, MouseEvent
나. ActionEvent가 발생할 수 있는 컴포넌트 : Button, List, MenuItem, TextField

∙ 이벤트 처리 : 위임형 이벤트 처리 모델
- 모든 AWT 컴포넌트는 이벤트 소스가 될 수 있다.
- 컴포넌트의 종류에 따라 발생될 수 있는 이벤트의 종류가 정해져 있다.
- 컴포넌트(이벤트 소스)에 특정 이벤트를 처리하기 위한 객체(이벤트 리스너)를 따로 등록함 (컴포넌트에 이벤트가 발생했을 때, 컴포넌트에 등록된 리스너 객체를 통해 이벤트 처리 코드를 실행함)
- 이벤트 처리를 위해 이벤트 소스에 이벤트 리스너 객체를 등록함 (하나의 이벤트 소스에서 여러 다른 이벤트가 발생 가능하며, 이벤트 종류별로 각각 이벤트 처리를 등록해야 함)
- 이벤트 처리를 위해서 이벤트 소스가 되는 컴포넌트는 addXxxListener() 메소드를 이용하여 이벤트 리스너를 등록한다.
- 실제 이벤트를 처리하는 것은 컴포넌트가 아니라 이벤트 리스너이다.
- 하나의 이벤트 소스에서 여러 다른 이벤트가 발생할 수 있으며, 이 경우 각각 이벤트 리스너를 등록시켜야 한다.
- 하나의 이벤트 리스너가 여러 컴포넌트에서 발생하는 이벤트들을 처리할 수도 있다.

∙ 이벤트 클래스
- 이벤트는 클래스(xxxEvent)로 분류되어 있음 (예, MouseEvent(마우스 클릭과 관련된 이벤트)
- 이벤트 클래스는 종류에 맞는 정보와 메소드를 가짐

∙ 이벤트 리스너
- 이벤트의 처리를 위임받은 객체이다. (이벤트 처리를 위한 인터페이스)
- 이벤트 리스너는 이벤트 클래스와 1 대 1 로 대응되는 인터페이스이며 이름은 ‘XxxListener’이다.
- 예를 들어 ActionEvent 클래스는 ActionListener 인터페이스와 대응된다.
- 이벤트 리스너에는 구체적인 개별 이벤트(저수준 이벤트)를 처리하기 위한 메소드들이 존재한다.
- 예를 들어 KeyEvent 의 경우는 keyPressed/keyReleased/keyTyped 로 구분된다. 이벤트 리스너를 구현하는 클래스는 해당 개별 메소드를 모두 구현해야 한다.
- 이벤트 클래스에 대응되는 인터페이스
가. WindowEvent - WindowListener, ItemEvent - ItemListener 등
나. 인터페이스에는 개별 이벤트를 처리하기 위한 하나 또는 여러 메소드가 존재함
다. 2개 이상의 메소드를 가지는 인터페이스는 상응하는 이벤트 어댑터 클래스가 존재함
- 이벤트 리스너 객체 : 이러한 이벤트 리스너 인터페이스를 구현한 클래스의 객체 또는 어댑터 클래스를 상속받는 클래스의 객체, 이벤트 처리를 담당함


∙ 이벤트 어댑터
- 이벤트 리스너에 2 개 이상의 개별 처리 메소드가 존재하는 경우 상응하는 이벤트 어댑터 클래스가 존재한다.
- 이벤트 어댑터는 추상 클래스로 이름은 ‘XxxAdapter’와 같다.
- ‘XxxAdapter’ 클래스는 ‘XxxListener’ 인터페이스를 구현한 추상 클래스이다.
- 실제 어댑터에서 정의된 개별 메소드는 아무 일도 하지 않는 빈 블록이다.
- 이벤트 리스너를 구현하는 클래스를 정의하는 대신 이벤트 어댑터를 상속하는 클래스를 정의하게 되면 불필요한 메소드에 대해서는 구현을 생략할 수 있다.


∙ 이벤트 등록
- 이벤트 소스와 처리할 이벤트 종류를 결정 (예: Button에서 ActionEvent를 처리하고자 함)
- 상응하는 리스너 인터페이스를 구현하는 클래스를 정의
가. 여기서 이벤트 처리를 위한 개별 메소드를 구현함
나. 개별 메소드가 이벤트를 처리하는 코드임
예: ActionListener를 구현하는 클래스 A를 정의하고 actionPerformed()를 구현
- 상응하는 어댑터 클래스가 존재하면 이것을 상속받는 클래스를 정의해도 됨 (불필요한 메소드의 구현을 생략할 수 있음)
- 리스너 객체를 생성하고 해당 이벤트 소스에 처리하고자 하는 이벤트를 등록함 (예: aButton.addActionListener(new A()); )

∙ 이벤트 처리
- 버튼을 누르면 ActionEvent가 발생
- 등록되어 있는 이벤트 리스너 객체를 통해 void actionPerformed(ActionEvent ev)가 실행됨. (ActionEvent 객체가 인자로 전달됨)

∙ ActionEvent 와 ActionListener
- ActionEvent 는 명령의 실행을 의미한다.
- 버튼을 클릭하는 경우, 메뉴 항목을 클릭하는 경우, TextField 에서 ‘엔터키’를 치는 경우, List 항목을 더블클릭하는 경우에 ActionEvent 가 발생한다.
- ActionListener 인터페이스를 구현할 때 actionPerformed(ActionEvent)만을 정의하면 되므로 어댑터 클래스가 필요없다.
- ActionEvent 클래스에서 정의된 ‘String getActionCommand()’는 버튼의 제목이나 메뉴 항목의 제목을 문자열로 리턴한다.
- Object getSource( ) // EventObject에서 상속된 메소드

∙ WindowEvent와 WindowListener
- WindowListener의 메소드 : 윈도우의 상태 변화를 야기하는 경우
예) void windowActivated(WindowEvent ev), void windowClosed(WindowEvent ev)
- WindowEvent의 메소드 : int getNewState() (windowStateChanged()메소드에서 사용, 0이면 정상 상태임), int getOldState(), Window getWindow()

∙ ItemEvent 와 ItemListener
- ItemEvent 는 Checkbox, CheckboxMenuItem, Lsit 의 항목을 클릭할 때 발생한다.
- ItemListener 인터페이스를 구현할 때 itemStateChanged()만을 정의하면 되므로 어탭터가 필요없다.
- ItemEvent 클래스의 메소드는 다음과 같다.
가. Object getItem():이벤트에 의해 영향을 받은 항목을 리턴한다.
나. int getStateChange():‘ItemEvent.SELECTED’ 또는 ‘ItemEvent.DESELECTED’를 리턴한다.

∙ KeyEvent 와 KeyListener
- KeyEvent 는 키보드를 타이핑할 때 발생한다.
- KeyListener 인터페이스를 구현할 때 keyPressed(), keyReleased(), keyTyped()를 정의해야 하며 KeyAdapter 클래스를 상속받을 수도 있다.

∙ MouseEvent 와 MouseListener/MouseMotionListener
- MouseEvent 는 마우스 클릭, 이동, 드래깅할 때 발생한다.
- MouseEvent 에 대응되는 리스너는 MouseListener 와 MouseMotionListener 로 구분된다.
- 리스너 메소드 언제 호출되는가?
- MouseListener의 메소드
mouseClicked(MouseEvent ev)마우스를 클릭했을 때(눌렀다가 떼었을 때)
mouseEntered(MouseEvent ev)마우스 포인터가 컴포넌트에 들어왔을 때
mouseExited(MouseEvent ev)마우스 포인터가 컴포넌트에서 나갔을 때
mousePressed(MouseEvent ev)마우스를 누르고 있을 때
mouseReleased(MouseEvent ev)마우스를 떼었을 때
- MouseMotionListener의 메소드
mouseDragged(MouseEvent ev)마우스가 드래깅 될 때
mouseMoved(MouseEvent ev)마우스가 움직일 때
- MouseAdapter 는 위의 모든 메소드를 구현한 어댑터 클래스이며 MouseMotion-Adapter 는 mouseDragged()와 mouseMoved()를 구현한 어댑터 클래스이다.
- MouseEvent의 메소드 : int getButton(), int getClickCount(), Point getPoint(), int getX(), int getY()

∙ TextEvent 와 TextListener
- TextEvent 는 텍스트 컴포넌트에서 텍스트에 변화가 생길 때 발생한다.
- TextListener 인터페이스에서는 textValueChanged() 메소드만이 선언되어 있다.

∙ ComponentEvent 와 ComponentListener
- ComponentEvent 는 컴포넌트의 이동, 크기 변화, 가시성 변화가 생겼을 때 발생한다.
- ComponentListener 인터페이스에는 componentHidden(), componentMoved(), componentResized(), componentShown() 메소드가 선언되어 있다.
- ComponentListener 인터페이스를 구현하는 대신에 ComponentAdapter 를 상속받을 수 있다.


제 10 장 Applet 프로그래밍

∙ 애플릿
- Java 애플릿은 Java 플러그인이 탑재된 웹 브라우저에서 실행되는 특별한 Java 프로그램이다.
- 사용자가 브라우저를 통해 애플릿이 들어 있는 HTML 문서를 요청하면 애플릿이 사용자 컴퓨터로 전송되어 실행된다.
- Java 애플릿 프로그램은 java.applet.Applet 클래스의 서브 클래스이어야 한다.
- 브라우저의 Java 플러그인이 애플릿의 실행주기를 관리한다.
- 웹 브라우저에 의해 자동으로 객체가 생성되어 로드되고 실행되므로 main() 함수를 가질 필요가 없다.

∙ Applet 클래스
- AWT 컴포넌트 가운데 Panel 클래스의 서브 클래스로 컨테이너의 성질을 가진다.
- Panel 을 상속받으므로 기본 배치 관리자는 FlowLayout 이다.
- Applet 는 기본적인 패널을 제공하고 애플릿과 브라우저 또는 애플릿과 실행 환경 사이의 통신 인터페이스를 제공한다.
- Applet 클래스의 메소드는 다음과 같다.
가. init(), start(), stop(), destroy():모두 빈 블록으로 정의되어 있다.
나. String getAppletInfo():애플릿의 정보를 리턴한다. 필요하면 오버라이딩해야 한다.
다. URL getCodeBase():애플릿의 클래스 파일이 위치한 디렉터리를 URL 로 리턴한다.
라. URL getDocumentBase():애플릿을 로드하는 HTML 파일의 위치를 URL 로 리턴한다.
마. Locale getLocale():지역 정보를 리턴한다.
바. boolean isActive():애플릿이 활성화 상태인지 아닌지를 조사한다.

∙ 애플릿의 실행
- 애플릿이 초기화, 시작, 멈춤, 종료될 때 상응하는 메소드가 실행된다.
- 애플릿이 로딩될 때 생성자 → init() → start() 순으로 호출된다.
- 애플릿이 종료될 때 stop() → destroy() 순으로 호출된다.
- 사용자가 다른 페이지로 이동할 때, ‘새로 고침’할 때, 브라우저를 닫을 때 기존 애플릿은 종료된다.
- 애플릿의 실행과 관련이 있는 메소드들은 다음과 같다.
가. 애플릿 생성자:init() 함수의 용도와 같다. 보통 애플릿은 생성자를 사용하지 않는 편이다.
나. init():애플릿을 초기화하는 함수이다. 애플릿이 로드될 때 한번 실행된다. 짧게 작성해야 로드 시간을 줄일 수 있다.
다. start():애플릿 실행의 시작을 뜻한다. init() 이후에 수행해야 하는 작업이 있으면 Applet 클래스의 start() 메소드를 오버라이딩해야 한다. start()에서 많은 작업을 수행해야 한다면 스레드를 이용하는 것이 좋다.
라. stop():애플릿 실행의 중지를 뜻한다. 시스템 자원을 소비하지 않도록 stop() 메소드를 오버라이딩하는 것이 좋다.
마. destroy():애플릿의 종료를 뜻한다. stop() 메소드가 있으므로 대부분의 애플릿은 이 메소드를 오버라이딩할 필요가 없다

∙ 매개변수 사용하기
- 애플릿 프로그램에 매개변수를 전달하기 위해 APPLET 태그는 PARAM 태그를 포함할 수 있다.
- 애플릿 프로그램에서 매개변수를 읽기 위해 ‘String getParameter(String name)’을 사용한다.

∙ Applet 에서 Frame 윈도 띄우기
- setMenuBar() 메소드는 Frame 클래스에서만 정의되어 있으므로 애플릿에 메뉴바를 붙일 수 없다.
- 애플릿에서 메뉴를 사용하려면 별도의 Frame 윈도를 띄워야 한다.

∙ Applet 의 제약
- 애플릿은 실행 환경의 특수성과 보안 문제로 인해 제약 사항을 가진다.
가. 클라이언트 컴퓨터의 파일을 읽거나 쓸 수 없다. 따라서 클라이언트 컴퓨터의 프로그램을 실행시킬 수 없다.
나. 클라이언트 컴퓨터의 시스템 속성 가운데 보안과 관련된 몇 가지 속성을 읽을 수 없다.
다. 애플릿 프로그램은 자신을 전송한 서버와는 통신할 수 있지만 다른 컴퓨터와는 통신을 할 수 없다.
- 한편 애플릿은 웹 브라우저의 일부 능력을 이용할 수 있다는 특징을 가진다.
가. 애플릿은 자신을 전송한 서버와 네트워크 연결을 설정하여 통신할 수 있다.
나. 자신과 같은 HTML 문서에 포함되어 있는 다른 애플릿의 public 메소드를 호출할 수 있다.
다. 애플릿은 자신이 실행되고 있는 웹 브라우저를 통해 다른 HTML 문서를 로드할 수 있다.

∙ 이미지 다루기
- Applet 클래스는 화면상에 나타낼 이미지를 만들기 위해 getImage() 메소드를 제공한다.
- getImage(URL, String)는 지정된 URL 에 위치한 이미지 파일로부터 Image 객체를 만든다.
- getImage() 메소드는 바로 리턴되므로 화면에 이미지가 그려질 때까지도 데이터가 계속 로드될 수 있다.
- 이미지 파일을 로드하는 애플릿 프로그램에서는 동기화 문제를 해결하기 위해 MediaTracker 클래스를 사용해야 한다.
1. MediaTracker 의 생성자 ‘MediaTracker(Component comp)’는 지정된 컴포넌트(여기에 이미지가 그려짐)를 위해 이미지 추적을 위한 객체를 생성한다.
2. MediaTracker 의 메소드 addImage(Image image, int id)를 사용하여 이미지를 트랙커의 이미지 리스트에 추가한다.
3. 실제 이미지를 화면에 그리기 전에 MediaTracker 의 메소드 waitForAll( )을 이용해 모든 이미지가 로드될 때까지 기다리게 한다.

∙ 사운드 다루기
- Java 에서 재생이 가능한 오디오 파일 형식은 .au, .wav, .mid 등이 있다.
- Applet 클래스는 오디오 객체를 만들기 위해 getAudioClip() 메소드를 제공한다.
- getAudioClip(URL url, String name)는 url 에 위치한 오디오 파일을 읽어서 AudioClip 객체를 생성한다. getAudioClip() 메소드도 getImage()와 마찬가지로 바로 리턴되므로 동기화 문제가 발생한다.
- AudioClip 은 인터페이스로서 반복 재생을 위한 void loop( ), 재생을 위한 void play( ), 멈춤을 위한 stop( ) 메소드를 제공한다.

∙ 초기화 전담 스레드 사용하기
Java 애플릿의 초기화 작업은 생성자, init( ), start( )의 세 곳에서 진행할 수 있다.
- 애플릿은 초기화 작업이 진행되는 동안, 즉 start( ) 메소드가 끝날 때까지는 이벤트를 처리할 수 없다.
- 초기화 작업이 오래 걸리면 애플릿이 아무런 동작도 하지 않고 멈춰있는 것처럼 보이게 된다.
- 이런 현상을 개선하려면 초기화 과정을 따로 스레드로 분리해야 한다.
- start() 메소드에서 초기화를 위한 스레드를 실행시키고 애플릿에 스레드의 실행 상태를 간간이 보여주는 것이다.

∙ 브라우저에서 애플릿 제어하기
- 브라우저에서 애플릿에 정의된 메소드를 호출할 수 있다.
- HTML 문서의 APPLET 태그에서 NAME 속성에 애플릿 인스탄스의 이름을 설정해 놓으면 해당 애플릿 클래스의 public 함수를 HTML 문서에서 Java 스크립트를 이용하여 호출할 수 있다.

∙ 애플릿에서 브라우저 또는 다른 애플릿의 제어
- 하나의 웹 문서 안에는 여러 애플릿이 존재할 수 있다.
- 애플릿 간의 통신을 통해 동일 웹 문서 내의 애플릿 전체가 하나의 프로그램인 것처럼 동작 가능하다.
- AppletContext 는 애플릿 코드를 포함하고 있는 문서를 제어하거나 다른 애플릿에 관한 정보를 얻고자할 때 사용되는 인터페이스이다.
- Applet 클래스의 getAppletContext() 메소드는 AppletContext 객체를 리턴한다.
- AppletContext 인터페이스는 다음 메소드를 제공한다.
가. Applet getApplet(String name):같은 HTML 문서에 존재하는 애플릿 객체를 리턴한다.
나. void showDocument(URL url, String target):브라우저에 url 문서를 표시한다.
다. void showStatus(String status):브라우저의 상태 표시줄에 status 를 출력한다.


제 11장 JavaFX

∙ JavaFX 개요
- JavaFX는 크로스 플랫폼에서 실행하는 리치 클라이언트 애플리케이션을 개발하기 위한 그래픽과 미디어 패키지를 말한다.
- AWT : 운영체제가 제공하는 네이티브 UI 컴포넌트를 이용하는 자바 라이브러리
- Swing : 네이티브 UI 컴포넌트를 사용하지 않고, 자신만의 UI를 갖도록 고안함.
- JavaFX : 화면 레이아웃과 스타일, 애플리케이션 로직을 분리할 수 있기 때문에 디자이너와 개발자들이 협력해서 JavaFX 애플리케이션을 개발할 수 있는 구조


∙ JavaFX 애플리케이션 개발
- 메인 클래스는 추상클래스인 javafx.application.Application을 상속받고, start() 메소드를 재정의해야 한다. 그리고 main() 메소드는 Application의 launch() 메소드를 호출해야 한다.
- JavaFX는 윈도우를 무대(javafx.stage.Stage)로 표현한다.
- launch()에서 생성된 메인 윈도우를 start()의 primaryStage 매개 값으로 제공하는데, start()의 메소드는 맨 마지막에서 primaryStage.show() 메소드를 호출함으로써 메인 윈도우가 보여진다.
- Application.launch() – 기본 생성자 – init() – start() – 사용
- Platform.exit() 호출 또는 마지막 Stage 닫힘 – stop() – 종료
- 윈도우를 무대(stage)로 표현하고, 무대는 한 번에 하나의 장면을 가질 수 있는데, JavaFX는 장면을 javafx.scene.Scene으로 표현한다.
- 메인 윈도우는 start() 메소드의 primaryStage 매개값으로 전달되지만, 장면은 직접 생성해야 한다.

∙ JavaFX 레이아웃
- FXML은 XML 기반의 마크업 언어로, JavaFX 애플리케이션의 UI 레이아웃을 자바 코드에서 분리해서 태그로 선언하는 방법을 제공한다. 이 방법은 안드로이드 앱을 개발하는 방법과 유사한데, 안드로이드는 XML을 레이아웃을 작성하고, 자바로 이벤트 처리 및 애플리케이션 로직을 작성한다.
- FXML 태그로 레이아웃을 정의하기 때문에 태그에 익숙한 디자이너와 협업이 가능하다.
- FXML로 선언된 태그는 자바 코드로 변환되어 실행되기 때문에 자바 코드와 매핑 관계가 존재한다. 패키지, 태그, 속성, 객체를 선언하게 된다.
- FXML 파일을 작성했다면, FXML 파일을 읽어드려 선언된 내용을 객체화해야 한다. 이것을 FXML 로딩이라고 한다. javafx.fxml.FXMLLoader를 사용한다
- JavaFX Scene builder : FXML에 익숙지 않은 개발자들을 위해 FXML을 자동으로 생성해주는 툴

∙ JavaFX 컨테이너
- AnchorPane, BorderPane, FlowPane, GridPane, StackPane, TilePane, Hbox, Vbox

∙ JavaFX 이벤트 처리
- 이벤트 핸들러 : 이벤트 발생 컨트롤과 이벤트 핸들러를 분리하는 위임형 방식을 사용한다. 즉, 컨트롤에서 이벤트가 발생하면, 컨트롤이 직접 처리하지 않고 이벤트 핸들러에게 이벤트 처리를 위임하는 방식이다.

∙ JavaFX 컨트롤
- 버튼 컨트롤 : Button, CheckBox, RadioButton, ToggleButton
- 입력 컨트롤 : Label, TextField, PasswordField, TextArea, ComboBox, DatePicker, ColorPicker, HTMLEditor
- 뷰 컨트롤 : ListView, TableView, ImageView
- 미디어 컨트롤 : MediaView, Slider, ProgressBar, ProgressIndicator
- 차트 컨트롤 : PieChart, LineChart, AreaChart, BarChart, BubbleChart, ScatterChart

∙ JavaFX 메뉴바와 툴바
- MenuBar 컨트롤
- ToolBar 컨트롤

∙ JavaFX 다이얼로그
- FileChooser, DirectoryChooser
- Popup
- 커스텀 다이얼로그

∙ JavaFX CSS 스타일
- JavaFX UI를 담당하는 컨테이너 및 컨트롤은 CSS를 적용해서 모양 및 색상 등을 변경할 수 있다. 이것은 HTML에 CSS를 적용하는 것과 유사하다. JavaFX CSS는 W3C CSS 버전 2.1 스펙을 따른다.
- 인라인 스타일, 외부 CSS 파일 적용 가능

∙ JavaFX 스레드 동시성
- JavaFX UI는 스레드에 안전하지 않기 때문에 UI를 생성하고 변경하는 작업은 JavaFX Application Thread가 담당하고, 다른 작업 스레드들은 UI를 생성하거나 변경할 수 없다.
- main 스레드가 Application의 launch() 메소드를 호출하면서 생성된 JavaFX Application Thread는 start() 메소드를 실행시키면서 모든 UI를 생성한다.
- 컨트롤에서 이벤트가 발생할 경우 컨트롤러의 이벤트 처리 메소드를 실행하는 것도 JavaFX Application Thread이다.
- JavaFX 애플리케이션을 개발할 때 주의할 점은 JavaFX Application Thread가 시간을 요하는 작업을 하지 않도록 하는 것이다.
- 시간을 요하는 작업을 하게 되면 이 시간 동안에 UI는 반응하지 않고 멈춰있는 상태가 되기 때문에 다른 작업 스레드를 생성해서 처리하는 것이 좋다.
- 작업 스레드가 직접 UI를 변경할 수 없기 때문에 UI 변경이 필요할 경우, Platform.runLater() 메소드를 이용하거나, javafx.concurrent API인 Task 또는 Service를 이용하여 해결해야 한다.

∙ Platform.runLater() 메소드
- 이벤트 큐에 Runnable을 저장하고 즉시 리턴한다. 이벤트 큐에 저장된 Runnable들은 저장된 순서에 따라서 JavaFX Application Thread에 의해 하나씩 실행 처리되어 UI 변경 작업을 한다.

∙ Task 클래스와 Service 클래스
- javafx.concurrent 패키지는 JavaFX 애플리케이션 개발에 사용할 수 있는 스레드 동시성 API를 제공하고 있다.
- 이 패키지는 Worker 인터페이스와 두 가지 구현 클래스인 Task와 Service로 구성되어 있다.
- Worker 인터페이스는 Task와 Service에서 공통적으로 사용할 수 있는 메소드가 선언되어 있다.
- Task 클래스는 JavaFX 애플리케이션에서 비동기 작업을 표현한 클래스이고, Service는 이러한 Task를 간편하게 시작, 취소, 재시작할 수 있는 기능을 제공한다.
- Task는 작업 스레드에서 실행되는 하나의 작업을 표현한 추상 클래스이다.
- Service 클래스 목적은 작업 스레드와 JavaFX Application Thread가 올바르게 상호작용을 할 수 있도록 도와주는 것이다.

∙ 화면 이동과 애니메이션
- 화면을 이동하는 가장 쉬운 방법은 Stage에 새로운 Scene을 세팅하는 것이다.
- 애플리케이션이 실행되면 start() 메소드는 메인 화면인 Scene을 생성하고, primaryStage의 setScene() 메소드로 Scene을 설정한다.
- 애니메이션은 컨트롤 또는 컨테이너의 속성 변화를 주어진 시간 동안 진행함으로써 구현한다.


제 12 장 JDBC 프로그래밍

∙ DBMS
- 데이터베이스의 효과적 관리를 위한 응용 소프트웨어이다.
- 관계형 DBMS 에서는 데이터를 테이블 형태로 저장한다.
- 하나의 데이터베이스는 여러 테이블들로, 하나의 테이블은 여러 레코드들로 구성된다.

∙ MySQL 설치와 실행
1. http://dev.mysql.com/downloads/mysql/에 접속하여 ‘MySQL Community Server 5.6.20‘을 다운받는다. 윈도우 32 비트용이라면 ’Windows (x86, 32-bit), MSI Installer‘를 다운받는다(미리 Oracle 에 회원 가입을 해야 함).
2. 다운받은 파일을 실행시켜 설치한다. 설치 유형을 ‘Typical’로 한다. 이 과정에서 root 사용자의 암호를 입력하고 기억한다.
3. 시작 메뉴>모든 프로그램>MySQL>MySQL Server 5.6>MySQL 5.6 Command Line Client 를 실행하고 root 암호를 입력하면 MySQL을 사용할 수 있다.

∙ JDBC (Java DataBase Connectivity) API
- JDBC 는 자바 프로그램에서 ‘관계형 DBMS’에 연결하여 데이터에 접근할 수 있게 하는 자바 API 규격이다. JDK 일부로 포함되어 있음. 데이터베이스에 연결하고, 데이터에 대해 질의와 갱신을 요청하고, 결과를 받는 방법
- JDBC 드라이버는 프로그램의 데이터베이스 요청을 DBMS가 이해할 수 있게 변환해주는 어댑터이다. JDBC 드라이버는 실제 데이터베이스에 연결하고 질의를 보내고 결과를 받는 작업을 구현한다. 사용하고자 하는 특정 DBMS의 JDBC 드라이버를 다운로드 받아 설치해야 JDBC API를 사용할 수 있음
- 자바 프로그램에서 DBMS를 사용하려면 DBMS 제작사가 제공하는 ‘JDBC 드라이버’를 클라이언트 머신에 설치하여야 한다.
- Java 프로그램에서 MySQL 을 사용하는 경우에는 MySQL Connectors 가운데 ‘Connector/J’가 필요하다.
- 환경 변수 CLASSPATH 에 C:\Program Files\MySQL\MySQL ConnectorJ\mysql–connector–java–5.1.32–bin.jar 를 추가한다.

∙ JDBC 프로그래밍 기본
- JDBC 드라이버를 동적으로 로드 : Class.forName().newInstance() 메소드 사용, 최신 JDBC 버전에서는 생략해도 됨
- DBMS와 연결 설정 : DriverManager와 Connection 객체 사용
- SQL 실행 : Connection, Statement와 ResultSet 객체 사용
- 연결 해제 : 사용 중인 데이터베이스 자원을 반납

∙ DatabaseMetaData 객체
- DBMS의 정보를 가지는 객체
- 객체는 Connection 객체의 getMetaData( ) 메소드로 됨
- 주요 메소드 : String getDriverName(), String getURL(), String getUserName()

∙ Statement 객체
- SQL 구문을 실행하고 결과를 반환해 주는 객체
- 객체는 Connection 객체의 createStatement( ) 메소드를 통해 생성됨
- 주요 메소드 :
가. boolean execute(String sql) (SQL 구문을 실행, select 구문을 실행하는 경우 true를 리턴)
나. ResultSet getResultSet() (현재 SQL 구문(select)을 실행한 결과를 리턴함)
다. int getUpdateCount() (현재 SQL 구문(select 외)의 실행으로 영향을 받은 행의 개수를 리턴함)
라. ResultSet executeQuery(String sql) (select 구문을 실행시킬 때 사용, 실행 결과를 나타내는 테이블인 ResultSet 객체를 리턴함)
마. int executeUpdate(String sql) (update, insert, delete 구문을 실행할 때 사용, 영향 받은 행의 개수를 리턴함)

∙ ResultSet 객체
- Statement 객체의 getResultSet( ), executeQuery( ) 메소드가리턴하는 객체 (실행 결과를 나타내는 테이블로 볼 수 있음)
- select 구문의 실행 결과를 다룰 때 사용
- select 구문을 실행하여 ResultSet 객체가 생성되면 커서가 만들어지고, select 구문 실행 결과를 가리킴 (커서는 행을 가리키는 포인터, 위에서 아래로 진행, 한 행씩 처리함)
- 메소드
가. boolean next() // 커서를 다음 행으로 이동시킨다, 최초에 커서는 첫 행의 이전을 가리키고 있음
나. boolean previous() // 커서를 이전 행으로 이동시킨다.
다. Statement getStatement() // 현재 ResultSet을 생성시킨 Statement 객체를 리턴함
라. String getString(int columnIndex) // ResultSet 객체에서 해당 열의 문자열을 리턴함
마. int getInt(int columnIndex) // ResultSet 객체에서 해당 열의 int 값을 리턴함

∙ PreparedStatement 객체
- Precompile된 SQL 문을 표현
- 객체는 Connection 객체의 prepareStatement(String sql) 메소드를 통해 생성됨
- 객체를 생성할 때 SQL 구문이 주어짐
- 대개 SQL문에 매개 변수를 사용하고, 실행 전에 값을 지정할 수 있음
- SQL 문을 여러 번 실행할 때 효율적임
- 메서드 : boolean execute(), ResultSet executQuery(), Int executeUpdate(), void setInt(int parameterIndex, int x), void setString(int parameterIndex, String x) (SQL 구문에서 매개 변수를 설정)

∙ DBMS와 Java의 자료형 변환
- DBMS 테이블에서 열의 자료형과 Java의 자료형, 그리고 JDBC메소드 간의 관계


∙ ResultSetMetaData 객체
- ResultSet 객체에서 테이블의 이름, 열의 이름과 타입 정보를 얻을 때 사용되는 객체
- ResultSet의 getMetaData() 메소드로 생성함
- 주요 메소드
가. String getColumnName(int colIndex) // colindex 위치의 컬럼 이름을 리턴
나. int getColumnCount( ) // ResultSet의 컬럼 개수를 리턴
다. int getColumnType(int colIndex) // colindex 위치의 컬럼 자료형을 리턴
라. String getTableName(int colIndex) // colindex 위치의 컬럼을 포함하는 테이블의 이름을 리턴


제 13 장 네트워크 프로그래밍

∙ 포트
- 네트워크 연결을 위한 가상의 연결 단자로 데이터의 송수신 통로이다.
- 데이터는 포트를 통해 송수신되어야 하며 하나의 포트는 하나의 네트워크 서비스에 할당된다.
- 서버로 전송된 데이터는 포트 번호에 따라 특정 응용 프로그램에 전달되어야 한다.
- HTTP 는 80 번 포트, FTP 서비스는 21 번 포트를 사용한다.
- 네트워크를 통해 송수신할 때, 포트 번호(16 비트)와 IP 주소(32 비트)를 가지고 소켓에 연결한다.

∙ 소켓
- 클라이언트-서버 응용 프로그램은 포트를 직접 제어하지 않고 소켓을 사용한다.
- 소켓은 네트워크로 연결된 두 프로그램 사이의 양방향 통신에서 한쪽 종단을 말한다.
- 소켓은 클라이언트 프로그램과 서버 프로그램 간의 연결을 표현한다.
- 소켓은 IP 주소와 포트번호를 가져야 한다.
- 클라이언트 소켓은 서버에 연결을 요청하기 위해 필요하고, 서버 소켓은 연결 요청을 받아들이고 클라이언트와의 통신을 위해 새로운 소켓을 만든다.
- 클라이언트 프로그램과 서버 프로그램은 각자의 소켓에서 읽기(수신)/쓰기(송신)를 수행한다.

∙ 네트워크 프로그래밍
- 네트워크를 통해 원격 컴퓨터의 프로그램과 데이터를 주고받기 위해 프로그램을 작성하는 것이다.
- 데이터 전송 서비스를 요청하는 측을 클라이언트라 하고 데이터를 제공하는 측을 서버라 한다.
- 인터넷상에서 컴퓨터들은 TCP 또는 UDP 프로토콜을 사용하여 통신한다.
- TCP 와 UDP 는 IP 프로토콜에 기초하여 만들어진 것이다.
- TCP 는 두 컴퓨터 사이에 신뢰성있는 데이터 스트림을 제공한 연결형 프로토콜이다.
- UDP 는 데이터그램이라고 하는 독립적 데이터 패킷을 전송하는 프로토콜로 데이터 수신을 보장하지 못하는 비연결형 프로토콜이다.
- Java 로 네트워크 프로그램을 작성하는 것은 애플리케이션 계층에서 프로그래밍하는 것이다.
- Java 언어로 네트워크 프로그램을 작성할 때 java.net 패키지를 import 해야 한다.
- ‘IP 주소’를 표현하는 클래스로 모든 네트워크 프로그램에서 사용된다.
- 별도의 생성자를 제공하지 않고, 대신에 객체를 생성시켜 주는 static 메소드 제공한다.
- 하나의 호스트 컴퓨터에 여러 IP 주소가 할당될 수 있다.
- 다음과 같은 메소드를 제공한다.
가. static InetAddress getByName(String host)와 ‘static InetAddress getAllBy-Name(String host):주어진 host 를 사용하여 IP 주소를 리턴한다.
나. static InetAddress getLocalHost():현재 컴퓨터의 IP 주소를 리턴한다.
다. String getHostName():도메인 네임을 리턴한다.
라. String getHostAddress():IP 주소를 문자열로 리턴한다.

∙ Java 의 소켓
- java.net 패키지에서 TCP 와 UDP 통신을 위해 소켓 관련 클래스를 제공한다.
- Socket 과 ServerSocket 클래스는 TCP 통신을 지원하며 데이터의 송수신 순서를 보장한다.
- 서버는 포트번호가 지정된 ServerSocket 객체를 만들고 클라이언트의 요청을 기다린다.
- ServerSocket 클래스는 서버가 클라이언트의 요청을 기다리고 연결을 설정할 수 있도록 소켓을 구현한 클래스이다.
- 클라이언트는 서버의 IP 주소와 포트 번호를 지정하여 Socket 객체를 만들고 서버에 연결을 요청한다.

∙ TCP 네트워킹에서 소켓을 이용한 통신 절차(클라이언트측)
1. 서버의 IP 주소와 포트 번호를 이용하여 소켓을 생성한다.
2. 소켓으로부터 입출력 스트림을 만든다.
3. 입출력 스트림을 이용하여 데이터를 송수신한다.

∙ TCP 네트워킹에서 소켓을 이용한 통신 절차(서버측)
1. 포트번호를 지정하여 서버 소켓을 생성한다.
2. 해당 포트로 들어오는 클라이언트의 연결 요청을 기다린다. 이때 accept() 메소드를 이용한다.
3. 클라이언트와 연결되면 새로운 소켓을 만들고, 그것으로부터 입출력 스트림을 생성한다.
4. 입출력 스트림을 이용하여 데이터를 송수신한다.

∙ Socket 클래스의 메소드
가. Socket(InetAddress address, int port):address 에는 서버의 주소, port 에는 연결하고자 하는 서버의 포트 번호를 넣는다.
나. InputStream getInputStream() throws IOException:소켓 객체의 입력 스트림을 리턴한다.
다. OutputStream getOutputStream() throws IOException:소켓 객체의 출력 스트림을 리턴한다.
라. void close():소켓을 닫는다.
마. void shutdownInput():입력 스트림을 닫는다.
바. void shutdownOutput():출력 스트림을 닫는다.

∙ ServerSocket 클래스의 메소드
가. ServerSocket(int port):현재 서버의 IP 주소에 연결되는 서버 소켓 객체를 생성한다.
나. Socket accept():서버 소켓으로 들어오는 클라이언트의 연결 요청을 기다린다. 즉, 클라이언트가 현재 서버의 해당 포트로 Socket 객체를 생성하면 accept()메소드가 종료된다. 이때 클라이언트와의 통신을 위해 Socket 객체가 리턴된다.

∙ 서버 프로그램의 설명
① 서버는 포트번호를 4444 로 하여 ServerSocket 객체를 생성한다.
② 클라이언트의 요청을 계속 처리하기 위해 무한루프를 돈다.
③ accept() 메소드는 클라이언트의 요청을 기다리다 요청이 오면 Socket 객체를 리턴한다.
④ Socket 객체에서 입력 스트림을 생성한다. 문자 단위 처리와 버퍼링 기능을 추가하여 최종적인 입력 스트림 객체는 in 이다.
⑤ Socket 객체에서 출력 스트림을 생성한다. 최종적인 출력 스트림 객체는 out 이다.
⑥ out 에 한 줄을 출력한다. 여기에 연결되어 있는 클라이언트가 이것을 읽을 것이다.
⑦ out 에 “OUT”을 출력한다. 클라이언트가 이것을 읽게 되면 입력 스트림을 닫게 되어 있다.
⑧ in 을 통해 한 줄을 읽는다. 클라이언트가 보낸 정보를 읽는 것이다.
⑨ 읽은 정보를 화면에 출력한다.

∙ 클라이언트 프로그램의 설명
① “locahost”의 IP 주소를 표현하는 InetAddress 객체를 만든다.
② InetAddress 객체와 포트번호(4444)를 지정하여 클라이언트 소켓인 Socket 객체를 만든다.서버에게 연결을 요청하는 것이다. 서버가 요청을 기다리고 있었다면 연결이 이루어진다.
③ Socket 객체에서 입력 스트림을 생성한다. 최종적인 입력 스트림 객체는 in 이다.
④ Socket 객체에서 출력 스트림을 생성한다. 최종적인 출력 스트림 객체는 out 이다.
⑤ 입력스트림으로부터 한 줄을 읽는다. 이것은 서버가 보낸 정보이다.
⑥ 입력된 것이 “OUT”이라면 입력 스트림을 닫는다. 다음에 읽을 때는 null 이 리턴될 것이다.
⑦ 입력된 것을 화면에 출력한다.
⑧ out 객체에 한 줄을 출력한다. 서버가 이것을 읽을 것이다.
⑨ out 객체에 “OUT”을 출력한다.
⑩ 출력스트림을 닫는다. 이후 서버에 정보를 보낼 수 없다.

∙ 연결 요청을 스레드로 처리하기
- 위 서버 프로그램(교재의 소스 14-5)은 여러 클라이언트의 요청을 처리해 줄 수는 있으나 무한 루프를 돌면서 하나씩 순차적으로 처리할 수밖에 없다.
- 클라이언트의 요청이 있을 때 그것을 처리하는 스레드를 생성해 주는 것이 좋다.
- 스레드를 이용하면 여러 클라이언트들을 동시에 처리해 줄 수 있다.
- 스레드를 만들 때 Socket 객체를 넘겨주어야 한다.

∙ URL 클래스
- URL 은 인터넷상의 자원을 가리킨다.
- 대개의 경우 URL 은 인터넷상의 파일을 표시한다.
- Java 에서 URL 클래스는 URL 주소를 표현하기 위한 것이다.
- URL 의 형식:
- URL 의 세부 정보를 리턴하는 메소드를 제공한다.
- openStream()을 이용하면 입력스트림을 얻을 수 있어서 URL 자원이 저장한 내용을 읽을 수 있다.

∙ URLConnection 클래스
- 추상 클래스로서 프로그램과 URL 에서 지정된 웹 서버간의 통신 기능을 제공한다.
- URL 객체를 통해 openConnection( )메소드를 호출하면 URLConnection 객체를 얻을 수 있다.
- URL 로 표현된 자원을 읽거나 자원에 쓸 수 있다.
가. ‘InputStream getInputStream( )’ 메소드는 URL 과 연결된 입력 스트림을 리턴한다. 이것을 이용하여 URL 로 연결된 웹 서버로부터 데이터를 전달받을 수 있다.
나. ‘OutputStream getOutputStream( )’ 메소드는 URL 과 연결된 출력 스트림을 리턴한다. 이것을 이용하여 웹 서버에 데이터를 전송할 수 있다.

∙ URLEncoder 와 URLDecoder 클래스
- URL 을 인코딩하는 ‘static String encode(String s, String enc)’와 디코딩을 해 주는 ‘static String decode(String s, String enc)’ 메소드를 제공한다.
- URL 의 쿼리 문자열에 한글이 들어가는 경우 URL 을 인코딩하여 사용해야 한다.
- URL 을 인코딩할 때 다음의 규칙이 적용된다.
가. [0–9a–zA–Z.–*_]에 속하는 문자는 변경되지 않는다.
나. 공백 문자는 ‘+’로 변환된다.
다. 그 외의 문자는 “%xy” 형태로 변환된다. xy 는 두 자리 16 진수이다.


제 14 장 제네릭과 람다식

제네릭은 소스 코드를 모듈화시켜 프로그램의 재사용성을 높이고 소스 코드를 컴파일할 때 자료형 검사를 보다 엄격하게 수행하여 실행시간 오류를 최소화하기 위한 기법이다.
- 제네릭은 실행 오류를 최소화하고 컴파일할 때 대부분의 오류를 발견하게 하는 프로그래밍 기법이다.
람다식은 매개변수를 갖는 코드 블록으로 익명 클래스의 객체를 생성하는 부분을 수식화한 것을 말한다. 람다식을 사용하면 코드를 보다 간단하게 작성할 수 있다.

∙ 제네릭 클래스, 제네릭 인터페이스, 제네릭 메소드
- 클래스, 인터페이스, 메소드를 정의할 때 타입 매개변수(타입 파라미터)를 선언하고 사용할 수 있음 (자료형을 매개변수화)
- 메소드 호출 시 매개변수의 타입과 일치하는 값을 대입하는 것처럼 제네릭의 타입매개변수(또는 타입 파라미터)에 사용할 타입을 지정할 수 있다.
- 컴파일 시 엄격한 자료형 검사 : 자료형을 한정함으로써 컴파일 시점에 자료형 검사가 가능하여 찾아내기 힘든 실행 오류를 줄일 수 있다.
- 캐스트(형변환) 연산자의 사용이 불필요 : 명시적 형변환이 불필요하다
- 다양한 자료형을 처리하는 범용 알고리즘의 작성 : 여러 유형에 걸쳐 동작하는 일반화된 클래스/메소드를 정의할 수 있음. 쉽게 수정할 수 있고, 가독성도 높다.

예) ArrayList 클래스는 List 인터페이스를 구현한 클래스
class ArrayList <E> implements List <E>
…{
boolean add(E e) { … }
E get(int index) { … }
E remove(int index) { … }

}
List list1 = new ArrayList();
list1.add("hello");
String s1 = (String)list1.get(0); // get() 메소드의 반환형은 Object 유형이기 때문에 String 형 변수에 대입하기 전에 캐스트 연산자를 사용한 형변환 필요

List <String> list2 = new ArrayList<String>();
list2.add("hello");
String s2 = list2.get(0); // 형변환이 필요 없음

∙ 제네릭 클래스
- 클래스 정의에서 타입 파라미터를 선언함 (클래스를 사용할 때는 타입을 명시해야 함, 필드의 자료형, 메소드 반환형, 인자의 자료형으로 사용할 수 있음)
- 타입 파라미터는 참조형만 가능함. 즉 기본 자료형은 안됨!!!
- 컴파일 할 때, 명확한 타입 검사를 수행할 수 있음 (메소드 호출시 인자의 유형이 맞는지, 메소드 호출의 결과를 사용할 때 유형이 맞는지)
- 자료형을 매개변수로 가지는 클래스와 인터페이스를 제네릭 타입이라고 함

∙ 제네릭 클래스 정의
- class 클래스이름<T1, T2, …> { … }
- 클래스 정의에서 클래스 이름의 오른편, 각 괄호 < > 안에 타입 파라미터를 표시함
- 컴마(,)로 구분하여 여러 개의 타입 파라미터를 지정할 수 있음
- 타입 파라미터는 타입을 전달 받기 위한 것
- 타입 파라미터의 이름은 관례적으로 E, K, V, N, T …을 사용함


∙ 제네릭 클래스의 사용
- 제네릭 타입과 자료형 검사 : 제네릭 타입을 사용하지 않으면 컴파일 시점에서 오류를 검출하지 못함
- 의미가 명확하면 생성자 호출 시, 괄호만 사용할 수 있음
예) Data2<String> b3 = new Data2< >( );
- 제네릭 인터페이스를 구현하는 일반 클래스 : 클래스를 정의할 때 제네릭 인터페이스의 자료형을 지정하면 됨
- Raw 타입 : 제네릭 타입을 일반 타입처럼 사용하는 경우의 제네릭 타입을 지칭하는 용어
예) Data2 data = new Data2(“hello”); // 이때 Data2는 제네릭 타입
Data2<T> 의 raw타입 // 자료형을 Object로 처리함

∙ 제네릭 메소드
- 자료형을 매개변수로 가지는 메소드
- 하나의 메소드 정의로 여러 유형의 데이터를 처리할 때 유용함
- 메소드 정의에서 반환형 왼편, 각 괄호 <> 안에 타입 매개변수를 가짐
- 타입 매개변수를 메소드의 반환형이나 메소드 인자의 타입으로 사용할 수 있음
- 지역 변수의 타입으로 사용할 수도 있음
예) public static <T>
T getLast(T[ ] a) {
return a[a.length-1];
}
- 인스탄스 메소드와 static 메소드 모두 제네릭 메소드로 정의 가능
- 제네릭 메소드를 호출할 때, 타입을 명시하지 않아도 인자에 의해 추론이 가능함

∙ 제네릭 타입 제한
- 자료형을 매개변수화하여 클래스/인터페이스/메소드를 정의할 때, 자료형에 제한을 두는 것
- <T extends Number>와 같이 하면 T의 상한으로 정할 수 있음 (타입 매개변수는 Number의 서브 클래스라야 함)

∙ 제네릭 타입과 형변환
- 상속 관계가 있어야 상위/하위 자료형의 관계가 존재함
- Integer나 Double은 Number의 자식 클래스
- Data <Number>와 Data <Integer>는 상하위 관계가 없음

∙ 제네릭 타입 사용 시 유의사항
- 기본 자료형은 타입 매개변수로 지정할 수 없음
예) Data<int> d = new Data<>( ); //오류
- 타입 매개변수로 객체 생성을 할 수 없음
예) class Data <T> { private T t1 = new T( ); } //오류
- 타입 매개변수의 타입으로 static 필드를 선언할 수 없음
예) class Data <T> { private static T t2; } //오류
- 제네릭 타입의 배열을 선언할 수 없음
예) Data <Integer>[ ] arrayOfData; //오류

∙ 람다식
- JDK 1.8에 새롭게 포함된 기능으로 매개변수를 갖는 코드 블록으로 '익명 구현 클래스'의 객체를 생성하는 부분을 수식화 한것
- 인터페이스를 구현하는 익명 클래스의 객체 생성 부분을 수식화한 것
- 구현할 것이 1개의 추상 메소드일 때 간단히 표현할 수 있음
예)
Runnable runnable = new Runnable( ) {
public void run( ) {...}
};
위의 코드에서 객체를 생성하는 부분 'new Runnable() { public void run() {...} };'을 수식화 한 것이 람다식으로 아래와 같이 고쳐 쓸 수 있다.
예) 람다식 구문 : Runnable runnable = () -> {...} ;
- 람다식은 객체 생성 구문에서만 사용되는 특별한 수식이고 대입문 왼편에서 변수 runnable의 자료형이 Runnable 인터페이스임을 알 수 있으므로, 대입문 오른편에서 'new Runnable()'을 생략한다.
- 람다식에 사용될 수 있는 인터페이스나 추상 클래스는 메소드가 하나뿐인 것으로 제한되기 때문에 익명 클래스 정의를 위한 중괄호 '{}'와 'public void run()'이라는 메소드 서명 부분도 생략되고 괄호만 남는다.
- 여기서 화살표 '->'와 함께 추상 메소드의 몸체가 정의된다.

- 람다식 구문 : 메소드 매개변수의 괄호, 화살표, 메소드 몸체로 표현
- 인터페이스 객체변수 = (매개변수목록) -> { 실행문목록 }

∙ 람다식 기본 문법
- 익명 구현 클래스의 객체 생성 부분만 람다식으로 표현함 (익명 서브 클래스의 객체 생성은 람다식이 될 수 없음)
- 이때 인터페이스에는 추상 메소드가 1개만 있어야 함 (2개 이상의 추상 메소드를 포함하는 인터페이스는 사용 불가)
- 람다식의 결과 타입을 타깃 타입이라고 함
- 1개의 추상 메소드를 포함하는 인터페이스를 함수적 인터페이스라 함 (메소드가 1개뿐이므로 메소드 이름을 생략할 수 있음)

- 인터페이스 객체변수 = (매개변수목록) -> { 실행문목록 }
- 매개변수 목록에서 자료형은 인터페이스 정의에서 알 수 있으므로 변수 이름만 사용 가능
- 매개변수가 1개면 괄호가 생략 가능하며 변수 이름 하나만 남음
- 매개변수를 가지지 않으면 괄호만 남음
- 실행문이 1개이면 중괄호 생략 가능
- 실행문이 return문 뿐이라면 retrun과 중괄호를 동시 생략해야 함
예)

람다식의 효과
- 메소드가 하나만 정의되어 있는 인터페이스나 추상 클래스는 모두 람다식으로 익명 객체를 생성할 때 사용할 수 있다.
- 일반적으로 인터페이스로 클래스를 구현하고 그 클래스를 사용하려면 클래스로 정의한 후 객체를 생성해서 스레드를 만들거나 익명 클래스의 객체를 만들어서 스레드를 만든다.
- 람다식을 사용하면 익명 클래스를 사용하는 것과 비슷하게 클래스를 정의하지 않고 바로 스레드를 생성할 수 있다.

- 람다식은 수식이기 때문에 그 자체로 값이 되고 그 값이 쓰이는 곳에 바로 넣을 수 있다.


람다식의 활용
- JDK 1.8 버전에는 람다식을 활용할 수 있는 표준 함수적 인터페이스들을 제공하고 있다.

Consumer 인터페이스
- 매개변수는 있지만 리턴값이 없는 accept() 메소드를 제공
- 매개변수를 넘겨 주고 적당한 동작을 수행하는 용도로 사용


Supplier 인터페이스
- 매개변수는 없고 리턴값이 있는 get() 메소드를 제공


Function 인터페이스
- 매개변수도 있고 리턴값도 있는 apply() 메소드를 제공


제 15 장 java.nio 패키지의 활용

∙ java.nio 패키지
- NIO는 ‘New Input Output의 약자’
- 기존 java.io 패키지를 개선한 새로운 입출력 패키지 : java.nio.channels, java.nio.charset, java.nio.file 등
- File 클래스보다 다양한 기능을 제공하는 Path
- Files의 정적 메소드를 통한 파일/디렉터리의 읽기/쓰기, 조작
- 입력과 출력이 모두 가능한 FileChannel 클래스
- 비동기식 입출력을 위한 AsynchronousFileChannel
- JDK 7부터는 파일 I/O를 개선한 NIO2도 등장 : java.nio.file 패키지의 Path, Files, FileSystem 등

∙ Path 인터페이스
- java.nio.file 패키지에 존재하며 java.io.File 클래스를 대신함
- 파일시스템에 존재하는 파일이나 디렉터리의 경로를 표현
- 경로의 생성, 경로의 조작/비교, 경로 요소 기능 등을 제공
- Files 클래스를 이용해 Path 객체에 대한 다양한 조작이 가능함
- Path객체의 생성 방법 : 파일이나 디렉터리 위치(절대/상대)를 명시해야 함
- Paths.get("C:\\tmp\\foo"); // FileSystems.getDefault( ).getPath("…")의 줄임형
- 메소드 : int compareTo(Path other), Path getFileName( ), FileSystem getFileSystem(), Path getName(int index), int getNameCount(), Path getParent(), Path getRoot(), Iterator <Path> iterator(), File toFile( ), String toString( )

∙ FileSystem과 FileStore 클래스
- FileSystem은 파일 시스템(디스크 드라이브)에 대한 인터페이스를 제공
예) Filesystems.getDefault()로 객체를 생성
- FileStore는 파티션(또는 볼륨)을 표현함
- FileSystem의 메소드 : Iterable <FileStore>, getFileStores(), WatchService newWatchService()
- FileStore의 메소드 : String name( ), String type(), long getTotalSpace(), long getUnallocatedSpace(), long getUsableSpace()

∙ Files 클래스
- 파일 조작 기능을 제공하는 static 메소드를 제공함
- 파일이나 디렉터리의 검사/생성/삭제/복사/이동/속성관리 : boolean isDirectory(Path), boolean isRegularFile(Path), Path createFile(Path), void delete(Path), Path copy(Path, Path), Path move(Path, Path), long size(Path), UserPrincipal getOwner(Path)
- 파일의 읽기와 쓰기 등
- 메소드는 Path 객체를 인자로 가지고 작업함

∙ 버퍼
- 데이터 생산자와 프로그램(입력), 프로그램과 데이터 소비자(출력) 간 속도 차로 인해 지연이 발생할 수 있음
- 버퍼를 사용하면 지연 현상을 방지할 수 있음
- 데이터 생산자는 버퍼로 데이터를 보냄(입력)
- 프로그램은 버퍼로 데이터를 출력함(출력)


∙ buffer 클래스
- 버퍼는 데이터 보관소
- java.nio 패키지에 존재하면 Buffer는 추상 클래스 (채널 입출력에 사용되며 버퍼 단위로 입출력할 수 있음)
- 실제 사용을 위해 boolean을 제외한 모든 기본형에 대해 서브 클래스가 존재함
- ByteBuffer, CharBuffer , DoubleBuffer, IntBuffer 등

∙ buffer의 사용
- 버퍼의 생성
예) Buffer buffer = ByteBuffer.allocate(1024*1024);
byte[ ] barray = new byte[100];
Buffer bbuffer = ByteBuffer.wrap(barray);
- 버퍼의 속성
가. capacity: 버퍼의 크기(데이터의 개수)로 생성될 때 정해짐
나. limit: 읽거나 쓸 수 없는 최초 위치
다. position: 읽기나 쓰기가 적용되는 위치
라. mark: reset( ) 되었을 때 position이 가리킬 위치

- Buffer 클래스의 메소드
가. Buffer mark(); // mark를 position의 값으로 설정
나. Buffer reset(); // position을 mark의 값으로 설정
다. Buffer rewind( ); // position을 0으로 바꾸고 mark를 삭제
라. Buffer flip(); // limit를 position 값으로 설정, position은 0으로 변경, 쓰기를 끝내고 읽기를 준비하는 것
마. Buffer clear(); // 버퍼를 초기 상태로 돌림. 새로운 쓰기를 준비하는 것

∙ FileChannel 클래스
- java.io 패키지의 파일 관련 입출력 스트림을 대체
- 파일에 대한 읽기와 쓰기를 제공
- 멀티 스레드 환경에서도 안전하게 사용할 수 있음
- FileChannel 객체의 생성 방법 : FileChannel.open(Path path, OpenOption …options); // 옵션은 StandardOpenOption.READ 등
- 읽기와 쓰기 메소드 : int read(ByteBuffer dst); int write(ByteBuffer src)

∙ WatchService 1 인터페이스의 사용
- WatchService란 어떤 대상에 대해 변화나 이벤트가 생기는 것을 감시(watch), 감시 대상을 WatchService에 등록
예) Path path = Paths.get("c:\\java\\temp");
path.register(ws, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
- WatchService는 take() 메소드를 호출하여 감시를 위해 기다림
예) while(true) {
WatchKey key = ws.take();
}
- take( )가 리턴하는 WatchKey 객체를 이용하여 이벤트를 처리
- WatchKey는 감시 대상 객체의 상태 정보를 가짐
- pollEvents()를 호출하여 WatchEvent 객체를 얻고 어떤 변화가 생겼는지 알 수 있음
예) for (WatchEvent<?> event:key.pollEvents()) {
WatchEvent.Kind k= event.kind();


제 16 장 컬렉션

∙ 컬렉션
- 여러 원소를 하나의 그룹으로 묶어 관리하기 위한 것으로 컨테이너라고도 하며, 여러 원소를 하나의 그룹으로 묶어 관리해주는 객체

∙ Java Collections Framework (JCF)
- 컬렉션을 표현하고 다루기 위한 통합된 프레임워크
- 다양한 방식으로 저장, 검색, 수정, 관리하는 도구를 제공
- 컬렉션을 일관된 방법으로 다룰 수 있음
- 인터페이스: 컬렉션의 기능을 표현 : 어떻게 표현되는가와 상관없이 일관성 있게 다룸(추상 자료형)
- 클래스: 인터페이스를 구현한 클래스를 제공(자료 구조)
- 제네릭 타입으로 정의되어 있기 때문에 사용할 때에는 다루는 자료의 종류에 따라 클래스 유형을 지정해서 정의하면 된다.

∙ JCF의 인터페이스
- Set: 순서는 의미가 없으며 중복을 허용하지 않는 자료구조
- List와 Queue : 중복을 허용하고 순서에 의미가있으며 Queue는 FIFO방식
- Map : 원소가 <key, value>의 형태이며 키는 유일해야 함


∙ JCF의 클래스
- java.util 패키지에 포함되며 제네릭 타입


∙ Collection<E> 인터페이스
- Set, List, Queue에서 공통으로 지원해야 하는 기능을 정의
- 원소 삽입/삭제 메소드 : boolean add(E o) / boolean addAll(Collection<? extends E> c) / boolean remove(Object o) / boolean removeAll(Collection<?>c) / boolean retainAll(Collection<?> c) / void clear()
- 원소 탐색 메소드 : boolean contains(Object o) / boolean containsAll(Collection<?> c) / boolean isEmpty()
- 기타 메소드 : int size() / int hashCode() / Object[] toArray() / Iterator<E> iterator()

∙ ArrayList 클래스
- List 인터페이스를 구현한 클래스 : 크기조절이 가능한 배열로 구현
- 같은 자료가 중복될 수 있으며 입력된 순서대로 관리됨 : 특정 위치의 자료를 참조할 수 있음
- List 인터페이스를 살펴봐야 함

∙ List<E> 인터페이스
- 순서가 있고 중복을 허용하는 구조
- 원소를 순차적으로 처리하는 구조 : 첨자에 의한, 특정 위치의 원소 처리가 가능
- 메소드 : int indexOf(Object o) / int lastIndexOf(Object o) / E set(int index, E element) / List<E> subList(int from, int to) / E remove(int index), / boolean remove(Object o) / ListIterator<E> listIterator() / ListIterator<E> listIterator(int index)

∙ Iterator<E> 인터페이스
- 컬렉션에 저장된 원소를 차례대로 다룰 수 있음
- 다음 메소드를 제공 : boolean hasNext(), E next( ), void remove()
- HashSet, ArrayList, LinkedList 등에서 Iterator 객체를 리턴하는 메소드가 정의됨
예) List <String> list = new ArrayList <String>( );
Iterator <String> it = list.iterator( );
while(it.hasNext( )) System.out.println(it.next());

∙ LinkedList 클래스
- ArrayList와 유사함 : 앞의 예제에서 ArrayList를 LinkedList로 바꾸면 됨
- Queue 인터페이스를 구현함
- Queue 인터페이스의 메소드 : boolean offer(E), boolean add(E), E poll( ), E remove(), E peek( ), E element( )
- 스택 자료구조에서 필요한 메소드도 제공함 : void push(E), E pop( )

∙ Map<K, V> 인터페이스
- (key, value)을 갖는 원소로 구성되는 컬렉션을 다루기 위한 인터페이스
- 하나의 key에 하나의 value만 대응됨
- 메소드 : V put(K key, V value), V get(Object key), V remove(Object key), boolean containsKey(Object key), Collection<V> values(), Set<K> keyset()

∙ HashMap 클래스
- 해싱을 이용하여 Map 인터페이스를 구현한 클래스 (ArrayList나 LinkedList 클래스와 다름)
- 복잡한 자료 관리