JAVA all

01. 자바 시작

1991년에 선마이크로시스템즈제임스고슬링이란 엔지니어를 중심으로 가전제품에 사용할 소프트웨어를 개발하기 시작했다. 기존에 작성된 프로그램은 플랫폼간에 호환성이 없었다. 특히 매우 다양한 플랫폼을 갖는 가전제품을 위해 플랫폼에 독립적인 언어의 필요성이 대두되었다. 이에 선마이크로시스템스는 플랫폼 독립적이며 메모리사용량이 적은 새로은 언어와 실행체계를 개발하였고, 처음에는 오크라고 지었다. 이 새로운 언어는 초기에는 별로 알려지지 않았으나 인터넷과 웹이 엄청난 속도로 발전하면서 급속도로 퍼지게 되었다. (C보다 자바가 이식성과 호환성이 높다.) 마침내 1995년 자바라는 이름으로 새로은 기술을 발표했다. 2009년에 오라클에서 선마이크로시스템스를 인수함으로써 현재는 오라클에서 자바를 제공하고 있다.


WORA(Write Once Run Anywhere)

자바 프로그램은 어디서든 한 번 작성하면, 다시 컴파일하거나 수정하지 않고, 어떤 하드웨어에서나 운영체제에서도 실행시킬 수 있다. 이를 WORA라고 한다.(플랫폼 종속성 극복)


바이트코드

바이트코드는 자바 가상 기계에서만 실행되는 기계어로서, 어떤 CPU와도 관계 없는 바이너리 코드이다. 자바 컴파일러는 자바 소스 프로그램을 컴파일하여 바이트코드로 된 클래스 파일을 생성한다. 이 클래스파일은 컴퓨터의 CPU에 의해 직접 실행되지 않고, 자바 가상 기계가 인터프리터 방식으로 실행시킨다.

오라클에서 배포하는 JDK(Java Development Kit)에는 자바 클래스 파일을 디어셈블(disassemble)하여 바이트 코드를 볼 수 있는 도구를 제공한다.


실행환경

C에서 .exe 실행파일에는 실행에 필요한 모든 코드가 들어있어 .exe 파일만 있으면 실행에 문제가 없으나 .exe파일이 매우 큰 경우 적은 양의 메모리를 가진 컴퓨터에서는 실행을 할 수 없는 문제점이 있다.

자바는 링크과정이 없다. 자바 가상기계는 그 때 그 클래스파일을 로딩하고 실행한다. (한 자바 안에 여러개의 클래스가 들어있음)


JDK와 JRE

JDK(Java Development Kit)는 자바 개발자에게 무료로 배포하는 소프트웨어이다.(만드는 도구들이 모인거).
JRE(Java Runtime Environment)작동되는 도구들이 모인거.

JDK가 설치되면 구성중에

bin폴더가 있는데 이 파일은 실행파일이 모여있으며,

include 폴더에는 네이티브 코드 프로그래밍에 필요하는 C언어 헤더 파일이 들어있고,

jmodes 폴더에는 컴파일된 모듈 파일들이 있다.

bin 폴더 안 javac는 자바 컴파일러로 자바 소스를 바이트코드로 변환시켜주며,

java는 자바 프로그램 실행기이며 자바 가상 기계를 작동시켜 자바 프로그램을 실행시켜준다.(class 실행시켜줌)


자바의 배포판
  • Java SE(Standard Edition) - 자바 표준 배포판
  • Java Me(Micro Edition) - 모바일용 배포판. 스마트폰이나 고해상도 tv등은 안드로이드에 자리를 내주고 있어 존폐가 위태롭다.
  • Java EE(Enterprise Edition) - 기업용 배포판. 자바를 이용한 다중 사용자, 대규모 기업 응용프로그램 개발을 위한 JDK이다.

자바 API

c에서는 동적배열(malloc)을 만들어서 썼으면 여기에 와있음.

자바 API는 개발자들이 사용하도록 미리 만들어놓은 유용한 자바 클래스들의 집합이다.


자바 IDE

IDE(Intergrated Development Environment)란 단어가 뜻하는 그대로 소스 코드 편집, 컴파일, 디버깅을 한꺼번에 할 수 있는 통합 개발 환경(소프트웨어)이다. IDE하면 가장 먼저 떠오르는것은 비주얼 스튜디오일 것이다. 자바 응용프로그램 개발에 현재 많이 사용되고 있는 IDE로 이클립스가 있따. (비주얼 스튜디오는 편집기)


자바 소스 편집

자바에서는 클래스이름과 소스파일의 이름이 일치해야한다!!!!

이클립스에서 한 프로젝트 안에 main 하나 꼭! .java에는 하나의 클래스 꼭! public은 대표 대표 클래스 안에 main 메소드 존재해야 한다. (이해 안가면 p.45 필기 봐라)


자바의 특징

  • 플랫폼 독립성 : 자바는 플랫폼에 종속되지 않는 독립적인 바이트코드로 컴파일되며 자바 가상 기계만 있으면 하드웨어/운영체제를 막론하고 자바 프로그램의 실행이 가능하다.
  • 객체 지향 : 자바는 객체지향 언어로서 캡슐화, 상속, 다형성을 지원한다. 객체지향 프로그램은 해결할 과제를 객체 간의 상호 관계로 모델링하여 인간의 사고에 가깝게 표현한다.
  • 클래스로 캡슐화 : 변수나 메소드는 반드시 클래스 내에 구현하도록 한다.
  • 소스와 클래스 파일 : 클래스파일에는 반드시 하나의 자바 클래스만 들어있다.
  • 실행 코드 배포 : 자바 응용프로그램은 한 개의 클래스 파일 또는 다수의 클래스파일로 구성된다. 다수의 클래스 파일을 jar 파일 형태로 압축하여 배포하거나 실행할 수 있다.
  • 패키지 : 서로 관련 있는 클래스는 패키지로 묶어 관리한다.
  • 멀티스레드 : 하나의 자바 프로그램이 다수의 작업을 처리할 수 있도록 다수의 스레드가 동시에 실행할 수 있는 환경을 지원한다.
  • 가비지 컬렉션 : 자바 언어는 메모리를 할당받는 기능은 있지만 메모리를 반환하는 기능은 없다. 이것은 프로그래밍의 부담을 대폭 줄여준다. 프로그램 내에 사용되지 않는 메모리는 자동으로 회수된다.
  • 실시간 응용 시스템에 부적합 : 자바 응용프로그램은 실행 도중 예측할 수 없는 시점에 가비지 컬렉션이 실행되므로, 프로그램이 일시적으로 중단된다. 이런 문제로 인해 일정 시간내에 반드시 실행 결과를 내야하는 실시간 시스템에는 자바 언어가 적합하지 않다.
  • 자바 프로그램은 안전하다 : 자바언어는 타입 체크가 매우 엄격하며, 포인터의 개념이 없기 때문에 잘못된 자바 프로그램으로 컴퓨터의 시스템이 중단되는 일은 없다.
  • 프로그램 작성이 쉽다 : 포인터 개념이 없기 때문에 프로그램 작성에 부담이 적다. 또한 다양한 라이브러리와 GUI 라이브러리를 지원하므로 프로그램 작성이 빠르고 쉽다.
  • 실행 속도를 개선하기 위해 JIT 컴파일러가 사용된다. : 자바는 바이트코드를 실행하므로 실행이 느리다고 알려져있지만, 최근에는 실행하는 도중 자바 프로그램을 해당 CPU의 기계어 코드로 컴파일하고 CPU가 바로 기계어를 실행하도록 하는 JIT(Just in Time) 컴파일링 기법을 이용하므로 실행성능이 C와 거의 비슷하도록 개선되었다.

02. 자바 기본 프로그래밍

클래스 만들기

자바 프로그램의 작성에 있어 가장 기본적이면서 중요한것은 클래스를 만들고, 그 안에 변수, 상수, 함수(메소드) 등 모든 프로그램 요소를 작성한다는 점이다. 클래스 바깥에 어떤 것도 작성해서는 안된다.

public class Hello{
  ...
}

main() 메소드

main()은 반드시 public, static, void 타입으로 선언되어야하며, 한 클래스에 2개 이상의 main()을 작성하면 안된다.

public static void main(String[] args){
  ...
}


메소드

클래스의 멤버 함수를 자바에서는 메소드(method)라고 부른다. 메소드의 이름은 개발자가 지정하며, 메소드 개수에는 제한이 없다.

다음은 메소드 sum()을 작성한 사례이다.

public static int sum(int n, int m){
  return n + m;
}

변수 선언

변수(variable)란 프로그램 실행 동안 데이터를 저장하는 공간으로 개발자가 이름을 붙이고 다음과 같이 선언한다.

int i;
char a;

메소드 내에 선언되어 사용되는 변수를 지역변수(loacal variable)라고 한다. 지역변수는 메소드 내에서만 사용되며, 메소드의 실행이 끝나면 소멸된다.


식별자

클래스 이름

클래스 이름의 첫 번째 문자는 대문자로 시작하고, 여러 단어가 복합되면 각 단어의 첫 번째 문자만 대문자료 표시한다.

public class HelloWorld{}
class AutoVendingMachine{}

변수, 메소드 이름

변수와 메소드 이름은 첫 단어는 소문자로 표기하고 이후 각 단어의 첫 번째 문자만 대문자료 표기한다. 이렇게 함으로써 변수와 클래스 이름을 쉽게 구분할 수 있다.

int myAge;
boolean isSingle;
public int getAge(){return 20;}

상수 이름

상수는 이름 전체를 대문자로 표가하도록 권장한다. 상수 선언시 앞에 final 명시. (상수는 종단변수라고도 불린다.)

final double PI = 3.141592;

자바의 데이터 타입

기본 타입(basic type) : 8개 (=프리미티브 타입)

  • boolean
  • char
  • byte
  • short
  • int
  • long
  • float
  • double

레퍼런스 타입(reference type) : 1개

레퍼런스 타입은 한 가지이지만 용도는 다음과 같이 3가지 이다.

  • 배열에 대한 레퍼런스
  • 클래스(class)에 대한 레퍼런스
  • 인터페이스(interface)에 대한 레퍼런스

레퍼런스란 c의 포인터와 비슷한 개념이다. 주소값정도로 생각해라.


자바의 기본 타입

자바에서 영어든 한글이든 문자 하나는 2바이트의 유니코드로 저장된다. (c는 아스키코드) c는 영어는 1바이트 한글은 2바이트로 표현되므로 한글과 영어가 섞인 문자열이나 파일을 다루는 프로그램 작성은 까다롭다. 한편 문자열은 자바의 기본타입에 속하지 않기 때문에, 다음과 같이 자바 라이브러리에서 제공하는 String 클래스를 이용한다.

논리타입 boolean (1비트, true 또는 false)

문자타입 char (2바이트)

정수타입 byte (1바이트) 정수타입 short (2바이트) 정수타입 int (4바이트) 정수타입 long (8바이트)

실수타입 float (4바이트) 실수타입 double (8바이트)


문자열

자바에서 문자열은 기본타입에 속하지 않으며 JDK에서 제공하는 String 클래스를 이용한다. (문자열은 “”, 문자는 ‘’)


변수와 선언

변수는 데이터를 저장하는 공간이다.


리터럴(literal)

리터럴이란 프로그램에 직접 표현한 값을 말한다. 정수, 실수, 문자, 논리, 문자열 타입 모두 리터럴이 있다.


정수 리터럴

정수 리터럴은 int 타입(기본)으로 자동 컴파일된다. 만일 long 타입으로 지정하려면 숫자 뒤에 l을 붙이면 된다.

int n = 15;     //십진수 15
int m = 015;    //8진수 13
int k = 0x15;   //16진수 21
int b = 0b0101; //2진수 5

실수 리터럴

실수 리터럴은 double 타입으로 자동 처리된다. 숫자 뒤에 f를 붙이면 float, d를 붙이면 double 타입으로 강제 변환할 수 있다.


문자 리터럴

문자 리터럴은 단일 인용부호(‘‘)로 문자를 표현하거나 \u다음에 문자의 유니코드 값을 사용하여 표현한다.


특수문자 리터럴

백슬래시 다음에 특수 기호를 붙여서 표현한다. \b, \t 등…


논리 리터럴과 boolean 타입

논리 리터럴은 true, false 두 개 밖에 없으며, boolean 타입의 변수에 직접 치환하거나 조건문에 사용한다.

boolean a = true;
boolean b = 10 > 0;   //참이므로 b 값은 true
boolean c = 1;        //오류!!! C와 달리 자바에서 숫자를 참, 거짓으로 사용 불가
while(true){...}      //자바에서 무한루프. while(1)로 하면 안된다!!!!!

null 리터럴

null은 기본타입에 사용될 수 없고 객체 레퍼런스에 대입된다.

int n = null;         //오류. 기본타입에는 null값을 저장할 수 없다
String str = null;    //정상

문자열 리터럴

자바에서 문자열 리터럴을 포함하여 모든 문자열은 String 객체이다. 그러므로 문자열 리터럴은 다음과 같이 String 객체에 저장한다.

String str = "Good";

var 키워드

java 10부터 변수 타입 대신 var 키워드를 사용 할 수 있다. 또한 var의 사용은 지역변수에만 한정된다. (어떤 형태의 값이 정해지지 않았을 때 사용. 교수님은 잘 안쓰심. 명시하는게 나음)

var price = 200;  //price는 int타입으로 결정
var name = "kitae"; //name은 String 타입으로 결정
var point = new Point; //point는 Point 타입으로 결정(4장 참조)

var name; //컴파일 오류. 변수 name의 타입을 추론할 수 없음.

class는 객체를 만들기 위한 하나의 틀!!!!


타입 변환

타입변환이란 변수나 상수 혹은 리터럴의 타입을 다른 타입으로 바꾸는 것을 말한다.

자동 타입 변환

수식 내에 타입이 일치하지 않을 때 컴파일러는 오류대신 작은 타입을 큰 타입으로 자동 변환한다.


강제 타입 변환
int n = 300;
//-----------------------------------------------------------
byte b = n;   //컴파일 오류. byte는 최대 255라서 오류 발생.
byte b = (byte)n;   //n을 byte타입으로 강제 변환.

큰 타입의 값을 작은 타입으로 변환해야 할 때 컴파일러는 오류를 발생시킨다. 개발자가 이 사실을 알고도 타입 변환을 원한다면 강제 타입 변환을 지시해야 한다. 하지만 강제 변환을 하면 오류가 발생하지 않을 뿐 데이터 손실이 발생한다. 강제 타입 변환을 캐스팅(casting)이라고도 부른다.


자바에서 키 입력

System.in

키보드 장치를 직접 제어하고 키 입력을 받는 표준 입력 스트림 객체이다. System.in 을 통해 사용자로부터 키를 입력받을 수 있다. 하지만 응용프로그램은 받은 바이트 정보를 문자나 숫자로 변환해야하는 번거로움이 있다. 그러므로 키보드에서 입력된 키를 문자나 정수, 실수, 문자열 등 사용자가 원하는 타입으로 변환해주는 Scanner 클래스를 사용하는 것이 효과적이다.


Scanner 객체 생성

우선 다음과 같이 Scanner 객체를 생성한다. 그리고 Scanner를 사용하기 위해선 맨 앞 줄에 import문이 필요하다.

import java.util.Scanner;   //맨앞 import는 C에서 include

Scanner scanner = new Scanner(System.in);

Scanner 클래스는 사용자가 입력하는 키 값을 공백문자를 기준으로 분리하여 토큰 단위로 읽는다.

Scanner scanner = new Scanner(System.in);

String name = scanner.next();
String city = scanner.next();

int age = scanner.nextInt();            //정수로 입력받겠다
double weight = scanner.nextDouble();   //실수값을 입력받겠다
boolean isSingle - scanner.nextBoolean();
nextLine()과 next()

공백이 낀 문자열을 입력받기 위해서는 nextLine()을 사용한다. 다른 입력 없이 enter만 입력될 때 nextLine()은 빈 문자열(““)을 리턴하면서 바로 돌아오지만, next()는 문자열이나 숫자 등 다른 키가 입력될 때까지 기다린다. next()는 결고 빈 문자열(““)을 리턴하지 않는다.


Scanner 객체 닫기
scanner.close();

scanner 객체가 닫히면, System.in도 함께 닫히므로 더이상 키 입력을 받을 수 없다.

응용프로그램에 scanner닫는 코드가 없으면 컴파일시 경고가 발생하지만 실행하는데는 특별히 문제가 없다. 프로그램이 종료되면 자동으로 닫힌다.

개발자는 응용프로그램 전체에 Scanner 객체를 하나만 생성하고 공유하는것이 바람직하다. Scanner 객체를 여러개 생성해도 모두 하나뿐인 System.in을 공유하므로 한군데서 닫아버리면 System.in도 닫혀버려 응용프로그램 내 다른 Scanner 객체에서 키 입력을 받을 수 없게 된다.


연산

연산자 우선순위

산술 연산

더하기, 빼기, 곱하기, 나누기, 나머지 5개.

% 연산자는 다음과 같이 정수 n이 홀수인지 짝수인지 구분할 때 유용하게 활용되며, n 값이 3의 배수인지 확인하기 위해서도 활용된다.

int r = n % 2;  //n이 홀수이면 r은 1, 짝수이면 r은 0

int s = n % 3;  //n이 3의 배수이면 s는 0

증감 연산

int a = 1;
a++;   //a값 1 증가. a는 2. 후위연산자
++a;   //다시 a 값 1 증가. a는 3. 전위 연산자

a++은 a를 1 증가하고 전의 값 반환 ++a는 a를 1 증가하고 증가된 값 반환


대입 연산(a=b)

비교연산(true, false)

논리연산(AND, OR, XOR, NOT)

조건연산(삼항 연산자)

비트 연산(비트논리연산(AND, OR, XOR, NOT), 비트 시프트 연산)

조건문(if문, if-else문, switch문).

p.94~103. 예제문제


p.110~112 실습문제

1 Scanner 클래스를 이용하여 원화를 입력받아 달러로 바꾸어 다음 예시와 같이 출력하는 프로그램을 작성하라. $1=1100원으로 가정하고 계산하라.

import java.util.Scanner;

public class Hello {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("원화를 입력하세여(단위 원) >> ");
		int change = scanner.nextInt();
		double account = change / 1100;
		
		System.out.printf(change + "원은 $" + account + "입니다.");

    scanner.close();
	}

}

2 Scanner 클래스를 이용하여 2자리의 정수(10~99사이)를 입력받고, 십의 자리와 1의 자리가 같은지 판별하여 출력하는 프로그램을 작성하라.

import java.util.Scanner;

public class Hello {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("2자리수 정수 입력(10~99) >> ");
		int value = scanner.nextInt();
		
		int a = value / 10;
		int b = value % 10;
		
		if(a == b) {
			System.out.printf("같다");
		}else {
			System.out.printf("다르다");
		}
		
		scanner.close();
	}

}

3 Scanner 클래스를 이용하여 정수로 된 돈의 액수를 입력받아 오만 원권, 만 원군, 천 원권, 500원짜리 동전, 100원짜리 동전, 50원짜리 동전, 10원짜리 동전, 1원짜리 동전 각 몇 개로 변환되는지 출력하라.

import java.util.Scanner;

public class Hello {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("금액을 입력하시오 >> ");		
		int won = s.nextInt();
		
		int num50000 = won / 50000;
		won = won - (num50000*50000);
		
		int num10000 = won / 10000;
		won = won - (num10000*10000);
		
		int num1000 = won / 1000;
		won = won - (num1000*1000);
		
		int num500 = won / 500;
		won = won - (num500*500);
		
		int num100 = won / 100;
		won = won - (num100*100);		
		
		int num50 = won / 50;
		won = won - (num50*50);		
		
		int num10 = won / 10;
		won = won - (num10*10);
		
		int num1 = won / 1;
		won = won - num1;
		
		System.out.println("오만원권 " + num50000 + "매");
		System.out.println("만원권 " + num10000 + "매");
		System.out.println("천원권 " + num1000 + "매");
		System.out.println("오백원 " + num500 + "개");
		System.out.println("백원 " + num100 + "개");
		System.out.println("오십원 " + num50 + "개");
		System.out.println("십원 " + num10 + "개");
		System.out.println("일원 " + num1 + "개");
		
		s.close();
	}
}

4 Scanner 클래스로 정수 3개를 입력받고 3개의 숫자 중 중간 크기의 수를 출력하라. 평균값을 구하는 것이 아님에 주의하라.

import java.util.Scanner;

public class Hello {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("정수 3개 입력 >> ");
		int num1 = s.nextInt();
		int num2 = s.nextInt();
		int num3 = s.nextInt();
		
		int value = 0;
		if(num1 > num2 && num1 < num3) {
			value = num1;
		}else if(num2 > num3 && num2 < num1) {
			value = num2;
		}else if(num3 > num1 && num3 < num2) {
			value = num3;
		}
		
		System.out.print("중간 값은 " + value);
		
		s.close();
	}
}

5 Scanner를 이용하여 삼각형의 변의 길이를 나타내는 정수 3개를 입력받고 이 3개의 수로 삼각형을 만들 수 있는지 판별하라. 삼각형이 되려면 두 변의 합이 다른 한 변의 합보다 커야 한다.

import java.util.Scanner;

public class Hello {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("정수 3개를 입력하세요 >> ");
		int num1 = s.nextInt();
		int num2 = s.nextInt();
		int num3 = s.nextInt();
		
		
		
		if( (num1 + num2 < num3) || (num1 + num3 < num2) || (num2 + num3 < num1) ) {
			System.out.println("삼각형이 안됩니다.");
		}else {
			System.out.println("삼각형이 됩니다.");
		}
		
		s.close();
	}
}

6 369게임을 간단히 작성해보자. 1~99까지의 정수를 입력받고 정수에 3, 6, 9 중 하나가 있는 경우는 “박수짝”을 출력하고 두 개 있는 경우는 “박수짝짝”을 출력하는 프로그램을 작성하라. 예를 들면, 키보드로 입력된 수가 13인 경우 “박수짝”을, 36인 경우 “박수짝짝”을 출력하면 된다.

import java.util.Scanner;

public class Hello {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("1~99사이의 정수를 입력하시오 >> ");
		int num = s.nextInt();
		
		int unit = num % 10;
		int ten = num / 10;
		
		if( unit == 3 || unit == 6 || unit == 9 ) {
			System.out.print("박수짝");
			if(ten == 3 || ten == 6 || ten == 9) {
				System.out.println("짝");
			}
		}else if( ten == 3 || ten == 6 || ten == 9 ){
			System.out.print("박수짝");
		}else {
			System.out.print("박수 없어");
		}
		
		s.close();
	}
}

7 2차원 평면에서 직사각형은 왼쪽 상단 모서리와 오른쪽 하단 모서리의 두 점으로 표현한다. (100, 100)과 (200, 200)의 두 점으로 이루어진 사각형이 있을 때, Scanner를 이용하여 정수 x와 y값을 입력받고 점 (x, y)가 이 직사각형 안에 있는지를 판별하는 프로그램을 작성하라.

import java.util.Scanner;

public class Hello {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("점 x,y의 좌표를 입력하시오 >> ");
		int x = s.nextInt();
		int y = s.nextInt();
		
		if( (x >= 100 && x <= 200) && (y >= 100 && y <= 200) ) {
			System.out.println("(" + x + "," + y + ") 는 사각형 안에 있습니다.");
		}else {
			System.out.println("범위를 벗어났습니다.");
		}
		
		s.close();
	}
}

8 2차원 평면에서 직사각형은 문제 7번처럼 두 점으로 표현된다. 키보드로부터 직사각형을 구성하는 두 점 (x1, y1), (x2, y2)를 입력받아 (100, 100), (200, 200)의 두 점으로 이루어진 직사각형과 충돌하는지 판별하는 프로그램을 작성하라.

import java.util.Scanner;

public class Hello {
	public static boolean inRect(int x, int y) {
		if(x >= 100 && x <=200 || y >=100 && y <= 200) {
			return true;
		}else {
			return false;
		}
	}
	
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("두 점 (x1, y1), (y1, y2)의 값을 입력 >> ");
		int x1 = s.nextInt();
		int y1 = s.nextInt();
		int x2 = s.nextInt();
		int y2 = s.nextInt();
		
		boolean num1 = inRect(x1, y1);
		boolean num2 = inRect(x2, y2);
		
		if(num1 == true || num2 == true) {
			System.out.println("충돌합니다");
		}else {
			System.out.println("충돌하지 않습니다");
		}
		
		s.close();
	}
}

9 원의 중심을 나타내는 한 점과 반지름을 실수 값으로 입력받아라. 그리고 실수 값으로 다른 점 (x, y)를 입력받아 이 점이 원의 내부에 있는지 판별하여 출력하라.

import java.util.Scanner;

public class Hello {
	
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("원의 중심과 반지름 입력 >> ");
		int circle_x = s.nextInt();
		int circle_y = s.nextInt();
		double r = s.nextDouble();
		System.out.print("점 입력");
		int x = s.nextInt();
		int y = s.nextInt();
		
		double distance = Math.sqrt(((x - circle_x) * (x - circle_x)) + ((y - circle_y) * (y - circle_y)));
		
		if(distance < r) {
			System.out.println("점 " + x + "," + y + "는 원 안에 있다.");
		}else {
			System.out.println("없다");
		}
		
		s.close();
	}
}

10 원의 정보를 받기 위해 키보드로부터 원의 중심을 나타내는 한 점과 반지름을 입력받는다. 두 개의 원을 입력받고 두 원이 서로 겹치는지 판단하여 출력하라.

import java.util.Scanner;

public class Hello {
	
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("첫번째 원의 중심과 반지름 입력 >> ");
		int x1 = s.nextInt();
		int y1 = s.nextInt();
		double r1 = s.nextDouble();		
		
		System.out.print("두번째 원의 중심과 반지름 입력 >> ");
		int x2 = s.nextInt();
		int y2 = s.nextInt();
		double r2 = s.nextDouble();
		
		double distance1 = Math.sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2)));
		
		if(distance1 <= r1+r2) {
			System.out.println("원이 겹침");
		}else {
			System.out.println("원이 안겹침");
		}
		
		s.close();
	}
}

11 숫자를 입력받아 3~5는 “봄”, 6~8은 “여름”, 9~11은 “가을”, 12,1,2의 경우 “겨울”을, 그 외 숫자를 입력한 경우 “잘못입력”을 출력하는 프로그램을 작성하라.

1) if-else 문을 이용해라.

import java.util.Scanner;

public class Hello {
	
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("달을 입력하세요(1~12) >> ");
		int season = s.nextInt();		
		
		if( (season == 3) || (season == 4) || (season == 5) ) {
			System.out.println("봄");
		}else if((season == 6) || (season == 7) || (season == 8)) {
			System.out.println("여름");
		}else if((season == 9) || (season == 10) || (season == 11)) {
			System.out.println("가을");
		}else if((season == 12) || (season == 1) || (season == 2)) {
			System.out.println("겨울");
		}else {
			System.out.println("잘못 입력");
		}
		
		s.close();
	}
}

2) switch 문을 이용해라.

import java.util.Scanner;

public class Hello {
	
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		
		System.out.print("달을 입력하세요(1~12) >> ");
		int season = s.nextInt();		
		
		switch(season) {
			case 3 :
			case 4 :
			case 5 :
				System.out.print("봄");
				break;
			case 6 :
			case 7 :
			case 8 :
				System.out.print("여름");
				break;
			case 9 :
			case 10 :
			case 11 :
				System.out.print("가을");
				break;
			case 12 :
			case 1 :
			case 2 :
				System.out.print("겨울");
				break;
			default : 
				System.out.print("잘못입력");
		}
		
		s.close();
	}
}

12 사칙 연산을 입력받아 계산하는 프로그램을 작성하고자 한다. 연산자는 +, -, *, / 의 네 가지로 하고 피연산자는 모두 실수로 한다. 피연산자와 연산자는 실행 사례와 같이 빈 칸으로 분리하여 입력한다. 0으로 나누기 시 “0으로 나눌 수 없습니다.”를 출력하고 종료한다.

1) if-else 문

import java.util.Scanner;

public class Hello {
	public static void main(String[] args) {
		
		System.out.print("사칙연산 입력 >> ");
		Scanner scanner = new Scanner(System.in);
		int num1 = scanner.nextInt();
		String value = scanner.next();
		int num2 = scanner.nextInt();
		
		int result = 0;
		if(value.equals("+")) {
			result = num1+num2;
		}else if(value.equals("-")) {
			result = num1-num2;
		}else if(value.equals("*")) {
			result = num1*num2;
		}else if(value.equals("/")){
			if(num2 == 0) {
				System.out.println("0으로 나눌 수 없습니다.");
				
				scanner.close();  // return(끝내기) 하기전에 닫아줌
				return;  //안끝내주면 아래의 ~의 계산 결과 뜸
				
			}else {
				result = num1/num2;
			}
		}else {
			System.out.println("사칙연산이 아닙니다.");
			
			scanner.close();  // return(끝내기) 하기전에 닫아줌
			return;  //안끝내주면 아래의 ~의 계산 결과 뜸
		}
		
		System.out.println(num1 + value + num2 + "의 계산 결과는 " + result);
		
		scanner.close();
	}
}

2) switch문

import java.util.Scanner;

public class Hello {
	public static void main(String[] args) {
		
		System.out.print("사칙연산 입력 >> ");
		Scanner scanner = new Scanner(System.in);
		int num1 = scanner.nextInt();
		String value = scanner.next();
		int num2 = scanner.nextInt();
		
		int result = 0;
		switch(value) {
			case "+" :
				result = num1 + num2;
				break;
			case "-" :
				result = num1 - num2;
				break;
			case "*" :
				result = num1 * num2;
				break;
			case "/" : 
				if(num2 == 0) {
					System.out.println("0으로 나눌 수 없습니다.");
					scanner.close();
					return;
				}
				result = num1 / num2;
				break;
			default:
				System.out.println("사칙연산이 아닙니다");
				scanner.close();
				return;
		}
		
		System.out.println(num1 + value + num2 +"의 계산 결과는 " + result);
		
		scanner.close();
	}
}

반복문과 배열 그리고 예외 처리

반복문 (for문, while문, do-while문)

continue문과 break문


배열

legnth 필드를 이용하여 배열의 크기 구하기

length가 c에서는 말록. 훨씬 단순화 됐다!

예제 3-8) 배열 원소의 평균 구하기

import java.util.Scanner;

public class ArrayLength{
  public statatic void main(String[] args){
    int intArray[] = new int[5];
    int sum = 0;

    Scanner scanner = new Scanner(System.in);
    System.out.print(intArray.legnth + "개의 정수를 입력하세요 >>");
    for(int i = 0; i < intArray.legnth; i++){
      intArray[i] = scanner.nextInt();
    }

    for(int i = 0; i < intArray.length; i++){
      sum += intArray[i];
    }

    System.out.print("평균은 " +(double)sum/intArray.length);
    scanner.close();
  }
}

배열과 for-each 문

for(변수 : 배열레퍼런스){
  ...반복작업문...
}
int [] n = {1,2,3,4,5};
int sum = 0;
for (int k : n) {     //변수와 위에 선언한 n의 타입은 동일해야한다(int)
  sum += k;
}

//위아래 같음-------------------------------------------

for(int i = 0; i < n.length; i++){
  int k = n[i];
  sum += k;
}

예제 3-9) for-each문 활용

public class foreachEx{
  enum Week {, , , , , , }

  public static void main(String[] args){
    int [] n = {1,2,3,4,5};
    String names[] = {"사과","배","바나나","체리","딸기","포도"};

    int sum = 0;

    for(int k : n){
      System.out.print(k + " ");
      sum += k;
    }
    System.out.println("합은" + sum);

    for(String s : name){
      System.out.print(s + " ");
    }
    System.out.println();

    for(Week day : Week.values()){
      System.out.print(day + "요일 ");
    }
    System.out.println();
  }
}

//결과
//1 2 3 4 5 합은 15
//사과 배 바나나 체리 딸기 포도
//월요일 화요일 수요일 목요일 금요일 토요일 일요일

다차원 배열

배열은 무조건 참조! c는 배열 선언 시 시작 주소값 가짐. 자바는 실행시 크기 잡음?(c는 컴파일시)

예제 3-10) 2차원 배열에 학년별로 1, 2학기 성적으로 저장하고, 4년간 전체 평점 평균을 출력하라.

public class ScoreAverage{
  public static void main(String[] args){
    double score[][] = { {3.3, 3.4}, {3.5, 3.6}, {3.7, 4.0}, {4.1, 4.2} };
    double sum = 0;

    for (int year = 0; year<score.length; year++){  //각 학년별로 번복
      for(int term=0; term<score[year].length; term++){  //학기별로 번복
        sum += score[year][term];
      }
    }

    int n = score.length; //배열의 행 개수, 4(4학년)
    int m = score[0].length; //배열의 열 개수, 2(2학기)
    System.out.println("4년 전체 평점 평균은 " + sum/(n*m));
  }
}

//결과
//4년 전체 평점 평균은 3.725

비정방형 배열

int i [][]; //2차원 배열의 레퍼런스 변수 i 선언. 공간만들기!!!!!
i = new int [4][];  //각 행을 가리키는 레퍼런스 배열 생성. 행만들기!!!!!
i[0] = new int[1];  //첫째 행에 1 크기의 배열 생성. 각 행에 크기 연결!!!!!
i[1] = new int[2];  //둘째 행에 2 크기의 배열 생성
i[2] = new int[3];  //셋째 행에 3 크기의 배열 생성
i[3] = new int[4];  //넷째 행에 4 크기의 배열 생성

여기서 length 필드의 의미는

  • i.length -> 2차원 배열의 의 개수, 4
  • i[0].length -> 0번재 행의 의 개수, 1

예제 3-11) 다음 그림과 같은 비정방형 배열을 만들어 값을 초기화하고 출력하라.

10 11 12
20 21
30 31 32
40 41

public class SkewedArray{
  public static void main(String[] args){
    int intArray[][] = new int[4][];
    intArray[0] = new int[3];
    intArray[1] = new int[2];
    intArray[2] = new int[3];
    intArray[3] = new int[2];

    for(int i=0; i<intArray.length; i++){
      for(int j=0; j<intArray[i].length; j++){
        intArray[i][j] = (i+1)*10 + j;
      }
    }

    for(int i=0; i<intArray.length; i++){
      for(int j=0; j<intArray[i].length; j++){
        System.out.print(intArray[i][j] + " ");
      }
      System.out.println();
    }
  }
}

메소드에서 배열 리턴


main() 메소드

  • main() 메소드는 public 속성이다. : 접근제어. 메소드가 다른 클래스에서 호출 가능함을 나타낸다.
  • main() 메소드는 static 속성이다. : 항시 사용가능한 메소드
  • main() 메소드의 리턴 타입은 void이다. : 값 없음

자바의 예외 처리

간단하게 될게 아님. 잘쓰면 약, 잘못쓰면 독 자바에서 오동작이나 결과에 악영향을 미칠 수 있는 실행 중 발생한 오류를 예외라고 한다.

  • 정수를 0으로 나누는 경우
  • 배열의 크기보다 큰 인덱스로 배열의 원소를 접근하는 경우
  • 존재하지 않는 파일을 읽으려고 하는 경우
  • 정수 입력을 기다리는 코드가 실행되고 있을 때, 사용자가 문자를 입력한 경우

예외처리 try-catch-finally문

무분멸하게 사용시 죽지 않고 오류를 발생할 수도 있음. 에러코드를 같이 달아야 함.

try{
  예외가 발생할 가능성이 있는 실행문(try 블록). (정수입력인데 문자 입력시)
}
catch(처리할 예외 타입 선언){
  예외 처리문(catch 블록). (후처리할거). 여러개 사용 가능하나 잘못타서 잘못들어갈  있음
}
finally{
  예외발생 여부와 상관 없이 무조건 실행되는 문장(finally 블록). 생략 가능. (접속 끊기)
}
예외타입(예외 클래스) 예외 발생 경우 패키지
ArithmeticException 정수를 0으로 나눌 때 발생 java.lang
NullPinterException null 레퍼런스를 참조할 때 발생(포인터는 있는데 참조 대상이 없을 때) java.lang
ClassCastException 변환할 수 없는 타입으로 객체를 변환할 때 발생 java.lang
OutOfMemoryError 메모리가 부족한 경우 발생 java.lang
ArrayIndexOutOfBoundsException 배열의 범위를 벗어난 접근 시 발생 java.lang
IllegalArgumentException 잘못된 인자 전달 시 발생 java.lang
IOException 입출력 동작 실패 또는 인터럽트 시 발생 java.io
NumberFormatException 문자열이 나타낸느 숫자와 일치하지 않는 타입의 숫자로 변환 시 발생 java.lang
InputMismatchException Scanner 클래스의 nextInt()를 호출하여 정수로 입력받고자 하였지만, 사용자가 ‘a’ 등과 같이 문자를 입력한 경우 java.util

예제 3-16) 배열의 인덱스가 범위를 벗어날 때 발생하는 ArrayIndexOutOfBoundsException을 처리하는 프로그램을 작성하라.

public class ArrayException{
  public static void main(String[] args){
    int[] intArray = new int[5];
    intArray[0] = 0;

    try{
      for(int i=0; i<5; i++){
        intArray[i+1] = i+1 + intArray[i];
        System.out.println("intArray [" + i + "]" + "=" +intArray[i]);
      }
    }
    catch(ArrayIndexOutOfBoundsException e){
      System.out.println("배열의 인덱스가 범위를 벗어났습니다.");
    }
  }
}

p.164~170 실습문제

1 다음 프로그램에 대해 물음에 답하라?

int sum=0, i=0;
while(i < 100){
  sum = sum + i;
  i += 2;
}
System.out.println(sum);

1) 무엇을 계산하는 코드이며 실행 결과 출력되는 내용은? -> 1~100까지 짝수의 합. 2450

2) 위의 코드를 main()메소드로 만들고 WhileTest 클래스로 완성하라.

public class WhileTest {
	public static void main(String[] args) {
		
		int sum=0, i=0;
		while(i < 100){
		  sum = sum + i;
		  i += 2;
		}
		System.out.println(sum);
	}
}

3) for 문을 이용하여 동일하게 실행되는 ForTest 클래스를 작성하라.

public class ForTest {
	public static void main(String[] args) {
		int sum=0;
		
		for(int i = 0; i < 100; i += 2) {
			sum = sum + i;
		}
		System.out.println(sum);
	}
}

4) do-while 문을 이용하여 동일하게 실행되는 DoWhileTest 클래스를 작성하라.

public class DoWhileTest {
	public static void main(String[] args) {
		int sum=0, i=0;
		
		do{
			sum = sum + i;
			i += 2;
		}while(i<100);
		
		System.out.println(sum);
	}
}

2 다음 2차원 배열 n을 출력하는 프로그램을 작성하라

int n[][] = { {1}, {1,2,3}, {1}, {1,2,3,4}, {1,2} };

1
1 2 3
1
1 2 3 4
1 2

public class DoWhileTest {
	public static void main(String[] args) {
		int n[][] = { {1}, {1,2,3}, {1}, {1,2,3,4}, {1,2} };
		
		int sum;
		for(int i = 0; i < n.length; i++) {
			for(int k = 0; k < n[i].length; k++ ) {
				sum = n[i][k];
				System.out.print(sum + " ");
			}
			System.out.println();
		}
	}
}

3 Scanner를 이용하여 정수를 입력받고 다음과 같이 *를 출력하는 프로그램을 작성하라. 다음은 5를 입력받았을 경우이다.

정수를 입력하시오»>5 *** ** *** ** *

import java.util.Scanner;

public class DoWhileTest {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("정수를 입력하세요 >> ");
		int star = scanner.nextInt(); 
		
		for(int i = star; i >= 0; i--) {	
			for(int k = 1; k <= i; k++) {
				System.out.print("*");
			}
			System.out.println();
		}
		
		scanner.close();
	}
}

4 Scanner를 이용하여 소문자 알파벳을 하나 입력받고 다음과 같이 출력하는 프로그램을 작성하라. 다음은 e를 입력받았을 경우이다.

소문자 알파벳 하나를 입력하시오»e abcde abcd abc ab a

import java.util.Scanner;

public class DoWhileTest {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("소문자 알파벳 하나를 입력하세요 >> ");
		String apb = scanner.next(); 
		char c = apb.charAt(0);
		
		for(char i = c; i >= 'a'; i--) {	
			for(char k = 'a'; k <= i; k++) {
				System.out.print(k);
			}
			System.out.println();
		}
		
		scanner.close();
	}
}

5 양의 정수를 10개 입력받아 배열에 저장하고, 배열에 있는 정수 중에서 3의 배수만 출력하는 프로그램을 작성하라.

import java.util.Scanner;

public class DoWhileTest {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("양의 정수 10개를 입력하시오 >> ");
		int num1 = scanner.nextInt();
		int num2 = scanner.nextInt();
		int num3 = scanner.nextInt();
		int num4 = scanner.nextInt();
		int num5 = scanner.nextInt();
		int num6 = scanner.nextInt();
		int num7 = scanner.nextInt();
		int num8 = scanner.nextInt();
		int num9 = scanner.nextInt();
		int num10 = scanner.nextInt();
		
		int arr[] = {num1,num2,num3,num4,num5,num6,num7,num8,num9,num10};
		
		System.out.print("3의 배수는 ");
		for(int i=0; i<arr.length; i++) {
			if(arr[i]%3 == 0) {
				System.out.print(arr[i] + " ");
			}
		}
		
		scanner.close();
	}
	
	//------------------------------------------------------------------------
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		int arr[] = new int[10];
		System.out.print("양의 정수 10개를 입력하시오 >> ");
		
		for(int i=0; i<arr.length; i++) {
			arr[i] = scanner.nextInt();
		}		
		
		System.out.print("3의 배수는 ");
		for(int i=0; i<arr.length; i++) {
			if(arr[i]%3 == 0) {
				System.out.print(arr[i] + " ");
			}
		}
		
		scanner.close();
	}
}

6 배열과 반복문을 이용하여 프로그램을 작성해보자. 키보드에서 정수로 된 돈의 액수를 입력받아 오만 원권, 만 원권, 천 원권, 500원짜리 동전, 100원짜리 동전, 50원짜리 동전, 10원짜리 동전, 1원짜리 동전이 각 몇 개로 변환되는지 예시와 같이 출력하라. 이 때 반드시 다음 배열을 이용하고 반복문으로 작성하라.

int [] unit = {50000, 10000, 1000, 500, 100, 50, 10, 1};  //환산할 돈의 종류
import java.util.Scanner;

public class DoWhileTest {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("금액을 입력하시오 >> ");
		int [] unit = {50000, 10000, 1000, 500, 100, 50, 10, 1};  //환산할 돈의 종류
		
		int won = scanner.nextInt();
		
		for(int i=0; i<unit.length; i++) {
			int value = won / unit[i];
			System.out.println(unit[i] + "원 짜리 : " + value + "개");
			won = won - (value*unit[i]);
		}
		
		scanner.close();	
	}
}

7 정수를 10개 저장하는 배열을 만들고 1에서 10까지 범위의 정수를 랜덤하게 생성하여 배열에 저장하라. 그리고 배열에 든 숫자들과 평균을 출력하라.

public class DoWhileTest {
	public static void main(String[] args) {
		int arr[] = new int [10];
		
		System.out.print("랜덤한 정수들 : ");
		
		int sum=0;		
		for(int i=0; i<arr.length; i++) {
			arr[i] = (int)(Math.random()*10 + 1);
			System.out.print(arr[i] + " ");
			
			sum = sum + arr[i];
		}
		System.out.println();
		
		double avg = sum / arr.length;
		
		System.out.print("평균은 " + avg);
	}
}

8 정수를 몇 개 저장할지 키보드로부터 개수를 입력받아(100보다 작은 개수) 정수 배열을 생성하고, 이곳에 1에서 100까지 범위의 정수를 랜덤하게 삽입하라. 배열에는 같은 수가 없도록 하고 배열을 출력하라.

import java.util.Scanner;

public class DoWhileTest {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("정수 몇개?(100보다 작은 개수) >> ");
		int num = scanner.nextInt();
		
		int arr[] = new int[num];
		
		for(int i=0; i<num; i++) {
			arr[i] = (int)(Math.random()*num + 1);
			
			for(int k=0; k<i; k++) {
				if(arr[i] == arr[k]) {
					i--;
				}
			}
		}
		
		for(int j=0; j<num; j++) {
			System.out.print(arr[j] + " ");
		}		
		
		scanner.close();
	}
}

9 4x4의 2차원 배열을 만들고 이곳에 1에서 10까지 범위의 정수를 랜덤하게 생성하여 정수 16개를 배열에 저장하고, 2차원 배열을 화면에 출력하라.

public class DoWhileTest {
	public static void main(String[] args) {
		int arr[][] = new int [4][4];
		
		for(int i=0; i<arr.length; i++) {
			for(int k=0; k<arr[i].length; k++) {
				arr[i][k] = (int)(Math.random()*10 + 1);
				System.out.print(arr[i][k] + " ");
			}
			System.out.println();
		}
	}
}

10 4x4의 2차원 배열을 만들고 이곳에 1에서 10까지 범위의 정수를 10개만 랜덤하게 생성하여 임의의 위치에 삽입하라. 동일한 정수가 있어도 상관없다. 나머지 6개의 숫자는 모두 0이다. 만들어진 2차원 배열을 화면에 출력하라.

public class DoWhileTest {
	public static void main(String[] args) {
		int arr[][] = new int[4][4];  //처음에 배열을 만들면 이미 0으로 초기화되어있음. 랜덤으로 10곳에 숫자 넣어주면 나머지 자동으로 0
		
		for(int j=0; j<10; j++) {
			int n = (int)(Math.random()*4);  //배열 위치
			int m = (int)(Math.random()*4);  //배열 위치
			
			if(arr[n][m] == 0) {  //랜덤입력이 안 된 곳이어야 숫자 넣을 수 있음.
				int x = (int)(Math.random()*10 + 1);
				arr[n][m] = x;
			}else {
				j--;
			}
		}
		
		for(int i=0; i<arr.length; i++) {
			for(int k=0; k<arr[i].length; k++) {				
				System.out.print(arr[i][k] + " ");
			}
			System.out.println();
		}
	}
}

11 다음과 같이 작동하는 Average.java를 작성하라. 명령행 인자는 모두 정수만 사용되며 정수들의 평균을 출력한다. 다음 화면은 컴파일된 Average.class 파일을 c:\Temp 디렉터리에 복사한 뒤 실행한 경우이다. 원본 Average.class 파일은 이클립스의 프로젝트 폴더 밑에 bin 폴더에 있다.

??????????????????????????????????????????????????????????????????????

public class Chap03_11 {

	public static void main(String args[]) {
		
		int sum=0;
		double averg=0;
		for(int i=0;i<args.length;i++)
			sum+=Integer.parseInt(args[i]);
		averg=(double)sum/args.length;
		System.out.println(averg);
	}
}

12 다음과 같이 작동하는 Add.java를 작성하라. 명령행 인자 중에서 정수 만을 골라 합을 구하라. 다음 화면은 Add.class 파일을 c:\Temp 디렉터리에 복사한 뒤 실행한 경우이다. 원본 Add.class 파일은 이클립스 프로젝트 폴더 밑에 bin 폴더에 있다.

????????????????????????????????????????????????????????????????????

public class Chap03_12 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		int num=0;
		int sum=0;

		for(int i=0;i<args.length;i++) {
			try {
					num=Integer.parseInt(args[i]);
					sum+=num;
			}
			catch (NumberFormatException e) {
			}
		}
		System.out.println(sum);
	}

}

13 반복문을 이용하여 369게임에서 박수를 쳐야 하는 경우를 순서대로 화면에 출력해보자. 1부터 시작하며 99까지만 한다. 실행 사례는 다음과 같다. (3,6,9 박수짝 / 두번씩은 박수짝짝)

public class DoWhileTest {
	public static void main(String[] args) {
		for(int i=1; i<100; i++) {
			if(i == 3 || i == 6 || i == 9) {
				System.out.println(i + "박수짝");				
			}else if(i/10 == 3 || i/10 == 6 || i/10 == 9) {
				System.out.print(i + "박수짝");
				if(i%10 == 3 || i%10 == 6 || i%10 == 9) {
					System.out.print("짝");
				}
				System.out.println();
			}else if(i%10 == 3 || i%10 == 6 || i%10 == 9) {
				System.out.println(i + "박수짝");
			}
		}
	}
}

14 다음 코드와 같이 과목과 점수가 짝을 이루도록 2개의 배열을 작성하라.

String course [] = { "Java", "C++", "HTML5", "컴퓨터구조", "안드로이드" };
int score[] = {95, 88, 76, 62, 55};

그리고 다음 예시와 같이 과목 이름을 입력받아 점수를 출력하는 프로그램을 작성하라. “그만”을 입력받으면 종료한다.

import java.util.Scanner;

public class DoWhileTest {
	public static void main(String[] args) {
		
		Scanner scanner = new Scanner(System.in);
		String course [] = { "Java", "C++", "HTML5", "컴퓨터구조", "안드로이드" };
		int score[] = {95, 88, 76, 62, 55};
		
		
		while(true) {
			System.out.print("과목 이름 >> ");
			String name = scanner.next();
			
			if(name.equals("그만")) {
				break;
			}
			
			for(int i=0; i<5; i++) {
				if(course[i].equals(name)) {
					System.out.println(course[i] + "의 점수는 " + score[i]);
					break;
				}else if(i == 4) {
					System.out.println("없는 과목입니다.");
				}
			}
		}
		
		scanner.close();
	}
}

15 다음은 2개의 정수를 입력 받아 곱을 구하는 Multiply 클래스이다.

import java.util.Scanner;
public class Multiply{
  public static void main(String[] args){
    Scanner scanner = new Scanner(System.in);
    System.out.print("곱하고자 하는 두 수 입력 >> ");
    int n = scanner.nextInt();
    int m = scanner.nextInt();
    System.out.print(n + "x" + m + "=" n*m);
    scanner.close();
  }
}

다음과 같이 실행할 때 프로그램은 10과 5를 곱해 50을 잘 출력한다.(10, 5)
하지만, 다음과 같이 실수를 입력하였을 때, 예외가 발생한다.(2.4, 4) 다음과 같이 실수가 입력되면 정수를 다시 입력하도록 예외 없이 정상적으로 처리되도록 예외 처리 코드를 삽입하여 Multiply 클래스를 수정하라.

import java.util.Scanner;
import java.util.InputMismatchException;

public class Multiply{
  public static void main(String[] args){
    Scanner scanner = new Scanner(System.in);
    
    while(true) {
    	try {
        	System.out.print("곱하고자 하는 두 수 입력 >> ");
            int n = scanner.nextInt();
            int m = scanner.nextInt();
            
            System.out.print(n + "x" + m + "=" + n*m);
            break;
            
        }catch(InputMismatchException e){
        	System.out.println("실수는 입력하면 안됩니다.");
        	scanner.nextLine();
        }
    }
    
    scanner.close();
  }
}

16 컴퓨터와 독자 사이의 가위 바위 보 게임을 만들어보자. 예시는 다음 그림과 같다. 독자부터 먼저 시작한다. 독자가 가위 바위 보 중 하나를 입력하고 키를 치면, 프로그램은 가위 바위 보 중에서 랜덤하게 하나를 선택하고 컴퓨터가 낸 것으로 한다. 독자가 입력한 값과 랜덤하게 선택한 값을 비교하여 누가 이겼는지 판단한다. 독자가 가위 바위 보 대신 "그만"을 입력하면 게임을 끝난다.

import java.util.Scanner;

public class Multiply{
  public static void main(String[] args){
    Scanner scanner = new Scanner(System.in);
    
    String str[] = {"가위", "바위", "보"};
    
    while(true) {
    	 int n = (int)(Math.random()*3);
    	 
    	System.out.print("가위 바위 보! >> ");
        String user = scanner.next();
    	
        if(user == "그만") {
        	System.out.println("게임을 종료합니다...");
        	break;
        }
        
        int diff = 0;
        switch(user) {
        	case "가위" :
        		if(str[n].equals("가위")) {
        			diff = 0;
        		}else if(str[n].equals("보")) {
        			diff = 1;
        		}else {
        			diff = 2;
        		}
        		break;
        	case "바위" : 
        		if(str[n].equals("바위")) {
        			diff = 0;
        		}else if(str[n].equals("가위")) {
        			diff = 1;
        		}else {
        			diff = 2;
        		}
        		break;
        	case "보" :
        		if(str[n].equals("보")) {
        			diff = 0;
        		}else if(str[n].equals("바위")) {
        			diff = 1;
        		}else {
        			diff = 2;
        		}
        		break;
        	default :
        		System.out.println("잘못입력");
        		break;
        }
        
        if(diff == 0) {
        	System.out.println("유저 : " + user + " 컴퓨터 : " + str[n] + " 결과는 비김");
        }else if(diff == 1) {
        	System.out.println("유저 : " + user + " 컴퓨터 : " + str[n] + " 결과는 이김");
        }else {
        	System.out.println("유저 : " + user + " 컴퓨터 : " + str[n] + " 결과는 짐");
        }        
    }
    scanner.close();
  }
}

04. 클래스와 객체

실세계에서 객체들은 자신만의 고유한 특성과 행동을 가지며 다른 객체들에게 행동을 요청하거나 정보를 주고받는 등 상호 작용하면서 존재한다.


객체 지향 언어의 특성

객체지향 언어는 실세계의 객체를 프로그램 내에 표현하기 위해 클래스와 객체 개념을 도입하였다. 객체 지향 언어는 다음과 같은 특성을 가지다.

c는 절차지향 함수기반,
자바는 객체지향 객체기반
c++은 절차지향 + 객체지향

실세계와 달리 자바에서 객체는 클래스(class)라는 캡슐을 사용하며, 필드(멤버변수)와 메소드(멤버함수)로 구성된다.
멤버는 변수. 특성(시력, 팔길이 등)

클래스(class) : 객체 모양을 선언한 틀(캡슐화). ex)붕어빵 틀.
객체 : 클래스의 모양대로 생성된 실체. ex)붕어빵. 객체=인스턴스=오브젝트. 객체들은 클래스의 모양대로 모두 동일한 속성을 가지고 탄생하지만, 자신만의 고유한 값을 가짐으로써 구분된다.

  • 캡슐화 : 캡슐화란 객체를 캡슐로 싸서 내부를 보호하고 볼 수 없게 하는것으로 객체의 가장 본질적인 특징이다. (정보 은닉 뿐만 아니라 보호도 한다.)
  • 상속 : 어류는 동물이다.부모클래스를 슈퍼클래스, 자식 클래스를 서브클래스(하위클래스)
  • 다형성 : 다형성은 같은 이름의 메소드가 클래스 혹은 객체에 따라 다르게 동작하도록 구현되는것을 말한다. ex)크림붕어빵, 치즈붕어빵. 메소드 오버라이딩은 똑같은 speak지만 멍멍, 야옹. 메소드 오버로딩은 같은 이름의 메소드가 매개변수의 개수와 형태가 다름.

클래스 구성

p.180페이지 그림 참조!

생성자는 클래스의 이름과 완전 동일하게 해야 한다!!!
클래스의 이름은 .java의 이름과 완전 동일하게 해야한다!!!!!!!


new 연산자와 객체 생성, 그리고 레퍼런스 변수

new는 실체(인스턴스)를 만들어내는 역할을 한다!!!!!!!!!!!!!!!
참조이며 직접접근이 아니다!!!!!!!!!!!!!!!!

public static void(String args[]){
  Circle pizza;   //Circle 객체에 대한 레퍼런스 변수 선언!!!
  pizza = new Circle();   // Circle 객체 생성!!!
}

객체 멤버 접근

객체의 멤버에 접근할 때는 다음과 같이 레퍼런스 변수 뒤에 점(.) 연산자를 붙인다.

예를들어, 다음 코드는 pizza 객체의 radius 필드에 10을 대입한다.

pizza.radius = 10;

pizza 객체의 radius 필드 값을 읽을 경우 다음과 같이 한다.

int r = pizza.radius;

다음 코드는 pizza 객체의 getArea() 메소드를 호출하여 면적을 알아낸다.

double area = pizza.getArea();

생성자

생성자는 매개변수를 다르게하여 여러개 작성 가능하다.

생성자는 여러 개 작성(오버로딩) 할 수 있다.

매개변수개수타입(이름이 아니라 타입!)만 다르다면, 생성자를 여러개 둘 수 있다.
생성자는 리턴타입을 지정하지 않으며, 리턴값이 없다고해서 void를 리턴타입으로 지정하면 안된다.

public class Book{
  String title;
  String author;

  public Book(String t){   //생성자
    title = t;
    author = "작자미상";
  }

  public Book(String t, string a){   //생성자
    title = t;
    author = a;
  }

  public static void main(String[] args){
    Book littlePrince = new Book("어린왕자", "생텍쥐페리");   //생성자 Book(String t, string a) 호출

    Book loveStory = new Book("춘향전");   //생성자 Book(String t) 호출

    System.out.println(littlePrice.title + " " + littlePrince.author);
    System.out.println(loveStory.title + " " + loveStory.author);
  }
}

//결과
//어린왕자 생텍쥐페리
//춘향전 작자미상
기본 생성자

디폴트 생성자라고도 부르며 생성자가 하나도 없는 경우 컴파일러는 기본 생성자를 자동으로 생성한다.


this 레퍼런스

this는 현재 객체 자신에 대한 레퍼런스이다.

this()로 다른 생성자 호출

()는 무조건 생성자!!!!!!!
this()는 클래스 내에 생성자가 다른 생성자를 호출할 때 사용하는 자바 코드이다.

public class Book{
  String title;
  String author;

  void show(){
    System.out.println(title + " " + author);
  }

  public Book(){
    this("","");
    System.out.println("생성자 호출됨");
  }

  public Book(String title){
    this(title, "작자미상"); //2. this 생성자 호출하여 아래거 호출
  }

  public Book(String title, string author){ //3? 위에거가 이걸 호출한다
    this.title = title;
    this.author = author;
  }

  public static void main(String[] args){
    Book littlePrince = new Book("어린왕자", "생텍쥐페리");
    Book loveStory = new Book("춘향전");  //1. Book(String title) 호출.
    Book emptyBook = new Book();

    loveStory.show();
  }
}

//결과
//생성자 호출됨
//춘향전 작자미상
this 사용 시 주의할 점
  • this()는 반드시 생성자 코드에서만 호출할 수 있다.
  • this()는 반드시 같은 클래스 내 다른 생성자를 호출할 때 사용된다.
  • this()는 반드시 생성자의 첫 번째 문장이 되어야 한다.

메소드 형식

아래를 메소드 코드라고 부름

public(접근지정자) int(리턴 타입) getSum(메소드이름)(int i, int j)(메소드 인자들){
int sum;
sum = i + j;
return sum;
}

매개변수가 없으면 return타입 void

  • 매개변수는 주소값을 넘겨주므로 바꿀경우 값이 바뀐다!(포인터처럼)
  • value는 복사(기본타입)
  • reference는 참조
public class ArrayPassingExP{
    static void replaceScape(char a[]){
        for(int i = 0; i <a.length; i++){
            if(a[i] ==  ' '){
                a[i] = ',';
            }
        }
    }

    static void printCharArray(char a[]){
        for(int i = 0; i <a.length; i++){
            System.out.print(a[i]);
        }
        System.out.println();
    }

    public static void main(String argsp[]){
        char c[] = {'T','h','i','s','','i','s','','a','','p','e','n','c','i','l','.'};
        printCharArray(c);
        replaceSpace(c);
        printCharArray(c);
    }
}

//결과
//This is a pencil.
//This,is,a,pencil.

배열을 메인에서 만들었는데, replaceSpace 함수를 만나고 매개변수가 레퍼런스타입이라(배열), 메인함수의 값에 영향이 미친다!!!


메소드 오버로딩

매개변수의 개수가 달라야 한다. 반환형은 큰 의미 없음. 이름과 매개변수만 중요!!!


객체의 소멸

malloc은 free로 내가 해제 가능. 자바는 내가 해제 x

가비지

참조하는 레퍼런스가 하나도 없는 객체나 배열을 가비지로 판단한다.

가비지 컬렉션

어떤 컨디션에서 작동하는지는 모르니 너무 신뢰하지마라. 항시작동x

가비지 컬렉션 강제요청
System.gc(); //가비지 컬렉션 강제 요청

너무 믿지는 말고.. 조건이 안맞으면 안돈다. 적절한 구석에 넣기는 하지만 맹신x


패키지

폴더와 같은 개념.


클래스 접근 지정

public 클래스

패키지에 상관 없이 다른 어떤 클래스에게도 사용이 허용된다.

디폴트 클래스(접근 지정자 생략)

같은 패키지 내의 클래스에만 사용이 허용된다.


멤버 접근 지정

public 멤버

모든 클래스들이 접근 가능하다.

private 멤버

클래스 내의 멤버들에게만 접근 허용된다.
멤버 자체는 private로 막아서 쓰는걸 권장!!
오입력 방지하기 위해..(한글 입력인데 영문 입력 할 때라던지..)
get, set으로 받아서 쓴다

protected 멤버
  1. 같은 패키지의 모든 클래스에 접근이 허용된다.
  2. 자식 클래스의 경우 접근이 허용된다.
디폴트 멤버

동일한 패키지내에 있는 클래스들만 접근 가능하다.


static 멤버

c에서는 static 함수가 종료되도 값이 살아있음.

static 멤버의 선언

인스턴스 생성 안해주고 클래스(.)으로 바로 사용 가능하다
공유자원된다.

  • static 메소드는 static 멤버만 접근할 수 있다.
  • 일반 메소드는 static 접근에 대해 자유롭다.
  • static 메소드는 this(자기 자신. 즉 인스턴스)를 사용할 수 없다.
  non-static 멤버 static 멤버
선언 class Smaple{
int n;
void g(){…}
}
class Sample{
static int m; //멤버
static void g(){…} //메소드
}
시간적 특성 인스턴스 선언 전에는 사용x 프로그램이 시작될 때 생성.
  소유주가 인스턴스
(person p = new person(); 이게 인스턴스 생성)
소유주 자체가 클래스
  인스턴스 생성하고 인스턴스 공간에 저장된다 클래스가 저장되는 공간에 저장된다

static 사용하는 이유는! 같은 작업인데 매번 인스턴스를 만들면 낭비. 내정보를 불러오는 경우도(로그인, 마이페이지 등) static을 적절하게 사용.


final 클래스

  • final 메소드를 선언하면 오버라이딩 할 수 없다. 무조건 상속받아 사용할 수 있음.
  • final 필드(=멤버)를 선언하면 필드는 상수가 된다.

p.241~247 실습문제

1 자바 클래스를 작성하는 연습을 해보자. 다음 main() 메소드를 실행하였을 때 예시와 같이 출력되도록 TV 클래스를 작성하라.

public static void main(String[] args){
    Tv myTV = new TV("LG", 2017, 32);
    myTV().show();
}

//LG에서 만든 2017년형 32인치 TV
public class TV{
	private String i;
	private int j;
	private int k;
	
	TV(String i, int j, int k) {
		this.i = i;
		this.j = j;
		this.k = k;
	}
	
	void show() {
		System.out.println(i + "에서 만든 " + j + "년형 " + k + "인치 TV");
	}
	
	public static void main(String[] args){
	    TV myTV = new TV("LG", 2017, 32);
	    myTV.show();
	}
}

2 Grade 클래스를 작성해보자. 3과목의 점수를 입력받아 Grade 객체를 생성하고 성적 평균을 출력하는 main( )과 실행 예시는 다음과 같다.

public static void main(String[] args) {
    Scanner scaner = new Scanner(System.in);
    
    System.out.print("수학, 과학, 영어 순으로 3개의 점수 입력>>");
    int math=scan.nextInt();
    int science=scan.nextInt();
    int english=scan.nextInt();
    Grade me = new Grade(math,science,english);
    System.out.println("평균은 "+me.average()); //average()는 평균을 계산하여 리턴
    
    scanner.close();
}
import java.util.Scanner;

public class Grade {
	private int math;
	private int science;
	private int english;
	
	Grade(int math, int science, int english){
		this.math = math;
		this.science = science;
		this.english = english;
	}
	
	int average() {
		int avg = (this.math + this.science + this.english) / 3;
		return avg;
	}
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("수학, 과학, 영어 순으로 3개의 점수 입력 >> ");
		int math = scanner.nextInt();
		int science = scanner.nextInt();
		int english = scanner.nextInt();
		
		Grade me = new Grade(math, science, english);
		System.out.println("평균은 " + me.average());
		
		scanner.close();
	}
}

3 노래 한 곡을 나타내는 Song 클래스를 작성하라. Song은 다음 필드로 구성된다.

  • 노래의 제목을 나타내는 title
  • 가수를 나타내는 artist
  • 노래가 발표된 연도를 나타내는 year
  • 국적을 나타내는 country

또한 Song 클래스에 다음 생성자와 메소드를 작성하라.

  • 성자 2개: 기본 생성자와 매개변수로 모든 필드를 초기화하는 생성자
  • 노래 정보를 출력하는 show( ) 메소드
  • main( ) 메소드에서는 1978년, 스웨덴 국적의 ABBA가 부른 “Dancing Queen”을 Song 객체로 생성하고 show()를 이용하여 노래의 정보를 다음과 같이 출력하라.

출력 -> 1978년 스웨덴 국적의 ABBa가 부른 Dancing Queen

public class Song {

	private String title;
	private String artist;
	private int year;
	private String country;
	
	Song(int year, String country, String artist, String title){
		this.title = title;
		this.artist = artist;
		this.year = year;
		this.country = country;
	}
	
	void show() {
		System.out.println(year + "년 " + country + "국적의 " + artist + "가 부른 " + title);
	}
	
	public static void main(String[] args) {
		
		Song song = new Song(1987, "스웨덴", "ABBA", "Dancing Queen");
		song.show();
	}
}

4 다음 멤버를 가지고 직사각형을 표현하는 Rectangle 클래스를 작성하라.

  • int 타입의 x, y, width, height 필드: 사각형을 구성하는 점과 크기 정보
  • x, y, width, height 값을 매개변수로 받아 필드를 초기화하는 생성자
  • int square( ): 사각형 넓이 리턴
  • void show( ): 사각형의 좌표와 넓이를 화면에 출력
  • boolean contains(Rectangle r): 매개변수로 받은 r이 현 사각형 안에 있으면 true 리턴
  • main( ) 메소드의 코드와 실행 결과는 다음과 같다.
public static void main(String[] args) {
    Rectangle r=new Rectangle(2,2,8,7);
    Rectangle s=new Rectangle(5,5,6,6);
    Rectangle t=new Rectangle(1,1,10,10);
    
    r.show();
    System.out.println("s의 면적은 "+s.square());
    if(t.contains(r))
        System.out.println("t는 r을 포함합니다.");
    if(t.contains(s))
        System.out.println("t는 s를 포함합니다.");
}

출력 -> (2,2)에서 크기가 8x7인 사각형
s의 면적은 36
t는 r을 포함합니다.

public class Rectangle {
	private int x;
	private int y;
	private int width;
	private int height;
	
	Rectangle(int x, int y, int width, int height){
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}
	
	int square() {
		int value = this.width * this.height;
		return value;
	}
	
	void show() {
		System.out.println("(" + x + "," + y + ") 에서 크기가 " + width + "x" + height + "인 사각형");
	}
	
	boolean contains(Rectangle r) {
		if( (this.x+this.width > r.x+r.width) && (this.y+this.height > r.y+r.height) ) {
			return true;
		}else {
			return false;
		}
	}
	
	public static void main(String[] args) {
		Rectangle r=new Rectangle(2,2,8,7);
		Rectangle s=new Rectangle(5,5,6,6);
		Rectangle t=new Rectangle(1,1,10,10);
		
		r.show();
		System.out.println("s의 면적은 "+s.square());
		if(t.contains(r))
			System.out.println("t는 r을 포함합니다.");
		if(t.contains(s))
			System.out.println("t는 s를 포함합니다.");
	}
}

5 다음 설명대로 Circle 클래스와 CircleManager 클래스를 완성하라.

import java.util.Scanner;

class Circle {
	private double x,y;
	private int radius;
	public Circle (double x,double y,int radius) {
		___________________________________; // x, y, radius 초기화
	}
	public void show() {
    	___________________________________; 
	}
}
public class CircleManager {
	public static void main(String[] args) {
		Scanner scanner = ____________________;
		Circle c [] = _______________; // 3개의 Circle 배열 선언
		for(int i=0;i<__________;i++) {
			System.out.print("x, y radius >>");
			_____________________________; // x 값이 읽기
			_____________________________; // y 값이 읽기
			_________________________; // 반지름 읽기
			c[i] = __________________________; // Circle 객체 생성
		}
		for(int i=0;i<c.length;i++) _______________________; // 모든 Circle 객체 출력
		scanner.close();
	}
}

출력 -> x, y radius »3.0 3.0 5
x, y radius »2.5 2.7 6
x, y radius »5.0 2.0 4
(3.0,3.0)5
(2.5,2.7)6
(5.0,2.0)4

import java.util.Scanner;

class Circle {
	private double x,y;
	private int radius;
	public Circle (double x,double y,int radius) {
		this.x=x;
		this.y=y;
		this.radius=radius;
	}
	public void show() {
		System.out.println("("+x+","+y+")"+radius);
	}
}

public class CircleManager {

	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
		Circle c[]=new Circle[3];
		for(int i=0;i<c.length;i++) {
			System.out.print("x, y radius >>");
			double x=scanner.nextDouble();
			double y=scanner.nextDouble();
			int radius=scanner.nextInt();
			c[i]=new Circle(x,y,radius);
		}
		for(int i=0;i<c.length;i++)
			c[i].show();
		scanner.close();
	}

}

6 앞의 5번 문제는 정답이 공개되어 있다. 이 정답을 참고하여 Circle 클래스와 CircleManager 클래스를 수정하여 다음 실행 결과처럼 되게 하라.

출력 -> x, y radius »3.0 3.0 5
x, y radius »2.5 2.7 6
x, y radius »5.0 2.0 4
가장 면적이 큰 원은 (2.5,2.7)6

import java.util.Scanner;

class Circle {
	private double x,y;
	private int radius;
	public Circle (double x,double y,int radius) {
		this.x = x; // x, y, radius 초기화
		this.y = y;
		this.radius = radius;
	}
	public void show() {
		System.out.println("가장 면적이 큰 원은 (" + x + "," + y + ")" + radius);
	}
	public int getRadius() {
		return radius;
	}
}
public class CircleManager {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		Circle c [] = new Circle[3]; // 3개의 Circle 배열 선언
		int max = 0;
		for(int i=0;i<c.length;i++) {
			System.out.print("x, y radius >>");
			double x = scanner.nextDouble(); // x 값이 읽기
			double y = scanner.nextDouble(); // y 값이 읽기
			int radius = scanner.nextInt(); // 반지름 읽기
			c[i] = new Circle(x, y, radius); // Circle 객체 생성
		}
		
		for(int i=0; i<c.length; i++) {
			if(max < c[i].getRadius()) {
				max = c[i].getRadius();
			}
		}
		for(int i=0; i<c.length; i++) {
			if(max == c[i].getRadius()) {
				c[i].show();
			}
		}
		
		scanner.close();
	}
}

7 하루의 할 일을 표현하는 클래스 Day는 다음과 같다. 한 달의 할 일을 표현하는 MonthSchedule 클래스를 작성하라.

class Day {
	private String work; // 하루의 할 일을 나타내는 문자열
	public void set(String work) { this.work=work; }
	public String get() { return work; }
	public void show() {
		if (work==null) System.out.println("없습니다.");
		else System.out.println(work+"입니다.");
	}
}

MonthSchedule 클래스에는 Day 객체 배열과 적절한 필드, 메소드를 작성하고 실행 예시처럼 입력, 보기, 끝내기 등의 3개의 기능을 작성하라.

–출력–
이번달 스케쥴 관리 프로그램.
할일(입력:1, 보기:2, 끝내기:3) »1
날짜(1~30)?1
할일(빈칸없이입력)?자바공부

할일(입력:1, 보기:2, 끝내기:3) »2
날짜(1~30)?1
1일의 할 일은 자바공부입니다.

할일(입력:1, 보기:2, 끝내기:3) »3
프로그램을 종료합니다.

import java.util.Scanner;

class Day {
	private String work; // 하루의 할 일을 나타내는 문자열
	public void set(String work) { 
		this.work=work; 
	}
	public String get() { 
		return work; 
	}
	public void show() {
		if (work==null) {
			System.out.println("없습니다.");
		}else {
			System.out.println(work+"입니다.");	
		}
	}
}

public class MonthSchedule {
	
	Scanner scanner = new Scanner(System.in);
	Day d[];
	
	public MonthSchedule(int day) {
		d = new Day[day];
		for(int i=0; i<day; i++) {
			d[i] = new Day();
		}
	}
	
	void input (Day d[], int day, String work) {
		d[day].set(work);
	}
	
	void view (Day d[], int day) {
		System.out.println(day + "의 할 일은 ");
		d[day].show();
	}
	
	int finish() {
		System.out.println("프로그램을 종료합니다.");
		return 0;	
	}
	
	void run() {
		int t=1;
		int option;
		int day;
		String work;
		System.out.println("이번달 스케줄 관리 프로그램");
		
		while(t==1) {
			System.out.println("할일(입력:1, 보기:2, 끝내기:3)");
			option = scanner.nextInt();
			switch(option) {
				case 1 :
					System.out.println("날짜(1~30)?");
					day = scanner.nextInt();
					System.out.println("할일(빈칸없이 입력)?");
					work = scanner.next();
					this.input(this.d, day, work);
					System.out.println();
					break;
				case 2 :
					System.out.println("날짜?(1~30)?");
					day = scanner.nextInt();
					this.view(this.d, day);
					System.out.println();
					break;
				case 3 :
					t=this.finish();
					break;
			}
		}
	}
	
	public static void main(String[] args) {
		MonthSchedule april = new MonthSchedule(30);
		april.run();
		
	}
}

8 이름(name), 전화번호(tel) 필드와 생성자 등을 가진 Phone 클래스를 작성하고, 실행 예시와 같이 작동하는 PhoneBook 클래스를 작성하라.

--출력--
인원수>>3
이름과 전화번호(이름과 번호는  칸없이 입력)>>황기태 777-7777
이름과 전화번호(이름과 번호는  칸없이 입력)>>나명품 999-9999
이름과 전화번호(이름과 번호는  칸없이 입력)>>최자바 333-1234
저장되었습니다...
검색할 이름>>황기순
황기순  없습니다.
검색할 이름>>최자바
최자바의 번호는 333-1234 입니다.
검색할 이름>>그만
import java.util.Scanner;

class Phone {
   private String name;
   private String tel;
   Phone(String name, String tel) {
      this.name = name;
      this.tel = tel;
   }
   public String getName() {
      return name;
   }
   public String getTel() {
      return tel;
   }
}

public class PhoneBook {
   
   public static void main(String[] args) {
      Scanner sc = new Scanner(System.in);
      Phone phone[];
      int i;
      System.out.print("인원수 >> ");
      int num = sc.nextInt();
      phone = new Phone[num];
      for(i=0; i<phone.length; i++) {
         System.out.print("이름과 전화번호(이름과 번호는 빈 칸없이 입력)>>");
         String name = sc.next();
         String tel = sc.next();
         phone[i] = new Phone(name, tel);
      }
      System.out.println("저장되었습니다...");
      while(true) {
         System.out.print("검색할 이름 >>");
         String name = sc.next();
         for(i=0; i<num; i++) {
            if(name.equals(phone[i].getName())) {
               System.out.println(name+"의 번호는 "+phone[i].getTel()+" 입니다.");
               i--;
               break;
            }
         }
         if(name.equals("그만")) break;
         if (i == num) System.out.println(name+"이 없습니다.");
      }
      
      sc.close();
   }

}

9 다음 2개의 static 가진 ArrayUtil 클래스를 만들어보자. 다음 코드의 실행 결과를 참고하여 concat( )와 print( )를 작성하여 ArrayUtil 클래스를 완성하라.

class ArrayUtil {	
	public static int [] concat(int[] a, int[] b) {
		/* 배열 a와 b를 연결한 새로운 배열 리턴*/
	}
	public static void print(int[] a) { /* 배열 a 출력 */ }
}
public class StaticEx {
	public static void main(String[] args) {
		int [] array1 = { 1, 5, 7, 9 };
		int [] array2 = { 3, 6, -1, 100, 77 };
		int [] array3 = ArrayUtil.concat(array1,  array2);
		ArrayUtil.print(array3);
	}
}

--출력--
[ 1 5 7 9 3 6 -1 100 77 ]
class ArrayUtil {	
	static int[] c;
	
	public static int [] concat(int[] a, int[] b) {
		c = new int[a.length+b.length];
		int i;
		for(i=0; i<a.length; i++) {
			c[i] = a[i];
		}
		for(i=0; i<b.length; i++) {
			c[i+a.length] = b[i];
		}
		return c;
	}
	public static void print(int[] a) { /* 배열 a 출력 */
		System.out.print("[");
		for(int i=0; i<a.length; i++) {
			System.out.print(a[i] + " ");
		}
		System.out.print("]");
	}
}
public class StaticEx {
	public static void main(String[] args) {
		int [] array1 = { 1, 5, 7, 9 };
		int [] array2 = { 3, 6, -1, 100, 77 };
		int [] array3 = ArrayUtil.concat(array1,  array2);
		ArrayUtil.print(array3);
	}
}

10 다음과 같은 Dictionary 클래스가 있다. 실행 결과와 같이 작동하도록 Dictionary 클래스의 kor2Eng( ) 메소드와 DicApp 클래스를 작성하라.

class Dictionary {
	private static String [] kor = { "사랑", "아기", "돈", "미래", "희망" };
	private static String [] eng = { "love", "baby", "money", "future", "hope" };
	public static String kor2Eng(String word) { /* 검색 코드 작성 */
}

--출력--
한영 단어 검색 프로그램입니다.
한글 단어?희망
희망은 hope
한글 단어?아가
아가는 저의 사전에 없습니다.
한글 단어?아기
아기은 baby
한글 단어?그만
import java.util.Scanner;

public class Dictionary {
	private static String[] kor = {"사랑","아기","돈","미래","희망"};
	private static String[] eng = {"love","baby","money","future","hope"};
	
	public static String kor2Eng(String word) { /* 검색 코드 작성 */
		int i;
		
		for(i=0; i<kor.length; i++) {
			if(kor[i].equals(word)) {
				System.out.println(word + "은 " + eng[i]);
				break;
			}
		}
		
		if (i == kor.length) {
			System.out.println(word + "는 저의 사전에 없습니다.");
		}
		
		return word;
		
	}
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.println("한영 단어 검색 프로그램입니다.");
		while(true) {
			System.out.print("한글 단어? ");
			String han = scanner.next();
			if(han.equals("그만")) {
				break;
			}
			kor2Eng(han); 
		}
		
		scanner.close();
	}

}

11 다수의 클래스를 만들고 활용하는 연습을 해보자. 더하기(+), 빼기(-), 곱하기(*), 나누기(/)를 수행하는 각 클래스 Add, Sub, Mul, Div를 만들어라. 이들은 모두 다음 필드와 메소드를 가진다.

  • int 타입의 a, b 필드: 2개의 피연산자
  • void setValue(int a, int b): 피연산자 값을 객체 내에 저장한다.
  • int calculate( ): 클래스의 목적에 맞는 연산을 실행하고 결과를 리턴한다.

main( ) 메소드에서는 다음 실행 사례와 같이 두 정수와 연산자를 입력받고 Add, Sub, Mul, Div 중에서 이 연산을 실행할 수 있는 객체를 생성하고 setValue( )와 calculate( )를 호출하여 결과를 출력하도록 작성하라. (참고: 이 문제는 상속을 이용하여 다시 작성하도록 5장의 실습 문제로 이어진다.)

--출력--
 정수와 연산자를 입력하시오>>5 7 *
35
import java.util.Scanner;

class Add {
	private int a;
	private int b;
	void setValue(int a, int b) {
		this.a = a;
		this.b = b;
	}
	int calculate() {
		int cal = this.a + this.b;
		return cal;
	}
}

class Sub {
	private int a;
	private int b;
	void setValue(int a, int b) {
		this.a = a;
		this.b = b;
	}
	int calculate() {
		int cal = this.a - this.b;
		return cal;
	}
}

class Mul {
	private int a;
	private int b;
	void setValue(int a, int b) {
		this.a = a;
		this.b = b;
	}
	int calculate() {
		int cal = this.a * this.b;
		return cal;
	}
}

class Div {
	private int a;
	private int b;
	void setValue(int a, int b) {
		this.a = a;
		this.b = b;
	}
	int calculate() {
		int cal = this.a / this.b;
		return cal;
	}
}

public class Calculate {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.print("두 정수와 연산자를 입력하시오 >> ");
		int a = scanner.nextInt();
		int b = scanner.nextInt();
		String value = scanner.next();
		
		switch(value) {
			case "+" : 
				Add add = new Add();
				add.setValue(a, b);
				System.out.println(add.calculate());
				break;
			case "-" : 
				Sub sub = new Sub();
				sub.setValue(a, b);
				System.out.println(sub.calculate());
				break;
			case "*" : 
				Mul mul = new Mul();
				mul.setValue(a, b);
				System.out.println(mul.calculate());
				break;
			case "/" : 
				Div div = new Div();
				div.setValue(a, b);
				System.out.println(div.calculate());
				break;
		}

        scanner.close();
	}
}

12 간단한 콘서트 예약 시스템을 만들어보자. 다수의 클래스를 다루고 객체의 배열을 다루기에는 아직 자바 프로그램 개발이 익숙하지 않은 초보자에게 다소 무리가 있을 것이다. 그러나 반드시 넘어야 할 산이다. 이 도전을 통해 산을 넘어갈 수 있는 체력을 키워보자. 예약 시스템의 기능은 다음과 같다.

  • 공연은 하루에 한 번 있다.
  • 좌석은 S석, A석, B석으로 나뉘며, 각각 10개의 좌석이 있다.
  • 예약 시스템의 메뉴는 “예약”, “조회”, “취소”, “끝내기”가 있다.
  • 예약은 한 자리만 가능하고, 좌석 타입, 예약자 이름, 좌석 번호를 순서대로 입력받아 예약한다.
  • 조회는 모든 좌석을 출력한다.
  • 취소는 예약자의 이름을 입력받아 취소한다.
  • 없는 이름, 없는 번호, 없는 메뉴, 잘못된 취소 등에 대해서 오류 메시지를 출력하고 사용자가 다시 시도하도록 한다.
--출력--
명품콘서트홀 예약 시스템입니다.
예약:1. 조회:2, 취소:3, 끝내기:4>>1
좌석구분 S(1), A(2), B(3)>>1
S>> --- --- --- --- --- --- --- --- --- ---
이름>>황기태
번호>>1
예약:1. 조회:2, 취소:3, 끝내기:4>>1
좌석구분 S(1), A(2), B(3)>>2
A>> --- --- --- --- --- --- --- --- --- ---
이름>>김효수
번호>>5
예약:1. 조회:2, 취소:3, 끝내기:4>>2
S>> --- 황기태 --- --- --- --- --- --- --- ---
A>> --- --- --- --- --- 김효수 --- --- --- ---
B>> --- --- --- --- --- --- --- --- --- ---
<<조회를 완료하였습니다>>
예약:1. 조회:2, 취소:3, 끝내기:4>>3
좌석 S:1, A:2, B:3>>2
A>> --- --- --- --- --- 김효수 --- --- --- ---
이름>>김효수
예약:1. 조회:2, 취소:3, 끝내기:4>>2
S>> --- 황기태 --- --- --- --- --- --- --- ---
A>> --- --- --- --- --- --- --- --- --- ---
B>> --- --- --- --- --- --- --- --- --- ---
<<조회를 완료하였습니다>>
예약:1. 조회:2, 취소:3, 끝내기:4>>4
import java.util.Scanner;

class Concert{
	private String S[];
	private String A[];
	private String B[];
	private Scanner scanner;
	
	Concert(){
		scanner = new Scanner(System.in);
		S = new String[10];
		A = new String[10];
		B = new String[10];
		for(int i=0; i<S.length; i++) {
			S[i] = "---";
			A[i] = "---";
			B[i] = "---";
		}
	}
	
	public static void printSeat(String seat[]) { //좌석 한줄 출력 메소드
		for(int i=0; i<seat.length; i++) {
			System.out.print(" " + seat[i] + " ");
		}
		System.out.println();
	}
	
	public void allPrint() { //모든 좌석 출력 메소드
		System.out.print("S >> ");
		Concert.printSeat(S);
		System.out.print("A >> ");
		Concert.printSeat(A);
		System.out.print("B >> ");
		Concert.printSeat(B);
		System.out.println("<<조회를 완료하였습니다.>>");
	}
	
	public void choiceSeat() { //좌석 선택(S, A, B) 메소드
		while(true) {
			System.out.print("좌석 구분 S(1), A(2), B(3) >> ");
			int select = scanner.nextInt();
			switch(select) {
				case 1 :
					System.out.print("S >> ");
					printSeat(S);
					inputSeat(S);
					return;
				case 2 :
					System.out.print("A >> ");
					printSeat(A);
					inputSeat(A);
					return;
				case 3 :
					System.out.print("B >> ");
					printSeat(B);
					inputSeat(B);
					return;
				default : 
					System.out.println("다시 입력 해주세요.");
			}
		}
	}
	
	public void inputSeat(String seat[]) { //좌석에 이름값 넣는 메소드
		System.out.print("이름 >> ");
		String name = scanner.next();
		while(true) {
			System.out.print("번호 >> ");
			int num = scanner.nextInt();
			num--;
			if(seat[num].equals("---")) {
				seat[num] = name;
				break;
			}else {
				System.out.println("다른 좌석을 선택해 주세요");
			}
		}
	}
	
	public void d_chiceSeat() {
		while(true) {
			System.out.print("좌석 S:1, A:2, B:3 >>");
			int select = scanner.nextInt();
			switch(select) {
				case 1 :
					System.out.print("S >> ");
					printSeat(S);
					delete(S);
					return;
				case 2 :
					System.out.print("A >> ");
					printSeat(A);
					delete(A);
					return;
				case 3 :
					System.out.print("B >> ");
					printSeat(B);
					delete(B);
					return;
				default : 
					System.out.println("다시 입력해 주세요");
			}
		}
	}
	
	public void delete(String seat[]) {
		System.out.print("이름 >> ");
		String name = scanner.next();
		for(int i=0; i<seat.length; i++) {
			if(name.equals(seat[i])) {
				seat[i] = "---";
				break;
			}
		}
	}
}

public class JavaEx {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		System.out.println("명품콘서트홀 예약 시스템입니다.");
		Concert concert = new Concert();
		
		while(true) {
			System.out.print("예약:1, 조회:2, 취소:3, 끝내기:4 >> ");
			int select = scanner.nextInt();
			switch(select) {
				case 1 :
					concert.choiceSeat();
					break;
				case 2 :
					concert.allPrint();
					break;
				case 3 :
					concert.d_chiceSeat();
					break;
				case 4 : 
					scanner.close();
					return;
				default :
					System.out.println("다시 입력해 주세요.");
			}
		}
	}
}


5. 상속

반복적인 일을 줄인다. 부모클래스를 슈퍼클래스, 자식클래스를 서브클래스라고 부르며, 상속을 선언 할 때 extends 키워드 사용한다.

  • 다중상속을 지원하지 않는다.
  • 상속의 횟수에 제한을 두지 않는다.
  • 최상위에 java.lang.object 클래스가 있다!!!

슈퍼클래스에 대한 접근 지정

슈퍼클래스의 private 멤버
슈퍼클래스의 디폴트 멤버
슈퍼클래스의 public 멤버
슈퍼클래스의 protected 멤버

상속과 생성자

서브 클래스와 슈퍼 클래스의 생성자 호출 및 실행

질문 1. 서브클래스 객체가 생성될 때 서브클래스의 생성자와 슈퍼 클래스의 생성자가 모두 실행되는가? 답변 ) 둘 다 실행된다.

질문 2. 서브클래스의 생성자와 슈퍼클래스의 생성자 중 누가 먼저 실행되는가? 답변 ) 슈포클래스의 생성자가 먼저 실행된다. 호출은 서브클래스 먼저!

개발자의 명시적 지시가 없으면 서브클래스의 생성자가 기본이든 매개변수를 가지든 슈퍼 클래스에 만들어진 기본생성자가 선택된다.

class A{
    public A(int x){
        System.out.println("생성자 A");
    }
}

class B extends A{
    public B(){    //오류발생.  2. 얘는 public A(int x)에 대한 짝을 찾을 수 없음.
        System.out.println("생성자 B");
    }
}

public class ConstructorEx2{
    public static void main(String[] args){
        B b;
        b = new B();  //1. 얘는 public B() 타고올라간다.
    }
}

매개변수가 있는 생성자가 있기 때문에,
컴파일러가 기본 생성자를 안만들어준다.
그렇기 때문에 매개변수가 없는 생성자 선택이 안돼서 오류발생한다.


super()를 이용하여 명시적으로 슈퍼 클래스의 생성자 선택

class A{
    public A(){
        System.out.println("생성자 A");
    }
    public A(int x){
        System.out.println("매개변수 생성자 A" + x);  //1번으로  출력
    }
}

class B extends A{
    public B(){    
        System.out.println("생성자 B");
    }
    public B(int x){
        super(x);   //여기가 키포인트~!, 첫줄에 와야함   //2. 얘는 public A(int x)얘 찾음.
        System.out.println("매개변수 생성자 B" + x);  //2번으로 출력
    }
}

public class ConstructorEx2{
    public static void main(String[] args){
        B b;
        b = new B(5);  //1. 얘는 public B(int x)얘를 찾고 
    }
}

//결과
//매개변수생성자A5
//매개변수생성자B5

super는 부모 자체를 의미함.
super 생략 시 기본생성자 자동 호출


업캐스팅

부모타입의 변수로 자식 클래스의 인스턴스를 가리킨다.

Person p;
Student s =new Student();
p = s; //업캐스팅

다운캐스팅

완전한 구조가 아님. 쓰면 안되는 구조. 여기서 말하는 다운캐스팅은 조금 다른 얘기. 원래 다운캐스팅은 말이 안된다. ex) 자식의 공부영역을 부모에게 못참음 인스턴스 형태가 부모냐 자식이냐에 따라 다름. 인스턴스 형태가 중요!

Person p = new Student("이재문"); //업캐스팅

Student s = (Student)p;  //다운캐스팅. 시작주소값을 넘겨줘서 student 타입으로 형변환 해라

instanceof 연산자

instanceof 연산자의 결과 값은 boolean값으로, ‘레퍼런스’가 가리키는 객체가 해당 ‘클래스’ 타입의 객체이면 true이고 아니면 false로 계산한다.

        person
student     researcher
            professor


Person jee = new Student();
Person kim = new Professor();
Person lee = new Researcher();

if(jee instanceof Person) //jee는 Person 타입이므로 true
if(jee instanceof Student) //jee는 Student 타입이므로 true
if(kim instanceof Student) //kim는 Student 타입이 아니므로 false
if(kim instanceof Professor) //kim는 Professor 타입므로 true
if(kim instanceof Researcher) //Professor 객체는 Researcher 타입이기도 하므로 true
if(lee instanceof Professor) //lee는 Professor 타입이 아니므로 false

업캐스팅과 instanceof 연산자

class Person{}
class Student extends Person{}
class Researcher extends Person{}
class Professor extends Researcher{}

public class InstanceOfEx{
    static void print(Person p){
        if(p instanceof Person){
            System.out.print("Person ");
        }
        if(p instanceof Student){
            System.out.print("Student ");
        }
        if(p instanceof Researcher){
            System.out.print("Researcher ");
        }
        if(p instanceof Professor){
            System.out.print("Professor ");
        }
    }

    public static void main(String[] args){
        System.out.print("new Student() -> \t ");   print(new Student());
        System.out.print("new Researcher() -> \t ");   print(new Researcher());
        System.out.print("new StudenProfessort() -> \t ");   print(new Professor());
    }
}

//결과
//new Student() -> Person Student
//new Researcher() -> Person Researcher
//new StudenProfessort() -> Person Researcher Professor

나중에 보충 추가

부모 = 자식 : 업캐스팅
자식 = 부모 : 다운캐스팅

다운캐스팅하려면 업캐스팅 먼저 선행되어야 함. -> 멤버 개수 때문에 차이가 나서.

Object obj = s ~~ : 업캐스팅으로 주소 먼저 넘겨줘야 String s2 = (String)obj; : 시작주소 넘겨줘서 다운캐스팅 가능하다.


나중에 보충 추가2

Person p = new Student("이재문"); //업캐스팅
Student s = (Student)p;  //다운캐스팅, (Student)의 타입 변환을 반드시 표시

class Person{
  String name;
  String id;

  public Person(String name){
	  this.name = name;
  }
}

class Student extends Person{
	String grade;
	String department;

	public Student(String name){
		super(name);
	}
}

//업캐스팅~~~~ 부모의 요소로 자식 접근은 못한다~~~ 오류 보기!
public class UpcastingEx{
	public static void main(String[] args){
		Person p;
		Student s = new Student("이재문");
		p = s;  //업캐스팅

		System.out.println(p.name);  //오류 없음

		p.grade = "A";  //컴파일 오류. 다운캐스팅?안해줘서 student에 있는 grade 요소에 접근 못함
		p.department = "Com";  //컴파일 오류
	}
	//실행결과 -> 이재문
}


//다운캐스팅~~~~
public class DowncastingEx{
	public static void main(String[] args){
		Person p = new Student("이재문");  //업캐스팅
		Student s;
		
		s = (student)p;  //다운캐스팅

		System.out.println(s.name);  //오류 없음

		s.grade = "A";  //오류 없음
	}
	//실행결과 -> 이재문
}

메소드 오버라이딩

사용용도 다양! 많이 쓰임.

매소드 오버라이딩 제약사항
  • 슈퍼클래스의 메소드와 동일한 원형으로 작성한다.
  • 슈퍼 클래스 메소드의 접근 지정자보다 접근의 범위를 좁여 오버라이딩 할 수 없다.
  • static이나 private 또는 final로 선언된 메소드는 서브 클래스에서 오버라이딩 할 수 없다.

동적바인딩 : 오버라이딩된 메소드 호출

재정의 한 부분에서. 자식 인스턴스에서 재정의 하면 우선권 가진다


오버라이딩과 super 키워드

우선권은 내거 먼저

코드 작성시 @Override 써주면 이 아래는 재정의다라고 암묵적으로..(표기부호)


오버로딩과 오버라이딩 비교
  메소드 오버로딩 메소드 오버라이딩
목적 이름이 같은 여러 개의 메소드를 중복작성하여 사용의 편리성 향상. 다형성 실현 슈퍼클래스에 구현된 메소드를 무시하고 서브 클래스에서 새로운 기능의 메소드를 재정의함. 다형성 실현
조건 메소드의 이름은 반드시 동일하고. 매개변수 타입이나 개수가 달라야 성립 모두 동일해야 성립
바인딩 정적 바인딩. 호출될 메소드는 컴파일 시에 결정(컴파일 할 때) 동적 바인딩. 실행 시간에 오버라디이된 메소드 찾아 호출(실행될 때)

다형성은 껍데기는 같은데 (운다), 다른걸 실현?(고양이, 강아지 등)


추상 메소드

  • 내용이 없는 메소드.
  • abstract 키워드와 함께 원형만 선언하고 코드는 작성하지 않는다.
  • 오버라이딩하여 구현해야 함
  • 중괄호 사용 안한다.
public abstract String getName();  //중괄호 없음. 너가 재정의해서 써야 해!!!

추상 메소드가 하나라도 있으면 추상 클래스가 되어야 함!!!

abstract class Shape{  //추상 클래스 선언. 추상 클래스가 되어야 한다!!!!!!!!!
    public Shape(){}
    public void paint(){draw();}
    abstract public void draw(); //추상 메소드 선언!
}

추상 클래스는 객체를 생성할 수 없다.

추상으로 new 인스턴스 생성 불가능


추상 클래스의 상속

재정의 안할거면 클래스에라도 추상 붙여줘야 함!

abstract class Shape{  
    public Shape(){}
    public void paint(){draw();}
    abstract public void draw(); 
}

abstract class Line extends Shape{     //재정의 안할거면 클래스에라도 추상 붙여줘야 함!
    public String toString(){
        return "Line";
    }
}

재정의를 했다 = 구현 상속이다?


상속과 추상클래스 키워드

  • 상속 : extends
  • 추상 : abstract

인터페이스

현업에서 자바버전 1.8 많이 씀.
필드(멤버 변수)를 만들 수 없다. 기능만!!
추상 = 인스턴스 만들기x
인터페이스는 규격같은것. 약속. 코드를 가지지 않는다.

  • 인터페이스는 객체를 생성할 수 없다. (new Phone(); 같은거 생성 못함)
  • 인터페이스 타입의 레퍼런스 변수 선언은 가능하다
  • 인터페이스끼리 상속된다
  • 인터페이스를 상속받아 클래스를 작성하면 인터페이스의 모든 추상 메소드를 구현하여야한다.

인터페이스 구현

implements 키워드를 사용하여 인터페이스의 모든 추상 메소드르 구현한 클래스를 작성하는 것을 말한다.


인터페이스 상속

인터페이스가 상속 받으려면 뒤에 받을 애도 인터페이스여야함.


interpace AIInterfave{
	void recognizeSpeach();
	void sysnthesizeSpeach();
}

class AIPhone implements MobilePhoneInterface, AIInterface{ //인터페이스 구현
	//MobilePhoneInterface의 모든 메소드를 구현한다.
	public void sendCall(){...}
	public void reseiveCall(){...}
	public void sendSMS(){...}
	public void receiveSMS(){...}
	
	//AIInterface의 모든 메소드를 구현한다.
	public void recognizeSpeach(){...}
	public void synthesizeSpeach(){...}
	
	//추가적으로 다른 메소드를 작성할 수 있다.
	public int touch(){...}
}

추상클래스와 인터페이스의 차이점

  • 인터페이스는 다중 상속 가능
  • 추상 클래스는 다중상속 x
  • 클래스는 단일 상속
비교 추상클래스 인터페이스
목적 추상클래스는 서브 클래스에서 필요로 하는 대부분의 기능을 구현하고 두고 서브클래스가 상속받아 활용할 수 있도록 하되, 서브클래스에서 구현할 수 밖에 없는 기능만을 추상메소드로 선언하여 서브클래스에서 구현하도록 하는 목적(다형성) 인터페이스는 객체의 기능을 모두 공개한 표준화같은 문서와 같은 것으로, 개발자에게 인터페이스를 상속받는 클래스의 목적에 따라 인터페이스의 모든 추상 메소드를 만들도록 하는 목적(다형성)
구성 추상 메소드와 일반 메소드 모두 포함,
상수와 변수 필드 모두 포함
변수 필드(멤버 변수)는 포함하지 않음,
상수, 추상 메소드, 일반메소드, default메소드, static 메소드 모두 포함
protected 접근 지정 선언 불가
다중 상속 지원

instanceof로 interface 안에 interface가 포함되어있느냐 따져볼 수 있음.


p.314~322 실습문제

[1~2]다음 TV 클래스가 있다.

class TV {
	private int size;
	public TV(int size) { this.size=size; }
	protected int getSize() { return size; }
}

1 다음 main( ) 메소드와 실행 결과를 참고하여 TV를 상속받은 ColorTV 클래스를 작성하라.

public static void main(String[] args) {
	ColorTV myTV=new ColorTV(32, 1024);
	myTV.printProperty();
}

--출력--
32인치 1024컬러
class TV {
	private int size;
	public TV(int size) { this.size=size; }
	protected int getSize() { return size; }
}

public class ColorTV extends TV {
	private int color;
	public ColorTV(int size, int color) {
		super(size);
		this.color=color;
	}
	void printProperty() {
		System.out.println(getSize()+"인치 "+color+"컬러");
	}
	
	public static void main(String[] args) {
		ColorTV myTV=new ColorTV(32, 1024);
		myTV.printProperty();
	}
}

2 다음 main( ) 메소드와 실행 결과를 참고하여 문제 1의 ColorTV를 상속받는 IPTV 클래스를 작성하라.

public static void main(String[] args) {
	IPTV iptv=new IPTV("192.1.1.2",32,2048); //"192.1.1.2" 주소에 32인치, 2048컬러
	iptv.printProperty();
}

--출력--
나의 IPTV는 192.1.1.2 주소의 32인치 2048컬러
class TV {
	private int size;
	public TV(int size) { this.size=size; }
	protected int getSize() { return size; }
}

class ColorTV extends TV {
	private int color;
	public ColorTV(int size, int color) {
		super(size);
		this.color=color;
	}
	void printProperty() {
		System.out.println(getSize()+"인치 "+color+"컬러");
	}
}

public class IPTV extends ColorTV {
	private String address;
	
	public IPTV(String address, int size, int color) {
		super(size, color);
		this.address = address;
	}
	
	void printProperty() {
		System.out.print("나의 IPTV는 " + address + "주소의 ");
		super.printProperty();
	}
	
	public static void main(String[] args) {
		IPTV iptv=new IPTV("192.1.1.2",32,2048); //"192.1.1.2" 주소에 32인치, 2048컬러
		iptv.printProperty();
	}
}

[3~4] 다음은 단위를 변환하는 추상 클래스 Converter이다.

import java.util.Scanner;
abstract class Converter {
	abstract protected double convert(double src); // 추상 메소드
	abstract protected String getSrcString(); // 추상 메소드
	abstract protected String getDestString(); // 추상 메소드
	protected double ratio; // 비율
	
	public void run() {
		Scanner scanner=new Scanner(System.in);
		System.out.println(getSrcString()+"을 "+getDestString()+" 로 바꿉니다.");
		System.out.print(getSrcString()+"을 입력하세요>> ");
		double val=scanner.nextDouble();
		double res=convert(val);
		System.out.println("변환 결과: "+res+getDestString()+"입니다");
		scanner.close();
	}
}

3 Converter 클래스를 상속받아 원화를 달러로 변환하는 Won2Dollar 클래스를 작성하라. main( ) 메소드와 실행 결과는 다음과 같다.

public static void main(String[] args) {
	Won2Dollar toDollar=new Won2Dollar(1200); // 1달러는 1200원
	toDollar.run();
}

--출력--
원을 달러  바꿉니다.
원을 입력하세요>> 24000
변환 결과: 20.0달러입니다
import java.util.Scanner;

abstract class Converter {
	abstract protected double convert(double src); // 추상 메소드
	abstract protected String getSrcString(); // 추상 메소드
	abstract protected String getDestString(); // 추상 메소드
	protected double ratio; // 비율
	
	public void run() {
		Scanner scanner=new Scanner(System.in);
		System.out.println(getSrcString()+"을 "+getDestString()+" 로 바꿉니다.");
		System.out.print(getSrcString()+"을 입력하세요>> ");
		double val=scanner.nextDouble();
		double res=convert(val);
		System.out.println("변환 결과: "+res+getDestString()+"입니다");
		scanner.close();
	}
}

public class Won2Dollar extends Converter {
	protected double convert(double src) {
		return src/ratio;
	}
	protected String getSrcString() {		
		return "원";
	}
	protected String getDestString() {
		return "달러";
	}	
	Won2Dollar(double ratio){
		this.ratio = ratio;
	}

	public static void main(String[] args) {
		Won2Dollar toDollar=new Won2Dollar(1200); // 1달러는 1200원
		toDollar.run();
	}
}

4 Converter 클래스를 상속받아 Km를 mile(마일)로 변환하는 Km2Mile 클래스를 작성하라. main( ) 메소드와 실행 결과는 다음과 같다.

public static void main(String[] args) {
	Km2Mile toMile=new Km2Mile(1.6); // 1마일은 1.6Km
	toMile.run();
}

--출력--
Km을 mile  바꿉니다.
Km을 입력하세요>> 30
변환 결과: 18.75mile입니다
import java.util.Scanner;

abstract class Converter {
	abstract protected double convert(double src); // 추상 메소드
	abstract protected String getSrcString(); // 추상 메소드
	abstract protected String getDestString(); // 추상 메소드
	protected double ratio; // 비율
	
	public void run() {
		Scanner scanner=new Scanner(System.in);
		System.out.println(getSrcString()+"을 "+getDestString()+" 로 바꿉니다.");
		System.out.print(getSrcString()+"을 입력하세요>> ");
		double val=scanner.nextDouble();
		double res=convert(val);
		System.out.println("변환 결과: "+res+getDestString()+"입니다");
		scanner.close();
	}
}

public class Km2Mile extends Converter {
	protected double convert(double src) {
		return src/ratio;
	}
	protected String getSrcString() {
		return "Km";
	}
	protected String getDestString() {
		return "mile";
	}
	Km2Mile(double ratio){
		this.ratio = ratio;
	}
	
	public static void main(String[] args) {
		Km2Mile toMile=new Km2Mile(1.6); // 1마일은 1.6Km
		toMile.run();
	}
}

[5~8] 다음은 2차원 상의 한 점을 표현하는 Point 클래스이다.

class Point {
	private int x,y;
	public Point(int x, int y) {this.x=x; this.y=y;}
	public int getX() {return x;}
	public int getY() {return y;}
	protected void move(int x, int y) { this.x=x; this.y=y;}
}

5 Point를 상속받아 색을 가진 점을 나타내는 ColorPoint 클래스를 작성하라. 다음 main( ) 메소드를 포함하고 실행 결과와 같이 출력되게 하라.

public static void main(String[] args) {
	ColorPoint cp=new ColorPoint(5,5,"YELLOW");
	cp.setXY(10,20);
	cp.setColor("RED");
	String str=cp.toString();
	System.out.println(str+"입니다.");
}

--출력--
RED색의 (10,20) 점입니다.
class Point {
	private int x,y;
	public Point(int x, int y) {this.x=x; this.y=y;}
	public int getX() {return x;}
	public int getY() {return y;}
	protected void move(int x, int y) { this.x=x; this.y=y;}
}

public class ColorPoint extends Point{
	private String color;
	ColorPoint(int x, int y, String color){
		super(x, y);
		this.color = color;
	}
	
	void setXY(int x, int y){
		move(x, y);
	}
	
	void setColor(String color) {
		this.color = color;
	}
	
	public String toString() {
		String temp = color + "색의 (" + getX() + "," + getY() + ")의 점";
		return temp;
	}
	
	public static void main(String[] args) {
		ColorPoint cp=new ColorPoint(5,5,"YELLOW");
		cp.setXY(10,20);
		cp.setColor("RED");
		String str=cp.toString();
		System.out.println(str+"입니다.");
	}
}

6 Point를 상속받아 색을 가진 점을 나타내는 ColorPoint 클래스를 작성하라. 다음 main( ) 메소드를 포함하고 실행 결과와 같이 출력되게 하라.

public static void main(String[] args) {
	ColorPoint zeroPoint=new ColorPoint(); // (0,0) 위치의 BLACK 색 점
	System.out.println(zeroPoint.toString()+"입니다.");
		
	ColorPoint cp=new ColorPoint(10,10); // (10,10) 위치의 BLACK 색 점
	cp.setXY(5,5);
	cp.setColor("RED");
	System.out.println(cp.toString()+"입니다.");
}

--출력--
BLACK색의 (0,0) 점입니다.
RED색의 (5,5) 점입니다.
class Point {
	private int x,y;
	public Point(int x, int y) {this.x=x; this.y=y;}
	public int getX() {return x;}
	public int getY() {return y;}
	protected void move(int x, int y) { this.x=x; this.y=y;}
}

public class ColorPoint extends Point{
	
	private String color;
	
	ColorPoint(){
		super(0, 0);
		this.color = "BLACK";
	}
	
	ColorPoint(int x, int y){
		super(x, y);
		this.color = "BLACK";
	}
	
	public String toString() {
		String temp = color + "색의 (" + getX() + "," + getY() + ")의 점";
		return temp;
	}
	
	void setXY(int x, int y) {
		move(x, y);
	}	
	
	void setColor(String color) {
		this.color = color;
	}
	
	public static void main(String[] args) {
		ColorPoint zeroPoint=new ColorPoint(); // (0,0) 위치의 BLACK 색 점
		System.out.println(zeroPoint.toString()+"입니다.");
			
		ColorPoint cp=new ColorPoint(10,10); // (10,10) 위치의 BLACK 색 점
		cp.setXY(5,5);
		cp.setColor("RED");
		System.out.println(cp.toString()+"입니다.");
	}
}

6. 모듈과 패키지, 자바 기본 패키지

다른 패키지에 있으면 각 패키지 안 클래스 이름 같아도 상관 없음. 다른 패키지에 있는 클래스를 쓰고싶으면 import해서 씀


Object 클래스

모든 클레스에 강제로 상속된다!! 최상위 클래스이다!!


객체를 문자열로 변환, toString() 메소드

쓰기 힘듬..


객체 비교와 equals() 메소드

==연산자

Point a = new Pint(2,3);
Point b = new Pint(2,3);
Point c = a;

if(a == b){
	System.out.println("a==b");
}

if(a == c){
	System.out.println("a==c");
}

//이 코드의 실행 결과는
// a==c

실수 많은 부분. 조심해야 함.
프리미티브타입(기본타입) 비교할 때 사용
reference 타입은 이렇게 비교하면 안된다!!!!!!!!!!!!!!!!!!!
reference가 같은 공간을 바라보냐라고 비교! ==

boolean equals

String a = new String("Hello");
String b = new String("Hello");

if(a == b){
	System.out.println("a==b");
}
if(a.equals(b)){
	System.out.println("a와 b는 둘 다 Hello입니다.");
}

//실행결과
//a와 b는 둘 다 Hello입니다.

값을 비교할때는 equals를 사용해야 함
reference 비교시
equals는 hash 값을 비교함


일반 클래스에서 equal은 hash값을 가지고 비교한다 근데 string은 hash값이 아닌 값 비교

public class GoodCalc{
	
	public static void main(String[] args) {
		String a = new String("this is a pencil");
		String b = new String("this is a pencil");
		String c = a;
		
		if(a == b) {
			System.out.println("a == b");
		}
		if(a == c) {
			System.out.println("a == c");
		}
		if(a.equals(b)) {
			System.out.println("a is equals to b");
		}
		if(a.equals(c)) {
			System.out.println("a is equals to c");
		}
		
		
	}
}

//결과
//a == c
//a is equals to b
//a is equals to c

Wrapper 클래스

Byte, Short, Integerm Long, Character, Double, Float, Boolean 클래스가 기본 타입에 해당되는 값을 객체로 다룰 수 있게 하는 wrapper 클래스이다. 기본 타입의 값을 객체로 만들어 사용할 수 있도록 Wrapper 클래스를 제공한다.
(일반타입을 wrapper로 한번 감싸줌. 일반 타입을 레퍼런스 타입으로 쓸 때!)

기본타입 Wrapper 클래스
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean
Wrapper 클래스의 객체 생성

Wrapper 객체는 기본 타입의 값을 인자로 하여 다음 예와 같이 정적 메소드인 valueOf()를 호출하여 생성한다.

Interger i = Integer.valueOf(10);  //정수 10의 객체화
Character c = Character.valueOf('c');  //문자 'c'의 객체화
Double d = Double.valueOf(3.14);
Boolean b = Boolean.valueOf(true);

//-character를 제외한 나머지 wrapper 클래스의 경우 문자열로 wrapper 객체 생성 가능--------------------------------------------------

Integer i = Integer.valueOf("10");
Double d = Double.valueOf("3.14");

Wrapper 클래스의 활용

wrapper클래스는 많은 메소드를 제공하나, 대부분은 기본 타입 값을 문자열로 변환하거나, 문자열을 기본 타입 값으로 변환하는 것들이 주를 이루고 있다. 가장 많이 사용되는 Integer 클래스의 주요 메소드는 아래의 표와 같으며, 많은 메소드가 static 타입이다.

value나 parseInt가 중요? 눈여겨봐야 할 것.

value는 레퍼런스를 하나 만듬. parseInt는 단순 변환만 해줌..


Wrapper 객체에 들어 있는 기본 타입 값 알아내기

Integer i = Integer.valueOf(10);
int ii = i.intValue(); // ii = 10

Double d = Double.valueOf(3.14);
double dd = d.doubleValue(); //dd = 3.14

Boolean b = Boolean.valueOf(true);
boolean bb = b.booleanValue(); // bb = true

문자열을 기본 타입으로 변환

int i = Intefer.parseInt("123"); // i = 123
boolean b = Boolean.parseBoolean("true");  // b = true
double d = Double.parseDouble("3.14");  //d = 3.14

parseInt(), parseBoolean(), parseDouble() 메소드는 모두 static 타입이므로 Wrapper 클래스의 이름으로 바로 메소드를 호출한다.
Wrapper 클래스는 해당 타입으로 변환하는 메소드만을 제공한다. 예를들어 Integer 클래스는 parseBoolean()이나 parseDouble()은 제공하지 않는다.


기본 타입 값을 문자열로 변환

String s1 = Intefer.toString(123); // 정수 123을 문자열 "123"으로 변환
String s2 = Intefer.toHexString(123); // 정수 123을 16진수의 문자열 "7b"로 변환
String s3 = Double.toString(3.14); // 실수 3.14를 문자열 "3.14"로 변환
String s4 = Character.toString('a'); // 문자 'a'를 문자열 "a"로 변환
String s5 = Boolean.toString(true); // 불린 값 true를 문자열 "true"로 변환

예제 6-5) 다음은 Wrapper 클래스를 활용하는 예이다. 다음 프로그램의 결과는 무엇인가?

public class WrapperEx {

	public static void main(String[] args) {
		System.out.println(Character.toLowerCase('A'));  //'A'를 소문자로 변환
		
		char c1 = '4', c2 = 'F';
		if(Character.isDigit(c1)) { //문자 c1이 숫자이면 true
			System.out.println(c1 + "는 숫자");
		}
		if(Character.isAlphabetic(c2)) { //문자 c2가 영문자이면 true
			System.out.println(c2 + "는 영문자");
		}
		
		System.out.println(Integer.parseInt("-123")); //"-123"을 10진수로 변환
		System.out.println(Integer.toHexString(28)); //정수 28을 2진수 문자열로 변환
		System.out.println(Integer.toBinaryString(28)); //28을 16진수 문자열로 변환
		System.out.println(Integer.bitCount(28)); //28에 대한 2진수의 1의 개수
		
		Double d = Double.valueOf(3.14);
		System.out.println(d.toString()); //Double을 문자열 "3.14"로 변환
		System.out.println(Double.parseDouble("3.14")); //문자열을 실수 3.14로 변환
		
		boolean b = (4>3);
		System.out.println(Boolean.toString(b)); //true를 문자열 "true"로 변환
		System.out.println(Boolean.parseBoolean("false")); //문자열을 false로 변환

	}
}

// a
// 4는 숫자
// F는 영문자
// -123
// 1c
// 11100
// 3
// 3.14
// 3.14
// true
// false

parse는 wrapper변환이 아니라 일반 데이터 타입으로 변환!!!


박싱(boxing)과 언박싱(unboxing)

기본 타입의 값을 Wrapper 객체로 변환하는 것을 박싱이라하고,
반대의 경우(wrapper 객체에 들어있는 기본 타입의 값을 빼내는 것)언박싱이라고 한다.

박싱은 Integer ten = Integer.valueOf(10);

언박싱은 int n = ten.intValue();

박싱과 언박싱은 JDK 1.5부터 자동으로 이루어지며, 이를 자동박싱과 자동 언박싱이라고 부른다.

Integer ten = 10; //자동박싱. Integer ten = Integer.valueOf(10);로 자동 처리됨
int n = ten; // 자동 언박싱. int n = ten.intValue();

String의 특징과 객체 생상

java.lang 패키지에 포함된 클래스로서 String 클래스는 문자열을 나타낸다. 스트링 리터럴은 자바 컴파일러에 의해 모두 String 객체로 처리된다. (string 클래스는 하나의 문자열 표현)

//스트링 리터럴로 string 객체 생성
String str1 = "abcd";

//string 클래스의 생성자를 이용하여 string 객체 생성
char data[] = {'a','b','c','d'};
String str2 = new String(data);
String str3 = new String("abcd"); //str2와 str3은 모두 "abcd" 문자열

참고로 아래 표는 오버로딩

생성자 설명
String 빈 스트링 객체 생성
String(char[] value) char 배열에 있는 문자들을 스트링 객체로 생성
String(String original) 매개변수로 주어진 문자열과 동일한 스트링 객체 생성
String(StringBuffer buffer) 매개변수로 주어진 스트링 버퍼의 문자열을 스트링 객체로 생성

스트링 리터럴과 new String()

스트링 리터럴과 new String()으로 생성된 스트링 객체는 서로 다르게 관리된다. 스트링 리터럴은 자바 내부에서 리터럴 테이블로 특별히 관리하여 동일한 리터럴을 공유시킨다. 하지만 new String으로 생성된 스트링은 new를 이용하여 생성되는 다른 객체와 동일하게 힙 메모리에 생성된다.

스트링 객체는 메모리에 자리를 잡으면 변경 안된다!!!!!!! 새로운 객체를 다시 생성.

String a = "Hello";
String b = "java";
String c = "Hello";
String d = new String("Hello");
String e = new String("java");
String f = new String("Hello");

생성자를 안 쓴 경우 독립적인 객체 생성 후 사용하며(a, c),
생성자를 쓴 경우 독립적인 객체 생성 후 사용한다.(d, f)


스트링 객체는 수정이 불가능하다.

String s = new String("Hello");
String t = s.concat("java");
//위의 코드 결과로 t는 Hellojava, s는 "Hello"를 출력한다.(s는 변경 안된다.)

//한번 만들어진 스트링은 수정이 불가능하기 때문에 새로운 스트링 객체(Hellojava)를 가리킨다.

s = s.concat("java");
//위의 코드로 해야 s는 "Hellojava"를 가리킨다.

스트링은 비교시 반드시 equals()를 사용해야 한다!!!!!!!!!!!


★★★★★ String 활용 ★★★★★

굉장히 많이 쓰임!!!!!!!!!!!!!!!!!!! 다들 리턴임. 값을 변경하고 싶으면 s = s.trim();해서 s에 다시 저장해야 함

메소드 설명
char charAt(int index) index 인덱스에 있는 문자 값 리턴
int codePointAt(int index) index 인덱스에 있는 유니코드 값 리턴
int compareTo(String anotherString) 두 스트링을 사전 순으로 비교하여 두 스트링이 같으면 0, 현 스트링이 anotherString 보다 먼저 나오면 음수, 아니면 양수 리턴.
(같다 다르다가 아니라 크기 비교. 그러나 문자열은 비교를 못하기때문에 사전순으로 비교)
String concat(String str) 현재 스트링 뒤에 str 스트링을 덧붙인 새로운 스트링 리턴
(스트링은 수정 안돼서 이렇게 사용)
boolean contains(charSequence s) s에 지정된 문자들을 포함하고 있으면 true 리턴.
(있냐 없냐만 따짐.)
int length() 스트링의 길이(문자개수) 리턴
String replace(Charsequence target, Charsequence replacement) target이 지정하는 일련의 문자들을 replacement가 지정하는 문자들로 변경한 스트링 리턴.
(target은 원본값 리턴! 바꾸는게 아니라!!)
String[] split(String regex) 정규식 regex에 일치하는 부분을 중심으로 스트링을 분리하고, 분리된 스트링들을 배열로 저장하여 리턴
(기준을 가지고 잘라낼때(ex 쉼표) 잘라내면 여러개의 값이 되니 메모리에 저장 후 인덱스(0,1,2)로 접근)
String subString(int beginIndex) beginIndex 인덱스부터 시작하는 서브 스트링 리턴
(원하는 위치의 문자열 뽑기)
String toLowerCase() 소문자로 변경한 스트링 리턴
String toUpperCase() 대문자로 변경한 스트링 리턴
String trim() 스트링 앞뒤의 공백 문자들을 제거한 스트링 리턴
public class StringEx {

	public static void main(String[] args) {
		String a = new String(" C#");
		String b = new String(", C++");

		System.out.println(a + "의 길이는 " + a.length()); //문자열의 길이(문자개수)
		System.out.println(a.contains("#")); //문자열의 포함 관계
		
		a = a.concat(b); //문자열 연결
		System.out.println(a);
		
		a = a.trim(); //문자열 앞 뒤의 공백 제거
		System.out.println(a);
		
		a = a.replace("C#", "Java"); //문자열 대치
		System.out.println(a);
		
		String s[] = a.split(","); //문자열 분리
		for(int i=0; i<s.length; i++) {
			System.out.println("분리된 문자열" + i + ": " + s[i]);
		}
		
		a = a.substring(5); //인덱스 5부터 끝까지 서브 스트링 리턴
		System.out.println(a);
		
		char c = a.charAt(2); //인덱스 2의 문자 리턴
		System.out.println(c);
	}
}

//  C#의 길이는 3
// true
//  C#, C++
// C#, C++
// Java, C++
// 분리된 문자열0: Java
// 분리된 문자열1:  C++
//  C++
// +


StringBuffer 클래스

String 클래스와 같이 문자열을 다룬다. String 객체의 경우 내부의 문자열을 수정할 수 없지만, StringBuffer 객체는 문자열을 저장하는 가변 버퍼를 가지고 있기 때문에 저장된 문자열의 수정이 가능하다. 문자열의 크기가 늘어나면 내부 버퍼 크기를 자동 조절한다.(내용 변경 가능. 배열구조와 흡사, 스트링버퍼가 무조건 스트링보다 낫다고 할 수 없음. 계속해서 바꾸는거면 스트링을 쓰나 스트링버퍼를 쓰나 차이가 없기 때문)

StringBuffer sb = new StringBuffer("java");

StringBuffer() -> 초기 버퍼의 크기가 16인 스트링 버퍼 객체 생성


Stringbuffer의 활용. (얘도 자주쓴다고 했던거같음)

메소드 설명
StringBuffer append(String str) str 스트링을 스트링 버퍼에 덧붙인다.
(이어붙이기)
StringBuffer append(StringBuffer sb) sb 스트링 버퍼를 현재의 스트링 버퍼에 덧붙인다. 이 결과 현재 스트링 버퍼의 내용이 변한다.
int capacity() 스트링 버퍼의 현재 크기 리턴
StringBuffer delete(int start, int end) start 위치에서 end 위치 앞까지 부분 문자열 삭제
StringBuffer insert(int offset, String str) str 스트링을 스트링 버퍼의 offset 위치에 삽입
(중간에 값 삽입)
StringBuffer replace(int start, int end, String str) 스트링 버퍼 내의 start 위치의 문자부터 end가 지정하는 문자 앞의 서브 스트링을 str로 대치
StringBuffer reverse() 스트링 버퍼 내의 문자들을 반대 순서로 변경
뒤집음
void set Length(int newLength) 스트링 버퍼 내 문자열 길이를 newlength로 재설정, 현재 길이보다 큰 경우 널 문자(‘‘)로 채우며 작은 경우는 기존 문자열이 잘린다.

*표에서 start, offset, end는 스트링 버퍼 내 위치를 나타내는 정수로, 위치는 0부터 시작한다.

public class StringBufferEx {

	public static void main(String[] args) {
		StringBuffer sb = new StringBuffer("This");
		
		sb.append(" is pencil");
		System.out.println(sb);
		
		sb.insert(7, " my");
		System.out.println(sb);
		
		sb.replace(8, 10, "your");
		System.out.println(sb);
		
		sb.delete(8, 13);
		System.out.println(sb);
		
		sb.setLength(4);
		System.out.println(sb);  //알아서 toString()해줌. 참고로 반드시 toString해야 글자 꺼낼 수 있음.
	}
}

// This is pencil
// This is my pencil
// This is your pencil
// This is pencil
// This


StringTokenizer 클래스

하나의 문자열을 여러개의 문자열로 분리하기 위해 사용된다. 문자열을 분리할 때 사용되는 기준 문자를 구분문자라고 하고, 구분 문자로 분리된 문자열을 토큰이라고 한다. (splite와 유사. 구분기호를 이용해서 끊어준다. 둘중에 편한거 쓰면 된다.)

아래 이미지(StringTokenizer 클래스 주요 메소드) 세개의 조합이 필요함?

public class StringTokenTokenizer {

	public static void main(String[] args) {
		StringTokenizer st = new StringTokenizer("홍길동/장화/홍련/콩쥐/팥쥐", "/");
		
		while(st.hasMoreTokens()) { //토큰이 있는 동안
			System.out.println(st.nextToken()); //다음으로 이동
		}
	}
}

// 홍길동
// 장화
// 홍련
// 콩쥐
// 팥쥐


Math 클래스

java.lang 패키지에 포함되어 있으며 기본적인 산술 연산을 제공한다. 모든 멤버 메소드는 static 타입이므로 다음과 같이 클래스 이름으로 바로 사용하면 된다.

double d = Math.random();
double pi = Math.PI; // 3.141592 원주율

Math 클래스의 주요 메소드


Math 클래스를 활용한 난수 발생

Math클래스에서 가장 많이 사용하는 메소드는 난수를 발생하는 random()이다. 이 메소드는 0.0보다 크거나 같고 1.0보다 작은 임의의 double값을 리턴한다.

public class MathEx {
	public static void main(String[] args) {		
		System.out.println(Math.PI);
		System.out.println(Math.ceil(3.14)); //올림
		System.out.println(Math.floor(3.14)); //내림
		System.out.println(Math.sqrt(9)); //제곱근
		System.out.println(Math.exp(2)); //e의 2승
		System.out.println(Math.round(3.14)); //반올림
		
		System.out.print("이번주 행운의 번호는 ");
		for(int i = 0; i < 5; i++) {
			System.out.print((int)(Math.random()*45 + 1) + " "); //1~45까지의 수를 int타입으로 강제변환해서 난수 발생시키기
		}
	}
}

// 3.141592653589793
// 4.0
// 3.0
// 3.0
// 7.38905609893065
// 3
// 이번주 행운의 번호는 27 33 8 25 29 

Calendar 클래스

프로그램이 실행되는 동안 개발자가 기억하고자 하는 시간과 날짜정보를 저장하고, 아래의 이미지와 같은 필드를 인자로 하여 set(), get()메소드를 이용하여 날짜나 시간을 알아내거나 설정한다.

Calendar 클래스의 get(), set()에 사용되는 static 상수)


Calendar 객체 생성 - 현재 날짜와 시간

calendar 클래스는 추상 클래스이므로, new Calendar()를 사용하지 않고 getInstance() 메소드를 통해 다음과 같이 객체를 생성한다.

Calendar now = Calendar.getInstance();

get(Calendar,MONTH)는 1월달이면 0을 리턴하기 때문에 month에 1을 더한다.


날짜와 시간 설정하기

set() 메소드는 calendar 객체에 날짜와 시간을 설정하는 메소드이다.


예제 6-11) calendar를 이용하여 현재 날짜와 시간을 알아내는 방법과 개발자가 저장하고자 하는 날짜와 시간을 기억하는 방법을 알아본다.

import java.util.Calendar;

public class CalendarEx {
	public static void printCalendar(String msg, Calendar cal){
		int year = cal.get(Calendar.YEAR);
		int month = cal.get(Calendar.MONTH) + 1;  //get()은 0~30까지의 정수 리턴
		int day = cal.get(Calendar.DAY_OF_MONTH);
		int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
		int hour = cal.get(Calendar.HOUR);
		int hourOfDay = cal.get(Calendar.HOUR_OF_DAY);
		int ampm = cal.get(Calendar.AM_PM);
		int minute = cal.get(Calendar.MINUTE);
		int second = cal.get(Calendar.SECOND);
		int millisecond = cal.get(Calendar.MILLISECOND);
		System.out.println(msg + year + "/" + month + "/" + day + "/");
		
		switch(dayOfWeek) {
			case Calendar.SUNDAY : 
				System.out.println("일요일");
				break;
			case Calendar.MONDAY : 
				System.out.println("월요일");
				break;
			case Calendar.TUESDAY :
				System.out.println("화요일");
				break;
			case Calendar.WEDNESDAY : 
				System.out.println("수요일");
				break;
			case Calendar.THURSDAY :
				System.out.println("목요일");
				break;
			case Calendar.FRIDAY : 
				System.out.println("금요일");
				break;
			case Calendar.SATURDAY : 
				System.out.println("토요일");
				break;
		}
		
		System.out.println("(" + hourOfDay + "시");
		if(ampm == Calendar.AM) {
			System.out.print("오전");
		}else{
			System.out.print("오후");
		}
		
		System.out.println(hour + "시" + minute + "분" + second + "초" + millisecond + "밀리초");
				
	}

	public static void main(String[] args) {
		Calendar now = Calendar.getInstance();
		printCalendar("현재 ", now);
		
		Calendar firstDate = Calendar.getInstance();
		firstDate.clear();
		firstDate.set(2016, 11, 25); //2016년 12월 25일. 12월을 표현하기 위해 month에 11로 설정
		
		firstDate.set(Calendar.HOUR_OF_DAY, 20); //저녁 8시
		firstDate.set(Calendar.MINUTE, 30); //30분
		printCalendar("처음 데이트 한 날은 ", firstDate);
		
	}
}

// 현재 2021/6/28/
// 월요일
// (20시
// 오후8시51분54초94밀리초
// 처음 데이트 한 날은 2016/12/25/
// 일요일
// (20시
// 오후8시30분0초0밀리초

07. 제네릭과 컬렉션 (컬렉션이 중요!!!)

컬렉션의 개념

컬렉션은 안드로이드를 비롯한 자바 프로그램을 작성하는데 빼놓을 수 없는 중요한 도구이다. 또한 컬렉션은 제네릭이라는 기법으로 구현되어 있다.

컬렉션은 배열이 가진 고정 크기의 단점을 극복하기 위해 객체들을 쉽게 삽입, 삭제, 검색할 수 있는 가변 크기의 컨테이너이다.

컬렉션 클래스는 개발자가 바로 사용할 수 있는 것들로서, Vector와 ArrayList는 가변 크기의 배열을 구현하며, LinkedList는 노드들이 링크로 연결되는 리스트를 구현한다. Stack는 스택을 구현하며, HashSet은 집합을 구현한다. 이들은 모두 Collection를 상속받고, 단일 클래스의 객체만을 요소로 다루는 공통점이 있다. 이와 달리 HashMap<K, V>는 키와 값의 쌍으로 이루어지는 데이터를 저장하고, 키로 쉽게 검색하도록 만든 컬렉션이다.


제네릭의 기본 개념

제네릭은 모든 종류의 타입을 다룰 수 있도록, 클래스나 메소드를 타입 매개변수를 이용하여 선언하는 기법이다. (제네릭은 생산성 향상을 위한 도구)

자바의 제네릭은 C++의 템플릿과 동일하다. 템플릿이란 형판이다. 즉 본 떠 찍어내기 위해 만들어진 틀이다. 자바의 제네릭은 클래스 코드를 찍어내듯이 생산할 수 있도록 일반화시키는 도구이다.

Stack에서 E에 구체적인 타입을 지정하면, 지정된 타입만 다룰 수 있는 구체화된 스택이 된다.</u> 예를들어, Stack는 Integer 타입만 다루는 스택이 되고, Stack는 Point 타입의 객체만 푸시하고 팝 할수 있는 스택이 된다.


제네릭 타입 매개변수

컬렉션 클래스에서 타입 매개변수로 사용하는 문자는 다른 변수와 혼동을 피하기 위해 일반적으로 하나의 대문자를 사용한다.

  • E : Element를 의미하며 컬렉션에서 요소임을 나타냄
  • T : type
  • V : Value
  • K : Key

Vector

배열을 가변 크기로 다룰 수 있게 하고, 객체의 삽입, 삭제, 이동이 쉽도록 구성한 컬렉션 클래스이다. 벡터는 삽입되는 요소의 개수에 따라 자동으로 크기를 조절하고, 요소의 삽입과 삭제에 따라 자동으로 요소들의 자리를 이동한다. (데이터타입이 들어가면 된다. 벡터는 배열과 흡사한 구조) (매개변수. 클래스 이름이 들어가야 함. 일반클래스 못들어감. 일반변수 쓰려면 wrapper 감싸서 써야함. )

벡터 생성

벡터를 생성할 때 E에 요소로 사용할 타입을 지정해야 한다.

Vector<Integer> v = new Vector<Integer>();

//-분리하여 사용 가능-----------------------------------------------

Vector<String> StringVector;
StringVector = new Vector<String>();

int, char, double 등의 기본 타입은 E에 사용할 수 없다. (기본타입은 wrapper에 감싸줘야 함!!)

Vector<int> v = new Vector<int>();  //오류!!!

개발자는 생성된 벡터의 용량을 굳이 알 필요가 없다. 컬렉션은 자신의 용량을 스스로 조절하기 때문. 만일 용량을 초기에 설정하고자 한다면 다음과 같이 지정.

Vector<Integer> v = new Vector<Integer>(5);

add()를 이용하여 요소를 삽입하고 get()을 이용하여 요소를 검색한다.

(표) Vector 클래스의 주요 메소드


벡터에는 null도 삽입할 수 있다.

v.add(Integer.valueOf(null));  //맨 뒤에 값 삽입

//---------------------------------

v.add(null);  //맨 뒤에 값 삽입

//---------------------------------

v.add(2, 100);  //중간에 객체 삽입. 그 뒤에 있는 요소들은 모두 한자리씩 뒤로 이동

벡터 내의 요소 알아내기

get()이나 elementAt() 메소드를 이용한다. 이 메소드들은 인자로 주어진 인덱스에 있는 Integer 객체를 리턴한다.

Vector<Integer> v = new Vector<Integer>();
v.add(5);
v.add(4);
v.add(-1);

Integer obj = v.get(1);  //벡터의 1번째 Integer 객체를 얻어낸다.
int i = obj.intValue();  //obj에 있는 정수를 알아냄. 이 값은 4

//위의 두 문장을 한문장으로 압축
int i = v.get(1);  //자동 언박싱

벡터의 크기와 용량 알아내기
int len = v.size(); //벡터의 크기. 벡터에 존재하는 요소 객체의 수

int cap = v.capacity();  //벡터의 용량. 수용할 수 있는 크기

벡터에서 요소 삭제
v.remove(1);  //인덱스 1의 위치에 잇는 요소 삭제. 실행 후 요소들이 한자리씩 앞으로 이동.

v.removeAllElements();  //벡터의 모든 요소 삭제

(그림) Vector 생성 및 삽입 삭제 사례


컬렉션과 자동 박싱/언박싱

컬렉션은 객체들만 요소로 다룸. 그러므로 기본 타입의 값은 Wrapper 클래스로 객체화하여 삽입한다.

Vector<Integer> v = new Vector<Integer>();
v.add(Integer.valueOf(4));
v.add(Integer.valueOf(-1));

//-자동박싱-------------------------------------------------
v.add(4);
v.add(-1);

컬렉션으로부터 값을 얻어내는 과정에서는 자동 언박싱이 일어난다.

int k = v.get(0); //k = 4

컬렉션을 매개변수로 받는 메소드 만들기

//컬렉션을 매개변수로 전달받는 메소드 선언
public void printVector(Vector<Integer> v){
	for(int i = 0; i<v.size(); i++){
		int n = v.get(i); //벡터의 i번째 정수
		System.out.println(n);
	}
}

//메소드 호출
Vector<Integer> v = new Vector<Integer>(); //Integer 벡터 생성
printVector(v);  //메소드 호출

ArrayList

가변 크기의 배열을 구현한 컬렉션 클래스로써 Vector 클래스와 거의 동일하다. 크게 다른점은 ArrayList는 스레드 간에 동기화를 지원하지 않기 때문에, 다수의 스레드가 동시에 ArrayList에 요소를 삽입하거나 삭제할 때 데이터가 훼손될 우려가 있다. 하지만 멀티스레드 동기화를 위한 시간 소모가 없기때문에 벡터보다 속도가 빨라, 단일 스레드 응용에는 더 효과적이다. (삽입 가능한건 객체, null 앞과 같음. 벡터와 차이점은 스레드 동기화 없음. 스레드는 동시에 작업하는거)

add() 를 이용하여 요소를 삽입하고 get() 을 이용하여 요소를 검색한다.

주요 메소드는 Vector와 거의 비슷하다


ArrayList의 생성

문자열만 다루는 ArrayList ArrayList는 스스로 용량을 조절하기때문에 용량에 대해 신경 쓸 필요가 없다.

ArrayList<String> a = new ArrayList<String>();  //a는 문자열만 삽입하고 검색 가능. 
a.add("Hello");
a.add("Hi");
a.add("Java");

a.add(null);  //ArrayList에도 Vector와 마찬가지로 null을 삽입할 수 있다.

a.add(2, "Sahni");  //인덱스 2의 위치에 문자 삽입

String str = a.get(1);  //요소 알아내기. "Hi" 리턴

int len = a.size();  //크기 알아내기. 들어있는 요소의 개수
//ArrayList는 벡터와 달리 현재 용량을 리턴하는 메소드가 없다.

a.remove(1);  //요소 삭제

a.clear(); //모든 요소 삭제

ArrayList는 벡터와 달리 현재 용량을 리턴하는 메소드가 없다.

import java.util.*;

public class ArrayListEx {

	public static void main(String[] args) {
		ArrayList<String> a = new ArrayList<String>();  //문자열만 삽입 가능한 ArrayList 생성
		
		//키보드로부터 4개의 이름 입력받아 ArrayList에 삽입
		Scanner scanner = new Scanner(System.in);
		for(int i = 0; i <4; i++) {
			System.out.print("이름을 입력하세요 >> ");
			String s = scanner.next();
			a.add(s);  //ArrayList 컬렉션에 삽입
		}
		
		//ArrayList에 들어 있는 모든 이름 출력
		for(int i = 0; i <a.size(); i++) {
			String name = a.get(i);
			System.out.println(name + " ");
		}
		
		//가장 긴 이름 출력
		int lingestIndex = 0;  //현재 가장 긴 이름이 있는 ArrayList 내의 인덱스
		for(int i=1; i<a.size(); i++) {
			if(a.get(lingestIndex).length() < a.get(i).length()) {
				lingestIndex = i;  //i번째 이름이 더 긴 이름임
			}
		}
		System.out.println("\n 가장 긴 이름은 : " + a.get(lingestIndex));
		scanner.close();
	}

}

컬렉션의 순차 검색을 위한 Iterator

Vector, ArrayList, LinkedList, Set과 같이 요소가 순서대로 저장된 컬렉션에서 요소를 순차적으로 검색할 때 사용한다. 여기서 는 컬렉션의 매개변수와 동일한 타입을 지정해야 한다. (데이터가 저장된 공간을 가리키는 화살표라고 생각해라)

Vector<Integer> v = new vector<Integer>();  //요소가 Integer 타입인 벡터

Iterator<Integer> it = v.Iterator();  //벡터의 v요소를 순차 검색할 Iterator 객체 리턴

while(it.hasNext()){  //it로 벡터의 끝까지 반복
	int n = it.next();  //it가 가리키는 요소 리턴. 가리킴과 동시에 값을 뽑아서 저장!!!!!!!!
}

Iterator 인터페이스의 메소드)

메소드 설명
boolean hasNext() 방문할 요소가 남아있으면 true 리턴
E next() 다음 요소 리턴
void remove() 마지막으로 리턴된 요소 제거
import java.util.*;

public class IteratorEx {

	public static void main(String[] args) {
		//정수 값만 다루는 제네렉 벡터 생성
		Vector<Integer> v = new Vector<Integer>();
		
		v.add(5);
		v.add(4);
		v.add(-1);
		v.add(2, 100);
		
		//Iterator를 이용한 모든 정수 출력하기
		Iterator<Integer> it = v.iterator();  //Iterator 객체 얻기
		while(it.hasNext()) {  //while 문은 벡터 v의 모든 정수 출력
			int n = it.next();
			System.out.println(n);
		}
		
		//Iterator를 이용하여 모든 정수 더하기
		int sum = 0;
		it = v.iterator();  //it 다시 설정
		while(it.hasNext()) {  //while 문은 벡터 v의 모든 정수합 계산
			int n = it.next();
			sum += n;
		}
		
		System.out.println("벡터에 있는 정수 합 : " + sum);
	}

}


HashMap<K, V>

키(key)와 값(value)의 쌍으로 구성되는 요소를 다룬다. k는 키로 사용할 데이터 타입을, v는 값으로 사용할 데이터 타입의 매개변수이다. put(), get() 메소드를 이용하여 요소를 삽입하거나 검색한다. (key는 중복 x, value는 중복 o)

HashMap<String, String> h = new HashMap<Sring, String>();  //해시맵 생성
h.put("apple", "사과");  //키(apple)와 값(사과) 삽입
String kor = h.get("apple"); //키로 값 검색. 검색된 값은 사과

put(key, value) 메소든는 키와 값을 받아, 키를 이용하여 해시 함수를 실행하고 해시 함수가 리턴하는 위치에 키와 값을 저장한다.
get(key) 는 다시 키를 이용하여 동일한 해시 함수를 실행하여 값이 저장된 위치를 알아내어 값을 리턴한다.


해시맵의 장단점

해시맵은 List 인터페이스를 상속받은 Vector나 ArrayList와는 다른점이 있다.

  1. 요소의 삽입, 삭제 시간이 매우 빠르다. 요소의 위치를 결정하는 해시 함수가 간단한 코드로 이루어지며, Vector나 ArrayList와 달리 요소의 삽입삭제시 다른 요소들의 위치 이동이 필요 없기 때문이다.
  2. 요소 검색은 더욱 빠르다. 해시맵의 get(key) 메소드가 호출되면 해시 함수가 key가 저장된 위치를 단번에 찾아내므로 Vector나 ArrayList에서처럼 모든 요소들을 하나씩 비교하는 시간 낭비가 전혀 없기 때문이다.
  3. 하지만 해시맵은 인덱스를 이용하여 요소에 접근할 수 없고 오직 키로만 검색해야한다. 그러므로 해시맵은 빠른 삽입과 검색이 필요한 응용에 적합하다.

HashMap<K, V> 클래스의 주요 메소드)


해시맵 생성

해시맵은 HashMap<K, V>에서 K에는 키로, V에는 값으로 사용할 구체적인 타입을 지정하여 생성한다.

HashMap<String, String> h = new HashMap<String, String>();

h.put("baby", "아기");  //해시맵 요소 삽입
h.put("love", "사랑");
h.put("apple", "사과");

String kor1 = h.get("love"); //kor1 = "사랑". 키로 값 읽기
String kor3 = h.get("babo"); //kor3 = null. 없는 키로 호출하면 null 리턴

h.remove("apple"); //키로 요소 삭제

int n = h.size();  //요소 개수 알아내기

만일 해시맵에 없는 키로 get()을 호출하면 null을 리턴한다.


해시맵의 전체 검색

모든 키를 알아낸 후, 각 키에 하나씩 값을 알아내는 방식으로 작성하면 된다. keySet() 메소드는 모든 ‘키’를 Set 컬렉션으로 만들어 리턴한다.

Set<String> keys = h.keySet();  //해시맵 h에 있는 모든 키를 Set 컬렉션으로 리턴
Iterator<String> it = keys.iterator();
while(it.hasNext()){
	String key = it.next();  // 키
	String value = h.get(key); //값
	System.out.println(key, value);
}

HashMap<String, String> 컬렉션의 생성 및 삽입 삭제 사례)


import java.util.*;

public class HashMapScoreEx {

	public static void main(String[] args) {
		//이름과 점수를 저장할 HashMap 컬렉션 생성
		HashMap<String, Integer> scoreMap = new HashMap<String, Integer>();
		
		//5개의 점수 저장
		scoreMap.put("김성동", 97);
		scoreMap.put("황기태", 88);
		scoreMap.put("김남윤", 98);
		scoreMap.put("이재문", 70);
		scoreMap.put("한원선", 99);
		
		System.out.println("HashMap의 요소 개수 : " + scoreMap.size());
		
		//모든 사람의 점수 출력. scoreMap에 들어있는 모든 (key, value) 쌍 출력
		Set<String> keys = scoreMap.keySet();  //모든 key를 가진 Set 컬렉션 리턴
		Iterator<String> it = keys.iterator();  //set에 있는 모든 key를 순서대로 검색하는 Iterator 리턴
		
		while(it.hasNext()) { //모든 점수 출력
			String name = it.next();  //다음 키. 학생이름
			int score = scoreMap.get(name);  //점수 알아내기
			System.out.println(name + " : " + score);
		}
	}
}
//출력된 결과는 삽입된 순서와 다르다.

key.Set();은 키 목록만 분리? 추출하기!!! iterator는 화살표를 만듬 hash는 Iterator 못만듬.(컬렉션을 상속받지 못해서) while로 화살표 옮기면서 키값에 저장된 값 뽑아옴.


LinkedList

요소들을 양방향으로 연결하여 관리한다는 점을 제외하고 Vector, ArrayList와 거의 같다.
add()메소드와 get()메소드를 가진다.
맨 앞과 맨 뒤를 가리키는 head, tail 레퍼런스를 가지고있오, 맨앞이나 맨 뒤, 중간에 요소의 삽입이 가능하며 인덱스를 이용하여 요소에 접근할 수도 있다. (이전까지는 다 컬렉션을 가지고 구현했음.)
(꼬리를 물고 다음을 계속 만듬)

LinkedList는 중간에 값을 삽입할 때 효율적이다.(기록시 유리, 대량의 데이터 입력시 유리) ArrayList는 추가하다가 공간 다 차면 이사가야 한다. 연속된 공간이 할당되어 있음.(읽는거 유리)


Collections 클래스 활용

다음과 같이 컬렉션을 다루는 유용한 여러 메소드를 지원한다.

  • sort() - 컬렉션에 포함된 요소들의 정렬
  • reverse() - 요소를 반대 순으로 정렬
  • max(), min() - 요소들의 최댓값과 최솟값 찾아내기
  • binarySearch() - 이진검색

Collections 클래스의 메소드는 모드 static 타입이므로 객체를 생성할 필요가 없다.


import java.util.*;

public class CollectionsEx {
	static void printList(LinkedList<String> l) {  //리스트의 요소를 모두 출력하는 메소드
		Iterator<String> iterator = l.iterator();
		while (iterator.hasNext()) {
			String e = iterator.next();
			String separator;
			if(iterator.hasNext()) {
				separator = "->";  //마지막 요소가 아니면 -> 출력
			}else {
				separator = "\n";  //마지막 요소이면 줄바꿈
			}
			System.out.print(e+separator);		
		}
	} 
	
	public static void main(String[] args) {
		LinkedList<String> myList = new LinkedList<String>();  //빈 리스트 생성
		myList.add("트랜스포머");
		myList.add("스타워즈");
		myList.add("매트릭스");
		myList.add(0, "터미네이터");
		myList.add(2, "아바타");
		
		Collections.sort(myList);  //요소 정렬. sort()는 static 메소드이므로 클래스 이름으로 바로 호출한다.
		printList(myList);  //정렬된 요소 출력
		
		Collections.reverse(myList);  //요소의 순서 반대로 구성
		printList(myList);
		
		int index = Collections.binarySearch(myList, "아바타") + 1;  //이분법?이진법? 중간 찾아서 양옆으로 이동
		System.out.println("아바타는" + index + "번째 요소입니다.");
	}
}
// 매트릭스->스타워즈->아바타->터미네이터->트랜스포머
// 트랜스포머->터미네이터->아바타->스타워즈->매트릭스
// 아바타는3번째 요소입니다.

ArrayList add()** 를 이용하여 요소를 삽입 get()** 을 이용하여 요소를 검색

Vector add()를 이용하여 요소를 삽입 get()을 이용하여 요소를 검색

Iterator hasNext next

HashMap put(key, value)** 메소든는 키와 값을 받아, 키를 이용하여 해시 함수를 실행하고 해시 함수가 리턴하는 위치에 키와 값을 저장 get(key)** 는 다시 키를 이용하여 동일한 해시 함수를 실행하여 값이 저장된 위치를 알아내어 값을 리턴

LinkedList add()메소드와 get()메소드를 가진다.


제네릭 만들기, 제네릭 클래스

제네릭은 빈도수가 높지 않다. 교수님도 사용한적 별로 없음. 개념만 알고 나중에 필요할 때 보고 만들기.
컬렉션 자체가 제네릭으로 구성되어있어서 묶여있음. 제네릭은 빈도수 x, 단 컬렉션은 반드시! 해시 사용법은 반드시 익히기. 컬렉션은 뭐 쓸때 뭐가 더 좋은지 익히기

제네릭은 모든 종류의 타입을 다룰 수 있도록, 클래스나 메소드를 타입 매개변수를 이용하여 선언하는 기법이다. (제네릭은 생산성 향상을 위한 도구)


08. 입출력 스트림과 파일 입출력

스트림 입출력이란?

컴퓨터공학에서 연속적인 데이터의 흐름 혹은 데이터를 전송하는 소프트웨어 모듈을 일컫는다. 컴퓨터에서 스트림은 도착한 순서대로 데이터를 흘러 보낸다.

자바에서 입출력 스트림으 응용프로그램과 입출력 장치를 연결하는 소프트웨어 모듈이다.

  • 스트림의 양끝에는 입출력 장치와 자바 응용프로그램이 연결된다.
  • 스트림은 단방향 이다 : input, output스트림 두가지 기능을 모두 가진 스트림은 없다.
  • 스트림을 통해 흘러가는 기본 단위는 바이트나 문자다
  • 스트림은 선입선출, 즉 FIFO 구조이다.(ex 키보드, 스택은 후입선출)

바이트 스트림과 문자 스트림

자바에서 입출력 스트림은 바이트스트림(~Stream)과 문자스트림(Reader, Writer)의 2종류이다. 바이트스트림은 정보를 단순 바이너리(비트들)로 다루기 때문에 문자든 이미지든 상관없이 흘려보낸다.
문자스트림은 문자만 다루기 때문에 문자가 아닌 데이터가 출력되면 보이지 않거나, 엉뚱한 기호가 출력된다.


스트림 연결

스트림은 서로 연결될 수 있다.(ex 쿠키 굽는 시스템)
키보드와 연결된 표준 입력스트림인 System.in

InputStream rd = new InputStream(System.in);
int c = rd.read();  //입력 스트림으로부터 키 입력. c는 입력된 키의 문자값

문자 스트림 클래스

2바이트의 유니코드 문자를 단위로 입출력하는 스트림이다.(문자스트림은 정말로 문자만!)


파일 입력 스트림 생성
FileReader fin = new FileReader("c:\\test.txt");
파일 읽기
int c;   //2바이트로 끊음
while( (c = fin.read()) != -1 ){   //문자 하나에 c를 읽어들인다. 파일을 끝까지 반복한다.
  System.out.print((char)c);  //char 형변환해서 사용
}
파일이 큰 경우 버퍼 사용
char [] buf = new char[1024];   //1024는 1KB이다
int n = fin.read(buf);  //한번에 1024개 문자를 읽어 buh[]에 저장하고 리턴

스트림 닫기

fin.close();

파일 입출력과 예외처리

첫째, 파일의 경로명이 틀린 경우 FileNotFoundException 예외 발생

FileReader fin = new FileReader("c:\\test.txt");

둘째, 파일 읽기, 쓰기, 닫기를 하는 동안 입출력 오류가 발생하면 IOException 에외 발생

int c = fin.read();

그러므로 파일 입출력 코드에 try-catch 블록이 필요하다

//구조 순서?
Exception
ㄴIOE
  ㄴFileNotFoundException

try{
  FileReader fin = new FileReader("c:\\test.txt");  //FileNotFoundException 오류 발생 가능
  ...
  int c = fin.read();  //IOException 오류 발생 가능
  ...
  fin.close();  //fin이 null상태이거나 파일을 열고있지 않았을때 오류 발생 가능
}catch(FileNotFoundException e){
  System.out.ptintln("파일을 읽을 수 없음");
}catch(IOEception){
  System.out.ptintln("입출력 오류");
}

//catch문 맨 위에(첫번째로) Exception 넣으면 오류 발생시 얘가 다 채가서 안된다. catch문은 순서대로(위에서 아래)로 잡기 때문. java문 맨 위에 구조순서? 참조!
//그렇기때문에 중요한 예외는 전용으로 만들어서 위로 뺀다!!!

예제 8-1) FileReader로 텍스트 파일 읽기

import java.io.*;

public class FileReaderEx{
  public static void main(String[] args){
    FileReader fin = null;
    try{
      fin = new FileReader("c:\\windows\\system.ini"); //문자 입력 스트림 생성. 오류 발생 가능->FileNotFound 경로에 파일 없을때 
      int c;
      while( (c = fin.read()) != -1 ){  //오류 발생 가능->읽는 중 오류
        System.out.print((char)c);
      }
      fin.close();  //오류 발생 가능->fin이 null상태일때, 파일을 열고있지 않았을 때 
    }catch(IOException e){   //이 위에 catch로 IOE보다 상위인 Exception 넣으면 얘가 다 채가서 안된다. 중요한 예외는 전용으로 만들어서 위로 뺄 것!!!!!!!!! catch는 위에서 아래로 순서대로 잡힘
      System.out.println("입출력 오류");
    }
  }
}

문자 집합과 InputStreamReader를 이용한 텍스트 파일 읽기

InputStreamReader는 스트림에 입력되는 바이트 데이터를 문자 집합을 통해 문자로 변환한다. (인풋 스트림은 읽을때 쓸때 바이트 단위로!!!)


InputStreamReader로 문자 입력 스트림 생성

FileInutStream fin = new FileInputStream("c:\\Temp\\hangul.txt");  //바이로 읽음
InputStreamReader in = new InputStreamReader(fin, "UTF-8");  //글자로 바꿔줌

예제 8-2) InputStreamReader로 한글 텍스트 파일 읽기

import java.io.*;
public class FileReadHangulSuccess {

	public static void main(String[] args) {
		InputStreamReader in = null;
		FileInputStream fin = null;
		
		try{
			fin = new FileInputStream("D:\\C_project\\hangul.txt");
			in = new InputStreamReader(fin, "UTF-8");
			int c;
			
			System.out.println("인코딩 문자 집합은 " + in.getEncoding());  //in.getEncoding은 
			while((c = in.read()) != -1 ) {
				System.out.print((char)c);
			}
			in.close();
			fin.close();
			
		}catch(IOException e) {
			System.out.println("입출력 오류");
		}

	}

}

FileWriter를 이용한 텍스트 파일 쓰기(문자로 기록)

파일 출력 스트림 생성
FileWriter fout = new FileWriter("c:\\Temp\\test.txt");

FileWriter의 생성자는 c:\Temp\test.txt 파일을 열어 스트림과 연결한다. 파일이 빈 경우 빈 파일을 생성하며, 이미 파일이 있는 경우 파일 내용을 지우고 파일의 처음부터 쓸 준비를 한다.

파일 쓰기
fout.write('A');   //close까지해줘야 기록됨

char [] buf = new char[1024];   //1024까지 담을 수 있는 버퍼 만들기
fout.write(buf, 0, buf.length;)   //0은 시작위치값, 그뒤는 길이(쓸 갯수)
스트림 닫기
fout.close();

예제 8-4) 키보드 입력을 파일로 저장하기

import java.io.*;
import java.util.*;

public class FileWriterEx {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		FileWriter fout = null;
		//int c;
		try {
			fout = new FileWriter("D:\\C_project\\hangul.txt");
			while(true) {
				String line = scanner.nextLine();  //빈 칸을 포함하여 한 줄 읽기. line에는 \n이 들어가지 않음
				if(line.length() == 0) {  // 한 줄에 enter키만 입력한 경우
					break;
				}
				fout.write(line, 0, line.length());  //읽은 문자열을 파일에 저장
				fout.write("\r\n", 0, 2);  //한 줄 띄기 위해 \r\n을 파일에 
			}
			fout.close();
		}catch(IOException e) {
			System.out.println("입출력 오류");
		}
		scanner.close();
	}

}

바이트 스트림 클래스

바이트 단위로 바이너리 데이터가 흐르는 스트림이다. 이미지나 동여앙 파일 입출력에 필수적이고, 문자들로 구성된 텍스트 파일도 입출력 할 수 있다

  • InputStream/OutputStream : 추상클래스이며, 바이트 입출력 처리를 위한 공통 기능을 가진 슈퍼 클래스이다.
  • FileInputStream/FileOutputStream : 파일 입출력을 위한 클래스로서, 파일로부터 바이너리 데이터를 읽거나 파일에 바이너리 데이터를 저장할 수 있다.
  • DataInputStream/dataOutputStream : 이 스트림을 이용하면 boolean, char … 타입의 값을 바이너리 형태로 입출력한다. 문자열도 바이너리 형태로 입출력한다.

FileOututStream을 이용한 바이너리 파일 쓰기

바이너리값을 그대로 파일에 저장해야하는 경우가 있다. 메모리에 있는 이미지 비트들을 그대로 이미지 파일로 저장하는 경우이다.

파일 출력 스트림 생성
FileOutputStream fout = new FileOutputStream("c:\\Temp\\test.out");

파일이 이미 있으면 그 내용을 지우고 스트림에 연결한다. 쓰기가 이루어지면 해당 파일은 바이너리 파일이 된다.

파일 쓰기
byte b[] = {7,51,3,4,-1,24};
for(int i=0; i<b.length; i++){
  fout.write(b[i]);
}

//for문 없이 한번에 배열 b[]를 저장할 수도 있다.
fout.write(b);

예제 8-5) FileOututStream로 바이너리 파일 쓰기

import java.io.*;

public class FileOutputStreamEx {

	public static void main(String[] args) {
		byte b[] = {7, 51, 3, 4, -1, 24};
		
		try {
			FileOutputStream fout = new FileOutputStream("D:\\C_project\\test.out");
			for(int i=0; i<b.length; i++) {
				fout.write(b[i]);
			}
			fout.close();
		}catch(IOException e) {
			System.out.println("D:\\C_project\\hangul.txt에 저장할 수 없습니다. 경로명 확인");
			return;
		}
		System.out.println("D:\\C_project\\hangul.txt을 저장했습니다.");
	}

}

FileInputStream을 이용한 바이너리 파일 읽기

파일 입력 스트림 생성
FileInputStream fin = new FileInputStream("c:\\Temp\\test.out");
파일 읽기
byte b[] = new byte [6];  //비어있는 배열
int n=0, c;
while( (c=fin.read()) != -1 ){  //파일 끝(EOF)까지 한 바이트씩 읽기
  b[n] = (byte)c;  //읽은 바이트를 배열에 저장
  n++;
}
for(int i=0; i<b.length; i++){
  fout.write(b[i]);
}

//이 코드의 끝에 있는 다섯 줄은 한줄로 한번에 배열로 읽어들일 수 있다
fin.read(b);  //파일에서 배열 b[]의 크기만큼 바이트 읽기
스트림 닫기
fin.close();

8-6) FileInputStream로 바이너리 파일 읽기

import java.io.*;

public class FileInputStreamEx {

	public static void main(String[] args) {
		byte b[] = new byte[6];
		try {
			FileInputStream fin = new FileInputStream("D:\\C_project\\test.out");
			int n=0, c;
			while((c = fin.read()) != -1 ) {
				b[n] = (byte)c;
				n++;
			}
			System.out.println("D:\\C_project\\hangul.txt에서 읽은 배열을 출력합니다.");
			for(int i=0; i<b.length; i++) {
				System.out.println(b[i] + " ");
			}
			System.out.println();
			
			fin.close();
		}catch(IOException e) {
			System.out.println("D:\\C_project\\hangul.txt에서 읽지 못했습니다. 경로명 체크");
		}
	}

}

버퍼입출력과 파일 입출력

버퍼스트림 역시 데이터의 타입에 따라 바이트 버퍼 스트림과 문자 버퍼 스트림으로 구분된다.

버퍼 출력 스트림 생성
BufferedOutputStream bout = new BufferedOutputStream(System.out, 20);
스트림 출력
FileReader fin = new FileReader("c:\\test.txt");
int c;
while( (c=fin.read()) != -1 ){  //파일 끝을 만날 때까지 문자들을 하나씩 읽는다
  bout.write((char)c);  //읽은 문자를 버퍼 출력 스트림에 쓴다. 출력 스트림과 연결된 화면에 출력된다
}

버퍼에 남아 있는 데이터 출력★★★

버퍼는 꽉 찼을 때 출력된다. 버퍼가 다 차지 않는 상태에서 버퍼에 있는 데이터를 강제로 출력장치로 보내려면 flush() 메소드를 호출하면 된다.

bout.flush();  //데이터가 다 차지 않더라도 남아있는 데이터 모두 출력!!!
스트림 닫기
bout.close();
fin.close();

예제 8-7) 버퍼 스트림을 이용한 출력

import java.io.*;
import java.util.Scanner;

public class BufferedIOEx {

	public static void main(String[] args) {
		FileReader fin = null;
		int c;
		try {
			fin = new FileReader("D:\\C_project\\test2.txt");
			BufferedOutputStream out = new BufferedOutputStream(System.out, 5);
			while((c = fin.read()) != -1) {  //파일 데이터를 모두 스크린에 출력
				out.write(c);
			}
      //파일 데이터가 모두 출력된 상태
			new Scanner(System.in).nextLine(); //enter키 입력. 정상적으로 출력되는지 확인
			out.flush();  //버퍼에 남아있던 문자 모두 출력
			fin.close();
			out.close();
		}catch(IOException e) {
			e.printStackTrace();
		}
	}

}

File 클래스

파일이나 디렉터리에 대해 경로명, 크기, 타입, 수정날짜 등의 속성 정보를 제공하고, 파일삭제, 디렉터리 생성, 파일 이름 변경, 디렉터리 내의 파일 리스트 제공 등 다양한 파일 관리 작업을 지원한다. File클래스에는 파일 입출력 기능은 없다.

  • length() : 파일이나 디렉터리 크기 리턴
  • getName() : 파일명만
  • getPath() : 완전 경로명
  • getParent() : 부모 디렉터리를 문자열로 리턴
  • isFile() : 파일인경우 true 리턴
  • isDirectory() : 디렉터리인 경우 true 리턴
  • listFiles() : 모든 파일과 서브디렉터리의 리스트를 얻을 수 있다.

예제 8-8) file 클래스를 활용한 파일관리

import java.io.File;

public class fileEx {
	public static void listDirectory(File dir) {  //디렉토리에 포함된 파일과 서브 디렉토리의 이름, 크기, 수정 시간을 출력하는 메소드
		System.out.println("------" + dir.getPath() + "의 서브 리스트입니다.-------");
		
		File[] subFiles = dir.listFiles();  //디렉토리에 포함된 파일과 디렉토리 이름의 리스트 얻기
		
		for(int i=0; i<subFiles.length; i++) {  //subFiles 배열의 각 File에 대해 루프
			File f = subFiles[i];
			long t = f.lastModified();  //마지막으로 수정된 시간
			System.out.print(f.getName());
			System.out.print("\t파일크기 : " + f.length());  //파일크기
			System.out.printf("\t수정한 시간 : %tb %td %ta %tT\n", t, t, t, t);  //포맷 출력
		}
	}

	public static void main(String[] args) {
		File f1 = new File("C:\\Windows\\system.ini");
		System.out.println(f1.getPath() + ", " + f1.getParent() + ", " + f1.getName());
		
		String res = "";
		if(f1.isFile()) {  //파일타입이면
			res = "파일";
		}else if(f1.isDirectory()) {  //디렉토리 타입이면
			res = "디렉토리";
		}
		System.out.println(f1.getPath() + "은 " + res + "입니다.");
		
		File f2 = new File("C:\\Temp\\java_sample");  //새로 만들고자 하는 디렉토리
		if( !(f2.exists()) ) {  //f2 디렉터리가 존재하는지 검사
			f2.mkdir();  //존재하지 않으면 디렉토리 생성. mkdir은 폴더 만드는 명령
		}
		
		listDirectory(new File("C:\\Temp"));  //파일 리스트 출력
		f2.renameTo(new File("C:\\Temp\\javasample"));  //java_sample->javasample로 파일 이름 변경/ renameTo는 파일 폴더 이름 바꾸기
		listDirectory(new File("C:\\Temp"));  //javasample로 변경한 후 리스트 출력
	}

}

텍스트 파일 복사

텍스트파일은 문자 스트림이나 바이트 스트림 중 어떤 것을 사용해도 무관하다.
FileReader를 이용하여 텍스트 파일을 읽고, FileWriter로 텍스트 파일에 복사한다. 파일 경로명은 File 객체를 이용한다


바이너리 파일 복사

바이너리파일은 바이트스트림으로 읽고 써야 정확하게 복사가 이루어진다. 이미지, 동영상, 실행파일(exe)뿐만 아니라 텍스트 파일도 복사 가능하다.


블록 단위로 파일 고속 복사(묶은 단위로 복사할 때 복사가 더 빠르다. 그래서 고속복사)

버퍼 사용한다. 일정 사이즈 잡고 파일 복사한다. 많이 쓴다~~

예제 8-11) 블록 단위로 바이너리 파일 고속 복사

import java.io.*;

public class BlockBinaryCopyEx {

	public static void main(String[] args) {
		File src = new File("C:\\Windows\\Web\\Wallpaper\\Theme1\\img2.jpg");
		
		File dest = new File("C:\\Temp\\desert.jpg");  //복사파일
		try {
			FileInputStream fi = new FileInputStream(src);  //파일 입력 바이트 스트림
			FileOutputStream fo = new FileOutputStream(dest);  //파일 출력 바이트 스트림
			byte[] buf = new byte[1024*10];  //여기부터 fi.close() 위까지 많이 씀!!!!!! 일정 사이즈 잡고 파일 
			while(true) {
				int n = fi.read(buf);  //버퍼 크기만큼 읽기. n은 실제 읽은 바이트
				fo.write(buf, 0, n);  //buf[0]부터 n 바이트 쓰기
				if(n < buf.length) {  // 같다면 while 계속 돈다
					break;  //버퍼 크기보다 작게 읽었기 때문에 파일 끝에 도달. 복사 종료
				}
			}
			fi.close();
			fo.close();
			System.out.println(src.getPath() + "를 " + dest.getPath() + "로 복사했습니다.");
		}catch(IOException e){
			System.out.println("파일 복사 오류");
		}
	}

}

최종 정리

바이트스트림 은 ~stream, 바이너리. 이진화데이터, 읽기는 ~InputStream, 저장은 ~OutputStream
문자스트림 은 ~reader, 문자만, 읽기는 ~reader, 쓰기는 ~writer


09. 자바 GUI 기초, AWT와 스윙(Swing)

기본적인거만. 디테일은 안드로이드에서 다시

GUI란 Graphical User interfaca의 약자로 이미지 혹은 그래픽을 이용하여 메뉴 등을 포함하는 화면을 구성하고, 키보드 외 마우스등의 편리한 입력도구를 이용하여 사용자가 입력하기 편하도록 만들어진 사용자 인터페이스이다.
자바는 AWT와 Swing 패키지 등 어떤 언어보다 강력한 GUI 라이브러리를 제공한다.

자바 언어는 GUI 응용프로그램을 쉽게 작성할 수 있도록 다양한 GUI 컴포넌트를 제공한다. 자바의 GUI 컴포넌트는 AWT 컴포넌트와 Swing 컴포넌트로 구분된다.

스윙(Swing) 컴포넌트의 이름은 AWT 컴포넌트와 구분하기 위해 모두 대문자 J로 시작한다.

AWT보다 스윙 사용을 권장한다. 최근에는 거의 모든 GUI응용플그램이 스윙기반으로 작성되고 있다.


GUI 패키지 계층 구조

모든 GUI 컴포넌트들은 Component 클래스를 반드시 상속받으며, JApplet, JFrame, JDialog를 제외한 모든 스윙 컴포넌트들은 JComponent를 상속받는다.

컨테이너

다른 GUI 컴포넌트를 포함할 수 있는 컴포넌트이다. 그러므로 컨테이너는 컴포넌트이면서 동시에 컨테이너다.

컴포넌트

다른 컴포넌트를 포함할 수 없다.

최상위 컨테이너

다른 컨테이너에 속하지 않고도 독립적으로 화면에 출력될 수 있는 컨테이너이다. JFrame, JDialog, JApplet이다. 그러나 이들을 제외한 나머지 컨테이너나 컴포넌트들은 다른 컨테이너에 부착되어야하고, 종국에는 최상위 컨테이너에 부착되어야만 화면에 출력된다.


스윙 패키지 사용을 위한 import문

import javax.swing.*;   //스윙 패키지 사용
import java.awt.*;   //폰트 등 그래픽 처리를 위한 클래스들의 경로명
import java.awt.event.*;   //이벤트 처리에 필요한 기본 클래스들의
import javax.swing.*;   //스윙 컴포넌트 클래스들의 경로명
import javax.swing.event.*;   //스윙 이베트 처리에 필요한 클래스들의 

스윙 프레임과 컨텐트팬

스윙 프레임은 최상위 컨테이너이다. JFrame. JFrame 객체는 Frame, 메뉴바, 컨텐츠팬의 3공가으로 구성된다.


스윙 응용프로그램에서 main() 메소드의 기능과 위치

스윙 응용프로그램에서 main()의 기능은 최소화하는것이 좋다. 응용프로그램이 실행되는 시작점으로서 프레임을 생성하는 코드정도만 만들기

예제 9-2)

import javax.swing.*;
import java.awt.*;

public class ContentPaneEx extends JFrame{
	public ContentPaneEx() { //생성자
		setTitle("contenPane과 JFream");  //프레임 타이틀 달기
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  //프레임 윈도우를 닫으면 프로그램을 종료하도록 설정
		
		Container contentPane = getContentPane();  //컨텐트 팬을 알아낸다.
		contentPane.setBackground(Color.BLUE);  //컨텐트팬의 색 블루
		contentPane.setLayout(new FlowLayout());  //컨텐트팬에 flowlayout 배치 관리자 
		
		contentPane.add(new JButton("OK"));
		contentPane.add(new JButton("Cancel"));
		contentPane.add(new JButton("Ignore"));
		
		setSize(300, 150);
		setVisible(true);
	}
	
	public static void main(String[] args) {
		new ContentPaneEx();
	}

}

스윙 프로그램의 종료

자바에서 프로그램을 종료하려면 System.exite(0);을 한다.
스윙 프레임의 윈도우 오른쪽 상단에 있는 x버튼은 프레임 윈도우를 닫는 버튼이지 프로그램을 종료시키는 버튼은 아니다.

main() 메소드가 종료한 뒤에도 프레임이 살아 있는 이유는 무엇인가?

자바 응용프로그램이 시작되면 자바 가상 기계는 main 스레드를 만들고 main()을 실행시킨다. 응용프로그램이 스레드를 만들지 않는 경우 main()이 종료하면 main스레드도 종료되며 더이상 살아있는 스레드가 없기 때문에 응용프로그램은 종료된다.
그러나 스윙에서 JFrame 객체가 생성되면 main 스레드 외에 입력되는 키와 마우스의 움직임을 컴포넌트에게 이벤트로 전달하는 이벤트 처리(분배) 스레드가 자동으로 추가 생성된다. 그러므로 main 스레드가 종료하더라도 이벤트 처리 스레드는 살아있기 때문에 자바 응용프로그램은 종료되지 않고 사용자로부터 키와 마우스 입력을 계속 처리하게 되는 것이다.


컨테이너와 배치

컨테이너에 부착되는 컴포넌트들의 위치와 크기는 컨테이너 내부에 있는 배치관리자에 의해 결정된다.

  • 컨테이너마다 배치관리자가 하나씩 있다.
  • 배치관리자는 컨테이너에 컴포넌트가 부착되는 시점에 컴포넌트의 위치와 크기를 결정한다.
배치관리자의 종류

import java.awt.*;문이 필요하다.

  • FloawLayout : 왼쪽에서 오른쪽으로 배치
  • BorderLayout : 동(EAST), 서(WEST), 남(SOUTH), 북(NORTH), 중앙(CENTER)의 5개 영역으로 나누어 배치한다. 5개의 영역 중 하나를 반드시 지정해야하며 지정하지 않으면 중앙에 배치한다.
  • GridLayout : 동일한 크기의 2차원 격자로 나누고 컴포넌트가 삽입되는 순서대로 좌에서 우로, 다시 위에서 아래로 배치
  • CardLayout : 컴포넌트를 포개어 배치한다.
디폴트 배치 관리자

Window, JWindow / Frame, JFrame / Dialog, JDailog 는 BorderLayout Pannel, JPannel / Applet, JApplet 은 FlowLayout


FlowLayout 배치 관리자

BorderLayout 배치 관리자
import javax.swing.*;
import java.awt.*;

public class BorderLayoutEx extends JFrame{
	public BorderLayoutEx() {
		setTitle("BorderLayout Sample");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		
		c.setLayout(new BorderLayout(30, 20));
		c.add(new JButton("Calculate"), BorderLayout.CENTER);
		c.add(new JButton("add"), BorderLayout.NORTH);
		c.add(new JButton("sub"), BorderLayout.SOUTH);
		c.add(new JButton("mul"), BorderLayout.EAST);
		c.add(new JButton("div"), BorderLayout.WEST);
		
		setSize(300, 200);
		setVisible(true);
	}
	public static void main(String[] args) {
		new BorderLayoutEx();
	}

}

배치관리자가 없는 컨테이너

  • 컴포넌트의 크기나 위치를 개발자가 결정하고자 하는 경우
  • 마우스/키보드의 입력에 따라 컴포넌트들의 위치와 크기가 수시로 변하는 경우
  • 여러 컴포넌트들이 겹치는 효과를 연출하고자 하는 경우
container.setLayout(null);

10. 자바의 이벤트 처리

이벤트 기반 프로그래밍

이벤트 기반 프로그래밍은 이벤트의 발생에 의해 프로그램 실행 흐름이 결정되는 방식의 프로그래밍 패러다임이다. 이벤트 기반 프로그래밍과 대조되는 개념은 프로그램 작성자에 의해 프로그램 흐름이 결정되는 방식이다. 이벤트 기반 응용프로그램은 각 이벤트를 처리하는 이벤트 리스너들을 보유하며, 이벤트가 발생할 때마다 리스너가 실행된다.
이벤트 리스너는 이벤트를 처리하는 프로그램 코드로서 컴포넌트에 연결되어 있어야 작동된다.

이벤트를 처리하는 과정에서 등장하는 이벤트 관련 용어
  • 이벤트 소스 : 이벤트를 발생시킨 GUI 컴포넌트
  • 이벤트 객체 : 발생한 이벤트에 대한 정보(이벤트 종류, 이벤트 소스, 화면 좌표, 눌러진 키)를 담는 객체로서, 이벤트에 따라 서로 다른 정보가 저장된다.
  • 이베트 리스너 : 이벤트를 처리하는 코드로서 컴포넌트에 등록되어야 작동 가능하다.
  • 이벤트 분배 스레드 : 이벤트 기반 프로그래밍의 핵심 요소로서 무한 루프를 실행하는 스레드이다. 자바 가상 기계로부터 이벤트의 발생을 통지받아, 이벤트 소스와 이벤트 종류를 결정하고 이에 따라 적절한 이벤트 객체를 생성하고 이벤트 리스너를 찾아 호출한다.

이벤트는 이벤트 분배 스레드에 의해 순서대로 처리된다. 그러므로 이벤트 리스너는 가능하면 짧게 작성해야 한다. 길어지게 되는경우 따로 스레드를 만들어 해결해야 한다.


이벤트 객체

이벤트 객체는 현재 발생한 이벤트에 관한 정보를 가진 객체이며, 이벤트 리스너에게 전달된다. 응용프로그램은 이벤트를 처리하기 위해 반드시 다음 import를 포함해야 한다.

import java.awt.event.*;  //이벤트 처리가 필요한 모든 소스에 포함
import javax.swing.event.*;  //스윙 이벤트를 다루는 경우 추가 포함

이벤트 객체는 메소드를 통해 이벤트 정보를 제공한다. MouseEvent 객체의 메소드 예는 getButton(), getCickCount(), getPoint(), getX(), getY() 등이 있다.


Object getSource()

모든 이베트가 객체에 있고, 이벤트 리스너에서 가장 많이 사용되는 메소드이다. 현재 발생한 이벤트의 소스 컴포넌트의 레퍼런스를 리턴한다.


리스너 인터페이스

이벤트 리스너란 이벤트를 처리하는 자바 프로그램 코드로서 클래스로 만든다. JDK는 이벤트 리스너 인터페이스(implements 사용)를 제공하며, 개발자는 이 인터페이스를 상속받고 추상 메소드를 모두 구현하여 이벤트 리스너를 작성한다.

interface ActionListener{
    public void actionPerformed(ActionEvent e);  //Action 이벤트 발생 처리
}

버튼을 누르는 Action 이벤트가 발생하면 actionPerformed(ActionEvent e) 메소드가 호출되고, 이때 ActionEvent 객체가 인자로 전달된다.
또한 MouseListener 인터페이스는 다음과 같이 5개의 메소드를 가지고있으며, 각 메소드는 마우스의 조작에 따라 발생하는 이벤트를 처리한다. 메소드에는 MouseEvent 객체가 인자로 전달된다.

interface MouseListener{
    public void mousePressed(MouseEvent e);  //마우스 버튼이 눌러지는 순간
    public void mouseReleased(MouseEvent e);  //눌러진 마우스 버튼이 떼어지는 순간
    public void mouseClicked(MouseEvent e);  //마우스가 클릭되는 순간
    public void mouseEntered(MouseEvent e);  //마우스가 컴포넌트 위에 올라가는 순간
    public void mouseExited(MouseEvent e);  //마우스가 컴포넌트 위에서 내려오는 순간
}

이벤트 리스너 작성방법

독립 클래스로 이벤트 리스너 작성(공통적으로 써야하는 이벤트의 경우에 사용)
public class IndepClassListener extends JFrame {
	public IndepClassListener() {
		setTitle("Action 이벤트 리스너 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.setLayout(new FlowLayout());
		JButton btn = new JButton("Action");
		btn.addActionListener(new MyActionListener());  //독립 클래스
		c.add(btn);		
		
		setSize(350,150);
		setVisible(true);
	}

	public static void main(String[] args) {
		new IndepClassListener();
	}

}

//01. 독립 클래스로 이벤트 리스너 작성
class MyActionListener implements ActionListener{
	public void actionPerformed(ActionEvent e) {
		JButton b = (JButton)e.getSource();  //이벤트 소스 버튼 알아내기. getsource는 이벤트가 발생된 객체. 리턴타입은 object. 지금은 jbutton으로 고정(object가 아닌). 어디서 발생했는지 알아내려면 getsource 사용. btn인지 text인지 모르니 object로 넘김.  //오브젝트에 넘겨줘서 바로 그냥 버튼으로 다운캐스팅
		if(b.getText().equals("Action")) {  //버튼의 문자열이 action인지 비교
			b.setText("액션");  //버튼의 문자열을 액션으로 변경set은 add가 아니라서 기존거를 바꿔라.
		}else {
			b.setText("Action");버튼의 문자열을 action으로 변경
		}
	}
}
내부 클래스로 이벤트 리스너 작성(한 화면?에서 쓸 때 유리)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class IndepClassListener extends JFrame {   //여기 IndepClassListener랑
	public IndepClassListener() {
		setTitle("Action 이벤트 리스너 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.setLayout(new FlowLayout());
		JButton btn = new JButton("Action");
		//02. 내부 클래스
		btn.addActionListener(new MyActionListener());
		c.add(btn);		
		
		setSize(350,150);
		setVisible(true);
	}
	
//	02. 내부 클래스. 이 클래스는 내부 클래스이므로 자신을 둘러싼 외부 클래스인 IndepClassListener나 상속받은 JFrame의 모든 멤버에 접근할 수 있다.
	class MyActionListener implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			JButton b = (JButton)e.getSource();
			if(b.getText().equals("Action")) {
				b.setText("액션");
			}else {
				b.setText("Action");
			}
			
      //IndepClassListener의 멤버나 JFrame의 멤버를 호출할 수 있음
			IndepClassListener.this.setTitle(b.getText());  //여기랑 동일해야함.  프레임의 타이틀에 버튼 문자열 출력. IndepClassListener.this에 유의하라
		}
	}

	public static void main(String[] args) {
		new IndepClassListener();
	}

}
익명 클래스로 이벤트 리스너 작성(재활용 불가능)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class IndepClassListener extends JFrame {
	public IndepClassListener() {
		setTitle("Action 이벤트 리스너 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.setLayout(new FlowLayout());
		JButton btn = new JButton("Action");
		c.add(btn);
		
		//03. 익명클래스
		btn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				JButton b = (JButton)e.getSource();
				if(b.getText().equals("Action")) {
					b.setText("액션");
				}else {
					b.setText("Action");
				}
				
        //IndepClassListener의 멤버나 JFrame의 멤버를 호출할 수 있음
				setTitle(b.getText());
			}
		});
		
		setSize(350,150);
		setVisible(true);
	}	

	public static void main(String[] args) {
		new IndepClassListener();
	}

}

예제 10-4) 마우스로 문자열 이동시키기 - 마우스 이벤트 연습

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MouseListenerEx extends JFrame {
	private JLabel la = new JLabel("Hello"); //Hello 출력하기 위한 레이블
	
	public MouseListenerEx() {
		setTitle("Mouse 이벤트 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.addMouseListener(new MyMouseListener());  //컨텐트팬에 이벤트 리스너 달기
		
		c.setLayout(null);  //컨텐트팬의 배치관리자 삭제
		la.setSize(50, 20);  //레이블의 크기 설정
		la.setLocation(30, 30);  //레이블의 위치 설정
		c.add(la);  //레이블 컴포넌트 삽입
		
		setSize(250, 250);
		setVisible(true);
	}
	
  //Mouse 리스너 구현
	class MyMouseListener implements MouseListener{  //클래스안에 클래스
		public void mousePressed(MouseEvent e) {  //누르기. 마우스 버튼이 눌려진 위치(x, y)를 알아내어 hello 레이블의 위치를 (x, y)로 
			int x = e.getX();
			int y = e.getY();
			la.setLocation(x, y);
		}
		public void mouseReleased(MouseEvent e) {}
		public void mouseClicked(MouseEvent e) {}
		public void mouseEntered(MouseEvent e) {}
		public void mouseExited(MouseEvent e) {}
	}
	
	public static void main(String[] args) {		
		new MouseListenerEx();
	}

}


어댑터 클래스

리스너 인터페이스를 상속받아 이벤트 리스너를 구현할 때 리스너 인터페이스의 메소드를 모두 구현해야하는 부담이 있다. 이런 부담을 줄이기 위해 리스너 인터페이스를 미리 구현해 놓은 클래스가 어댑터 클래스다. (어댑터클래스는 이미 인터페이스 상속 받아서 재정의해 놓은것, 인터페이스는 추상메소드? 다 재정의 해줘야함. 상속은 다 안써도 됨)


Key 이벤트와 포커스

포커스란 키 입력의 독점권을 뜻한다.

어떤 컴포넌트에ㅔ 키를 입력하고자 하면 탭키나 마우스 클릭으로 포커스를 그 컴포넌트에게 이동시켜야 한다. 스윙 프로그램에서는 강제로 임의의 컴포넌트에 포커스를 주기 위해 다음 두 코드가 필요하다. (두개 같이 쓰는것을 권장! 원래 아래거 하나있어도 된다)

component.setFocusable(true);  //component가 포커스를 받을 수 있도록 설정한다.
component.requestFocus();  //component가 포커스를 주어 키 입력을 받을 수 있게 함

Key 이벤트와 KeyListener

keyPressed()는 키를 누르는 순간에, keyReleased()는 누른 키를 떼는 순간에 호출되며, 문자 키(유니코드)인 경우에는 누른 키가 떼어지는 순간에 keyTyped()가 추가적으로 호출된다. (home, function, up 키 등은 유니코드 값을 정의하지 않는다. 눌러도 실행 안됨. 뭐 상수값만 알면 된다?)


입력된 키 판별

char KeyEvent.getKeyChar()

입력된 키의 문자코드(유니코드 값)를 리턴한다.

int KeyEvent.getKeyCode();

유니코드 키를 포함한 모든 키에 대해 정수형 키 코드 값을 리턴한다. 키코드는 운영체제나 하드웨어에 따라 다를 수 있기 때문에 입력된 키를 판별하기 위해서는 반드시 getKeyCode()가 리턴한 키 코드와 가상키 값을 비교해야 한다. 가상키는 keyEvent 클래스에 VK_로 시작하는 static 상수로 선언되어 있다

예제 10-6)

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class KeyListenerEx extends JFrame {
	private JLabel[] keyMessage;  //3개의 메시지를 출력할 레이블 컴포넌트 배열
	
	public KeyListenerEx() {
		setTitle("KeyListener 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		Container c = getContentPane();
		c.setLayout(new FlowLayout());
		c.addKeyListener(new MyKeyListener());
		
    //레이블 배열을 3개 생성하고 각 레이블 컴포넌트 생성
		keyMessage = new JLabel[3];  //레이블 배열 생성
		keyMessage[0] = new JLabel("getKeyCode()");
		keyMessage[1] = new JLabel("getKeyCode()");
		keyMessage[2] = new JLabel("getKeyText()");
		
    //3개의 레이블 컴포넌트를 컨텐츠팬에 부착
		for(int i = 0; i <keyMessage.length; i++) {
			c.add(keyMessage[i]);
			keyMessage[i].setOpaque(true);  //스윙 컴포넌트의 배경색을 설정하기 위해 미리 setOpaque(true) 호출 배경색이 보이도록 불투명 속성 설정
			keyMessage[i].setBackground(Color.YELLOW);
		}
		
		setSize(300, 150);
		setVisible(true);
		
    //컨텐트팬이 키 입력을 받을 수 있도록 포커스 강제 지정
		c.setFocusable(true);
		c.requestFocus();
	}
	
	class MyKeyListener extends KeyAdapter{
		public void keyPressed(KeyEvent e) {
			int keyCode = e.getKeyCode();  //키 코드 알아내기
			char keyChar = e.getKeyChar();  // 키 문자 값 알아내기
			keyMessage[0].setText(Integer.toString(keyCode));  //키 코드 출력
			keyMessage[1].setText(Character.toString(keyChar));  //키 문자 출력
			keyMessage[2].setText(KeyEvent.getKeyText(keyCode));  //키 이름 문자 열 출력. 키 코드 값으로부터 키 이름 문자열을 알아내어 레이블에 출력
			
			System.out.println("KeyPressed");  //콘솔창에 메소드 이름 출력
		}
		public void keyReleased(KeyEvent e) {
			System.out.println("KeyReleased");
		}
		public void keyTyped(KeyEvent e) {
			System.out.println("KeyTyped");
		}
	}
	public static void main(String[] args) {
		new KeyListenerEx();
	}

}

Mouse 이벤트

예제 10-9)

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class MouseListenerAllEx extends JFrame{
	private JLabel la =new JLabel("No Mouse Event");  //메시지 출력 레이블 컴포넌트
	public MouseListenerAllEx() {
		setTitle("MouseListener와 MouseMotionListener 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		Container c =getContentPane();
		c.setLayout(new FlowLayout());
		
		MyMouseListener listener = new MyMouseListener();  //리스너 객체 생성
		c.addMouseListener(listener);  //MouseListener 리스너 등록
		c.addMouseMotionListener(listener);  //MouseMotionListener 리스너 등록
		
		c.add(la);
		setSize(300, 200);
		setVisible(true);
	}
	
  //Mouse 리스너와 MouseMotion 리스너를 모두 가진 리스너 작성  
	class MyMouseListener implements MouseListener, MouseMotionListener{
		//MouseListener의 5개 구현
		public void mousePressed(MouseEvent e) {
			la.setText("mousePressed( " + e.getX() + ", " + e.getY() + ")");			
		}
		public void mouseReleased(MouseEvent e) {
			la.setText("MouseReleased(" + e.getX() + ", " + e.getY() + ")");
		}
		public void mouseClicked(MouseEvent e) {}
		public void mouseEntered(MouseEvent e) {
			Component c = (Component)e.getSource();  //마우스가 올라간 컴포넌트를 알아낸다
			c.setBackground(Color.CYAN);
		}
		public void mouseExited(MouseEvent e) {
			Component c = (Component)e.getSource();  //마우스가 내려간 컴포넌트를 알아낸다
			c.setBackground(Color.YELLOW);
		}
		
		//MouseMotionListener의 2개 메소드 구현
		public void mouseDragged(MouseEvent e) {  //마우스가 드래깅되는 동안 계속 호출
			la.setText("MouseDragged (" + e.getX() + ", " + e.getY() + ")");
		}
		public void mouseMoved(MouseEvent e) {  //마우스가 움직이는 동안 계속 
			la.setText("MouseMoved (" + e.getX() + "," + e.getY() + ")");
		}
	}
	public static void main(String[] args) {
		new MouseListenerAllEx();

	}

}

11. 기본적인 스윙 컴포넌트와 활용, 12. 그래픽은 앞에서 배운걸로 사용 가능하니 읽어보기?? skip~


13. 스레드와 멀티태스킹

멀티태스킹은 응용프로그램의 여러 작업(태스크)이 동시에 진행되게 하는 기법으로, 응용프로그램의 목적을 효율적으로 달성하게 한다.

스레드는 멀티태스크 응용프로그램을 작성한다. 프로그램 코드를 실행하는 하나의 실 혹은 제어의 개념이다. 하나의 스레드로 하나의 작업밖에 처리할 수 없다. 스레드 a와 스레드 b는 한 객체의 메소드에서 다른 메소드로의 호출에 따라 이동하면서 코드를 실행하고 있다. 2개의 스레드는 상호독립적이다. 그러므로 이 응용프로그램은 2가지 작업을 동시에 하고 있는 셈이다(거의 동시에 진행, 완전동시x). ex) 테트리스 게임에서 1. 오디오 재생코드를 움직이는 스레드?, 2. 블록을 아래로 움직이는 코드를 하는 스레드, 3. 키 입력을 받아 블록의 방향을 바꾸는 코드의 스레드


멀티스레딩

멀티태스킹의 문제점(독립적으로 실행되어 변수공유 불가능, 오버헤드가 크다, 문맥교환에 따른 과도한 작업량과 시간소모)을 개선.
멀티스레딩은 하나의 응용프로그램을 동시처리가 가능한 여러 작업(코드)로 분할하고 작업의 개수만큼 스레드를 생성하여 각 스레드로 하여금 하나의 작업을 처리하도록 하는 기법이다.

멀티스레딩은 응용프로그램이 다수의 스레드를 가지고 다수의 작업을 동시에 처리함으로써, 한 스레드가 대기하는 동안 다른 스레드를 실행하여 시간 지연을 줄이고 자원의 비효율적 사용을 개선한다. EX) 네이버 여러 유저가 접속, 프린터와 다른 작업 동시


멀티스레드와 자바 가상 기계(JVM)

자바에는 프로세스가 존재하지 않고 스레드 개념만 존재하며, JVM은 멀티 스레딩만 지원한다. 자바 스레드JVM에 의해 스케줄되는 실행 단위 코드 블록이다.
하나의 JVM은 하나의 자바 응용프로그램만 실행한다. 사용자가 자바 응용프로그램을 실행시키면, JVM이 먼저 실행되고 JVM이 자바 응용프로그램을 로딩하여 실행시킨다. 자바 응용프로그램이 종료되면 JVM도 함께 종료된다. 만일 한 컴퓨터에서 n개의 자바 응용프로그램이 실행된다고 하면 n개의 JVM이 실행되고 있는 것이다.

-> JVM은 한개의 응용 프로그램만 실행 가능, 하나의 응용프로그램이 여러 개의 스레드를 가질 수 있음

2개 이상의 자바 응용프로그램을 실행하고자 하는 경우 각각 JVM에 의해 실행되며, 서로 정보를 주고받고자 하는 경우 소켓통신과 같은 통신 방법을 이용한다. (그림 참조하려면 p.690)


자바스레드와 JVM

개발자의 임무는 자바 스레드로 작동할 스레드 코드를 작성하고, 스레드 코드가 생명을 가지고 실행을 시작하도록 JVM에게 요청하는 일뿐이다.


스레드 만들기

개발자는 두가지 작업을 해야 한다.

  1. 스레드 코드 작성
  2. JVM에게 스레드를 생성하고 스레드 코드를 실행하도록 요청

스레드 코드를 작성하는 방법

  1. Thread 클래스 이용
  2. Runnable 인터페이스 이용

스레드 클래스 작성 : Thread 클래스 상속
class TimerThread extends Thread{
    ...
}
스레드 코드 작성 : ru()메소드 오버라이딩

run() 메소드에 작성된 코드를 스레드 코드라고 한다. 스레드는 run()에서부터 실행을 시작하고 run()이 종료하면 스레드도 종료된다.
만일 run()을 오버라이딩 하지 않으면 Thread(부모)에 작성된 run이 실행되며, 이 run()은 아무 일도 하지 않고 단순 리턴하도록 작성되어있어 스레드가 바로 종료된다.

class TimerThread extends Thread{
    @Override
    public void run(){
        ...
    }
}
스레드 객체 생성

스레드 객체 생성만으로 스레드가 작동하는것은 아니다.

TimerThread th = new TimerThread();
스레드 시작 : start() 메소드 호출

start()해야 스레드 작동된다.(병렬처리)

th.start();

예제 13-1) 1초 단위로 출력하는 타이머 스레드 만들기

import java.awt.*;
import javax.swing.*;

class TimerThread extends Thread {
	private JLabel timerLabel;  //타이머 값이 출력되는 레이블
	
	public TimerThread(JLabel timerLabel) {
		this.timerLabel = timerLabel;  //타이머 카운트를 출력할 레이블
	}
	
  //스레드 코드. run()이 종료하면 스레드 종료
	@Override  //재정의
	public void run() {  //run()은 스레드 코드로서 start() 메소드가 호출된 후 스레드가 실행을 시작하는 메소드이다.  //try-catch 블록이 없으면 컴파일 오류가 발생한다. sleep()에 의해 잠을 자는 경우 예외 발생에 대비하기 위해서이다.
		int n=0;  //타이머 카운트 값
		while(true){  //무한 루프
			timerLabel.setText(Integer.toString(n));  //레이블에 카운트 값 출력
			n++;  //카운트 증가
			try {
				Thread.sleep(1000);  //1초 동안 잠을 잔다.
			}catch(InterruptedException e) {
				return;  //예외가 발생하면 스레드 종료
			}
		}
	}
}

public class ThreadTimerEx extends JFrame{
	public ThreadTimerEx() {
		setTitle("Thread를 상속받은 타이머 스레드 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.setLayout(new FlowLayout());
		
    //타이머 값을 출력할 레이블 생성
		JLabel timerLabel = new JLabel();
		timerLabel.setFont(new Font("Gothic", Font.ITALIC, 80));
		c.add(timerLabel);  //레이블을 컨텐츠팬에 부착
		
    //타이머 스레드 객체 생성. 타이머 값을 출력할 레이블을 생성자에 전달
		TimerThread th = new TimerThread(timerLabel);  //스레드 객체를 만든다
		
		setSize(300, 170);
		setVisible(true);
		
		th.start();  //타이머 스레드의 실행을 시작하게 한다. 스레드를 동작시킨다. 이 호출의 결과 TimerThread의 run() 메소드가 실행을 시작한다.
	}
	
	public static void main(String[] args) {		
		new ThreadTimerEx();
	}
}

Runnable 인터페이스로 스레드 만들기

추상메소드 run() 하나만 가지고 있다. 차이점은 예제 보기. 별거 없음


p.702 예제~~~~~~~~~~~~~~~~~~~~~~~


스레드 상태

스레드는 JVM에 있어 생명체와 같다. 생명주기를 가진다.
threadA = new Thread() -> NEW(탄생) 이전까지, TIMED_WATING(시간대기) 까지가 우리가 할 수 있는 정도. 나머지는 JVM이

  • NEW : 스레드가 생성되었지만 아직 실행할 준비가 되지 않은 상태이다. start() 메소드가 호출되면 RUNNABLE 상태가 된다.
  • RUNNABLE : 스레드가 현재 실행되고 있거나, 실행 준비되어 스케줄링을 기다리는 상태이다.
  • TIME_WATING : 스레드가 sleep(long n)을 호출하여 n미리초 동안 잠을 자는 상태이다.
  • BLOCK : 스레드가 I/O 작업을 실행하여 I/O 작업의 완료를 기다리면서 멈춘(blocked) 상태이다. 스레드가 I/O 작업을 실행하면 JVM이 자동으로 현재 스레드를 BLOCK 상태로 만들고 다른 스레드를 스케줄링한다.
  • WATING : 스레드가 어떤 객체 a에 대해 a.watie()를 호출하여, 다른 스레드가 a.notify(). a.notifyAll()을 불러줄 때까지 무한정 기다리는 상태이다.
  • TERMINATED : 스레드가 종료한 상태이다. 더이상 다른 상태로 변이할 수 없다.

스레드의 일생

p.705 그림…


스레드 우선순위와 스케줄링

JVM은 철저히 우선순위(priority)를 기반으로 스레드를 스케줄링한다. (값이 클수록 우선순위 높다.)

자바 프로그램이 실행될 떄 처음으로 생성되는 main스레드는 보통 값 5의 우선순위로 태어난다.
main 스레드의 모든 자식 스레드는 보통 값(5)의 우선순위를 가지고 태어난다.

다음은 우선순위 값 변경 메소드

void setPriority(int newPriority)  //newPriority로 스레드의 우선순위 값 변경
      getPriority                                         //우선순위 확인                  

main() 을 실행하는 main 스레드

(main 스레드 실행하기 위해 기본적으로) 아래 문제에서.. 스레드 여러개 가능. 5개 있을 시 첫번째 currentThread값 가져옴

long id = Thread.currentThread().getId(); //Thread.currentThread()는 현재 작동중인 스레드!!!!!!!!!!!!!!!!!!!!!!11. 스레드 id 얻기.
String name = Thread.currentThread().getName(); //스레드 이름 얻기
int priority = Thread.currentThread().getPriority();  //스레드 우선순위 값 얻기
Thread.state s = Thread.currentThread().getState(); //스레드 상태 값 얻기

System.out.println("현재 스레드 이름 = " + name );
System.out.println("현재 스레드 ID = " + id );
System.out.println("현재 스레드 우선순위 값 = " + priority );
System.out.println("현재 스레드 상태 = " + s );

//출력
//현재 스레드 이름 = main
//현재 스레드 ID = 1
//현재 스레드 우선순위 값 = 5
//현재 스레드 상태 = RUNNABLE

스레드 종료

run() 메소드가 실행 도중 return하거나 run()을 완전히 실행하고 리턴하면 종료된다.


강제종료

스레드 A가 스레드 B를 강제 종료시킥자 하는 경우 스레드 B의 interrupt()를 호출해야 한다.
타 스레드에서 interrupt하여 강제종료 하고, run의 catch문에서 InterrupteException return 한다.


flag를 이용한 종료

인터럽트랑 비슷. flag는 여기저기 많이 사용됨. flag = 상태의 변화를 담는 변수. 마우스 누를때, 뗄 때 등…


스레드 동기화의 필요성

스레드 동기화 -> 한줄 세워서 문제 해결

  • 공유프린터에 동시 접근하는 경우 : 공유 프린터에 대한 멀티스레드의 동시 접근순차화하여 섞여 출력되는 문제를 해결했다.
  • 공유 집계판에 동시 접근 하는 경우 : 방이라는 임계영역을 만들고 기다리게한다(교착상태). 문을 동기화 가정으로 정의했다.

멀티스레드 프로그램을 작성할 때 주의할 점은 다수의 스레드가 공유 데이터에 동시 접근하는 경우에 대한 처리이다. 이에 대한 해결책이 바로 스레드 동기화이다.(스레드 동기화 -> 한줄 세워서 문제 해결)
스레드 동기화란 공유 데이터를 배타적으로 접근하기 위해 상호협력하는 것을 말한다. 공유데이터에 대한 접근은 배타적이고 독점적으로 이루어져야한다.
자바에서 스레드 동기화에는 다음 2가지 방법을 사용한다.

  • synchronized로 동기화 블록 지정
  • wate()-notity()메소드로 스레드 실행 순서 제어

자바 스레드 동기화를 위한 synchronized 키워드

일정 영역을 잡아서 synchronized에 가둠
메소드 전체를 임계영역으로 지정할 수 있고, 코드 블록을 임계영역으로 지정할 수도 있다.

package chapter13;

public class SynchronizedEx {

	public static void main(String[] args) {
		SharedBoard board = new SharedBoard();  //집계판 공유 데이터 생성
		
		//두 스레드가 집계판에 동시 접근
		Thread th1 = new StudentThread("kitae", board);
		Thread th2 = new StudentThread("hyosoo", board);
		
		th1.start();
		th2.start();
	}
}

//두 스레드에 의해 동시 접근됨
class SharedBoard{
	private int sum = 0;
	synchronized public void add() {
		int n = sum;
		Thread.yield();  //현재 실행중인 스레드 양보. 테스트용. 여기선 synchronized있으니 안써도 됨
		n += 10;
		sum = n;
		System.out.println(Thread.currentThread().getName() + " : " + sum);
	}
	public int getSum() {
		return sum;
	}
}

class StudentThread extends Thread{
	private SharedBoard board;  //집계판의 주소
	public StudentThread(String name, SharedBoard board) {
		super(name);
		this.board = board;
	}
	
	@Override
	public void run() {
		for(int i=0; i<10; i++) {
			board.add();
		}
	}
}

wait()-notify()를 이용한 스레드 동기화가 필요한 경우

  • wait() : 다른 스레드가 이 객체의 notify()를 불러줄 때까지 대기한다.
  • notify() : 이 객체에 대기 중인 스레드를 깨워 RUNNABLE 상태로 만든다. 2개 이상의 스레드가 대기 중이라도 오직 한 개의 스레드만 깨워 RUNNABLE 상태로 한다.
  • notifyAll() : 이 객체에 대기 중인 모든 스레드를 깨우고 모두 RUNNABLE 상태로 한다.
package chapter13;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

class MyLabel extends JLabel{
	private int barSize = 0;  //현재 그려져야 할 바의 크기
	private int maxBarSize;  //바의 최대 크기
	
	public MyLabel(int maxBarSize) {
		this.maxBarSize = maxBarSize;
	}
	
	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.setColor(Color.MAGENTA);
		int width = (int) (((double)(this.getWidth()))/maxBarSize*barSize);
		if(width==0) {
			return;  //크기가 0이기때문에 바를 그릴 필요 없음
		}
		g.fillRect(0, 0, width, this.getHeight());
	}
	
	synchronized public void fill() {
		if(barSize == maxBarSize) {
			try {
				wait();  //바가 최대이면, ComsumerThread에 의해 바가 줄어들 때까지 대기
			}catch(InterruptedException e) {
				return;
			}
		}
		barSize++;
		repaint();
		notify();//기다리는 ComsumerThread 스레드 깨우기
	}
	synchronized public void consume() {
		if(barSize == 0) {
			try {
				wait();
			}catch(InterruptedException e) {
				return;
			}
		}
		barSize--;
		repaint();
		notify();  //기다리는 이벤트 스레드 깨우기
	}
}

class ConsumerThread extends Thread{
	private MyLabel bar;
	public ConsumerThread(MyLabel bar) {
		this.bar = bar;
	}
	@Override
	public void run() {
		while(true) {
			try {
				sleep(200);
				bar.consume();  //0.2초마다 바를 1씩 줄인다.
			}catch(InterruptedException e) {
				return;
			}
		}
	}
}
public class TabAndThreadEx extends JFrame {
	private MyLabel bar = new MyLabel(100);  //바의 최대 크기를 100으로 설정
	
	public TabAndThreadEx(String title) {
		super(title);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.setLayout(null);
		bar.setBackground(Color.ORANGE);
		bar.setOpaque(true);
		bar.setLocation(20, 50);
		bar.setSize(300, 20);
		c.add(bar);
		
		//컨텐트팬에 키 이벤트 핸들러 등록
		c.addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				bar.fill();  //키를 누를 때마다 바가 1씩 증가한다.
			}
		});
		setSize(350,200);
		setVisible(true);
		
		c.setFocusable(true);
		c.requestFocus();  //컨텐트팬에게 키 처리권 부여
		ConsumerThread th = new ConsumerThread(bar);
		th.start();
	}
	
	public static void main(String[] args) {
		new TabAndThreadEx("아무키나 빨리 눌러 바 채우기");

	}

}

14장 고급 스윙 컴포넌트

skip~~~~~~~~~~~~~


15. 네트워크

TCP/IP 프로토콜 소개

TCP 프로토콜은 다른 두 시스템 간에 신뢰성 있는 데이터의 전송을 관장하는 통신 프로토콜로서 IP 프로토콜 위에서 동작한다. TCP 프로토콜을 사용하는 응용프로그램으로는 e-mail, FTP, 웹(HTTP) 등이 있다.
IP는 패킷 교환 네트워크에서 송신 호스트와 수신 호스트가 데이터를 주고받는 것을 관장하는 프로토콜로서 TCP의 하위 레벨 프로토콜이다.

(TCP는 데이터 전송 목적, IP는 누가 누군지 분류하는게 목적)


IP 주소

IP 주소는 네트워크상에서 유일하게 식별될 수 있는 네트워크 장치의 주소로서, 예를들면 192.156.11.15와 같이 4개의 숫자가 .으로 연결된다. 하나의 숫자 범위는 0~255로서 한 바이트로 표현이 가능하다. 도메인 이름으로 바꿔 사용할 수도 있다. 128비트의 IPv6 버전을 사용하는 추세이다. (ex 집주소, 192.168.~~~랑 ~10.~는 사설 ip!)


포트

IP주소는 네트워크상에 있는 한 컴퓨터를 유일하게 식별한다. 하지만 한 컴퓨터에는 여러 응용프로그램이 네트워크를 사용하고 있기 때문에 IP주소만으로는 통신하고자 하는 응용프로그램을 식별할 수 없다. 이를 위해 한 컴퓨터 내의 각 응용프로그램은 통신을 위해 가상의 연결단인 포트(port)를 생성하고, 이 포트번호로 상대방이 자신을 식별하게 한다.


예를 들면 IP주소는 은행 지점의 주소이고, 포트번호는 은행 내의 고객 창구 번호와 같다.


따라서 통신을 수행하는 모든 응용프로그램은 IP주소와 포트를 이용하여 상대편 통신 프로그램을 인지하며 데이터를 교환한다. 물론 이 때 상대편 응용프로그램은 자신의 IP 주소와 포트 번호를 알고 통신 접속이나 데이터가 오기를 기다리고 있어야 한다.


포트 번호는 개발자가 이의로 선택하여 사용할 수 있으나, 기존 응용프로그램에서 사용하는 포트 번호는 피하는 것이 좋다. 시스템이나 기존에 알려진 응용프로그램에서 사용하는 포트 번호를 잘 알려진 포트라고 한다. 예를 들어 SSH는 22번 포트, HTTP는 80번 포트, FTP는 21번 포트 등이며, 이들은 주로 0~1023 사이의 번호를 가지므로 사용자가 작성하는 응용프로그램에서는 이 범위의 포트번호는 피해서 선택하도록 한다. (한 포트 번호를 두 개 이상의 프로그램에서 쓸 수 없다)


소켓

소켓 통신은 개발자가 TCP/IP 네트워크를 이용하여 쉽게 통신 프로그램을 작성하도록 지원하는 기반 기술이다. 여기서 소켓은 통신하는 두 응용프로그램 간의 통신 링크의 각 끝단으로서, TCP/IP의 네트워크 기능을 활용하여 다른 컴퓨터의 소켓과 데이터를 주고 받는다. 소켓은 특정 포트에 연결되어 데이터를 보내거나 받을 때 해당 응용 프로그램을 식별한다.
(TCP/IP와 포트를 가지고 통신하는게 소켓. 각 통신의 제일 끝 단계가 소켓이다.)


응용프로그램은 소켓과 연결한 후 소켓에 데이터를 주기만 하면, 소켓이 상대방 응용프로그램에 연결된 소켓에 데이터를 보낸다. 또는 응용프로그램은 연결된 소켓으로부터 도착한 데이터를 단순히 받기만 하면 된다. 인터넷을 경유하여 데이터를 주고받는 기능은 순전히 소켓의 몫이다.


소켓과 서버 클라이언트 통신

소켓을 이용하는 통신에서는 반드시 서버 응용프로그램과 클라이언트 응용프로그램으로 구분된다. 정보를 제공하는쪽을 서버라고 부르며, 정보를 이용하는 쪽을 클라이언트라고 부른다.

서버 소켓과 클라이언트 소켓

소켓에는 서버 소켓과 클라이언트 소켓의 2가지 종류가 있다.

  • 서버 소켓은 서버 응용프로그램이 사용자의 접속을 기다리는 목적으로만 사용된다.
  • 클라이언트 응용프로그램에서는 클라이언트 소켓을 이용하여 서버에 접속한다.
  • 서버 소켓은 클라이언트가 접속해오면, 클라이언트 소켓을 추가로 만들어 상대 클라이언트와 통신하게 한다.

이 내용을 정리하면 서버소켓클라이언트의 접속을 기다리는 소켓이며, 클라이언트 소켓데이터 통신을 실시하는 소켓이다.

(소켓은 사용 후에 닫아줘야한다!!!!!!!!!!!!!!!!!!! close())


Soket 클래스, 클라이언트 소켓

클라이언트 소켓 생성 및 서버 접속
Socket clientSoket = new Soket("128.12.1.1", 5550);  //IP주소가 128.12.1.1이고 포트번호가 5550인 서버에 접속. 이때 클라이언트의 포트는 사용되지 않는 포트 중에서 자동으로 선택된다.
네트워크 입출력 스트림 생성
BufferedReader in = new BufferedReader(new InputStreamReader(clientSoket.getIputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamReader(clientSoket.getOutputStream()));
서버로 데이터 전송
out.write("hello" + "\n");
out.flush();
서버로부터 데이터 수신
int x = in.read();  //클라이언트로부터 한 개의 문자 수신
String line = in.readLine();  //클라이언트로부터 한 행의 문자 수신
데이터 송수신 종료
socket.close();

ServerSoket 클래스, 서버 소켓 (접속을 받아들이는 용도)

서버 소켓 생성
ServerSocket listener = new ServerSocket(5550);  //자신의 포트 번호
클라이언트로부터 접속 대기
Socket socket = listener.accept(); //연결 요청을 기다림. accept() 메소드가 연결을 수락하면 다음과 같이 Socket 객체를 하나 별도로 생성하여 리턴한다.
네트워크 입출력 스트림 생성
BufferedReader in = new BufferedReader(new InputStreamReader(clientSoket.getIputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamReader(clientSoket.getOutputStream()));
클라이언트로부터 데이터 수신
int x = in.read();  //클라이언트로부터 한 개의 문자 수신
String line = in.readLine();  //클라이언트로부터 한 행의 문자 수신
클라이언트로 데이터 전송
out.write("hello" + "\n");
out.flush();
데이터 송수신 종료
socket.close();
서버 응용프로그램 종료
ServerSocket.close();

서버-클라이언트 채팅 프로그램 만들기

서버 프로그램

package chapter15;

import java.io.*;
import java.net.*;
import java.util.*;

public class ServerEx {

	public static void main(String[] args) {
		BufferedReader in = null;
		BufferedWriter out = null;
		ServerSocket listener = null;
		Socket socket = null;
		Scanner scanner = new Scanner(System.in);
		try {
			listener = new ServerSocket(9999);  //서버 소켓 생성
			System.out.println("연결을 기다리고 있습니다...");
			socket = listener.accept();  //클라이언트로부터 연결 요청 대기
			System.out.println("연결되었습니다.");
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));  //소켓 입력 스트림
			out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));  //소켓 출력 스트림
			while(true) {
				String inputMessage = in.readLine();  //클라이언트로부터 한 행 읽기
				if(inputMessage.equalsIgnoreCase("bye")) {
					System.out.println("클라이언트에서 bye로 연결을 종료했음");
					break;
				}
				System.out.println("클라이언트 : " + inputMessage);
				System.out.print("보내기 >> ");  
				String outputMessage = scanner.nextLine();  //키보드에서 한 행 읽기
				out.write(outputMessage + "\n");  //키보드에서 읽은 문자열 전송
				out.flush();  //out의 스트림 버퍼에 있는 모든 문자열 전송
			}		
		}catch(IOException e) {
			System.out.println(e.getMessage());
		}finally{
			try {
				scanner.close();
				socket.close();
				listener.close();
			}catch(IOException e) {
				System.out.println("클라이언트와 채팅 중 오류 발생");
			}
		}
	}
}

클라이언트 프로그램

package chapter15;

import java.io.*;
import java.net.*;
import java.util.*;

public class ClientEx {

	public static void main(String[] args) {
		BufferedReader in = null;
		BufferedWriter out = null;
		Socket socket = null;
		Scanner scanner = new Scanner(System.in);
		try {
			socket = new Socket("localhost", 9999);
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			while(true) {
				System.out.print("보내기 >> ");
				String outputMessage = scanner.nextLine();
				if(outputMessage.equalsIgnoreCase("bye")) {
					out.write(outputMessage + "\n");
					out.flush();
					break;
				}
				out.write(outputMessage + "\n");
				out.flush();
				String inputMessage = in.readLine();
				System.out.println("서버 : " + inputMessage);
			}		
		}catch(IOException e) {
			System.out.println(e.getMessage());
		}finally{
			try {
				scanner.close();
				if(socket != null) {
					socket.close();
				}
			}catch(IOException e) {
				System.out.println("서버와 채팅 중 오류 발생");
			}
		}
	}
}

16. JDBC 프로그래밍

데이터베이스란?

데이터베이스는 여러 응용 시스템들의 통합된 정보들을 저장하여 운영할 수 있는 공용 데이터들의 집합이다. 데이터베이스는 대규모의 데이터를 효율적으로 저장, 검색, 갱신할 수 있도록 데이터를 고도로 조직화하여 저장한다.


DBMS

데이터베이스를 관리하는 소프트웨어 시스템을 DBMS라고 한다. DBMS는 다수의 사용자들이 동시에 데이터베이스를 사용할 수 있도록 관리한다. 대표적인 DBMS는 오라클, SQL Server, MySQL 등이 있다.


데이터베이스의 종류

관계형 데이터베이스

관계형 데이터베이스는 데이터들이 다수의 테이블로 구성된다.
테이블의 각 행은 하나의 레코드이며, 각 테이블은 키와 값들의 관계로 표현된다. 키는 테이블의 열 이름이며, 키 중에서 특정 레코드를 검색하거나 레코드들을 정렬할 때 우선적으로 참조되는 키를 일차키(프라이머리 키)라고 한다. 여러 테이블 간에는 공통된 이름의 열을 포함할 수 있음 이런 경우 서로 다른 테이블 간에 관계가 성립된다.(이를 외래키)

객체 지향 데이터베이스

객체 지향 데이터베이스는 객체 지향 프로그래밍에 쓰이는 것으로, 정보를 객체의 형태로 표현하는 데이터베이스이며 오브젝트 데이터베이스라고도 부른다. 장점은 객체 모델이 그대로 데이터베이스에도 적용되므로 응용프로그램의 객체 모델과 데이터베이스의 모델이 부합하는데 있다. 그러나 현재 관계형 데이터베이스로 된 DBMS와 그에 따른 응용프로그램들이 주류를 이루고 있어 객체 지향 데이터베이스는 틈새시장을 차지하고 있다.


SQL

SQL은 관계형 데이터베이스 관리시스템에서 데이터베이스 스키마 생성, 자료의 검색, 관리, 수정, 그리고 데이터베이스 객체 접근 관리 등을 위해 고안된 언어이다.


JDBC

JDBC는 관계형 데이터베이스에 저장된 데이터를 접근 및 조작할 수 있게 하는 자바 API이다. JDBC는 자바 응용프로그램이 다양한 DBMS에 대해 일관된 API로 데이터베이스 연결, 검색, 수정, 관리 등을 할 수 있게 한다. 그러므로 자바 응용프로그램 개발자는 DMBS의 종류에 관계 없이 JDBC API 만을 이용하면 된다.


MySQL WorkBench를 이용한 데이터베이스 활용

p.846 오라클에서 해봤던거..

insert into student(name, dept, id) values ('김철수', '컴퓨터시스템', '1091011'); //레코드 추가
select name, dept, id 
from student 
where dept='컴퓨터공학'; //데이터 검색
update student set dept='컴퓨터공학'
where name='최고봉' //데이터 수정
delete from student where name='최고봉' //데이터 삭제

자바의 JDBC 프로그래밍

데이터베이스 연결 설정


데이터베이스 사용

자바에서 SQL 문을 실행하기 위해서는 Statement 클래스를 이용하고,
SQL문 실행 결과를 얻어오기 위해서는 ResultSet 클래스를 이용한다. 데이터를 검색하기 위해서는 executeQuery() 메소드를 추가하고,
추가, 수정, 삭제와 같이 데이터 변경은 executeUpdate() 메소드를 이용한다.
ResultSet 객체는 현재 데이터의 행(레코드 위치)을 가리키는 커서를 관리한다. 초기 값은 첫 번째 행 이전을 가리키도록 되어있다.


데이터 검색

package jdbcEx;

import java.io.*;
import java.sql.*;

public class jdbcEx {

	public static void main(String[] args) {
		Connection conn;
		Statement stmt = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");			
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sampledb", "root", "1234");
			System.out.println("DB 연결 완료");			
			stmt = conn.createStatement();
			
			ResultSet srs = stmt.executeQuery("select * from student");			
			printData(srs, "name", "id", "dept");
			
			srs = stmt.executeQuery("Select name, id, dept from student where name='이기자'");
			printData(srs, "name", "id", "dept");
			
			conn.close();
		}catch(ClassNotFoundException e) {
			e.printStackTrace();
			System.out.println("JDBC 드라이버 로드 에러");
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("SQL 실행 에러");
		}

	}
	
	private static void printData(ResultSet srs, String col1, String col2, String col3) throws SQLException {
		while(srs.next()) {
			if(col1 != "") {
				System.out.print(new String(srs.getString("name")));
			}if(col2 != "") {
				System.out.print("\t|\t" + srs.getString("id"));
			}if(col3 != "") {
				System.out.println("\t|\t" + new String(srs.getString("dept")));
			}else {
				System.out.println();
			}
		}
	}
}

데이터의 변경

package jdbcEx;

import java.io.*;
import java.sql.*;

public class jdbcEx2 {

	public static void main(String[] args) {
		Connection conn;
		Statement stmt = null;
		
		//update를 이렇게 할 수 있다. 추가
		String name ="아무개", id="0893012", dept="컴퓨터공학";
		String sql="";
		
		PreparedStatement pstmt = null;
		String insertSql = "";
		//--update를 이렇게 할 수 있다. 추가
		
		try {
			Class.forName("com.mysql.jdbc.Driver");			
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sampledb", "root", "1234");
			System.out.println("DB 연결 완료");			
			stmt = conn.createStatement();
			
			//update를 이렇게 할 수 있다. 추가
			insertSql = "insert into student(name, id, dept) values(?, ?, ?)";
			pstmt = conn.prepareStatement(insertSql);
			pstmt.setString(1, name);
			pstmt.setString(2, id);
			pstmt.setString(3, dept);
			pstmt.executeUpdate();
			//--update를 이렇게 할 수 있다. 추가
			
			//stmt.executeUpdate("insert into student(name, id, dept) values ('아무개', '0893012', '컴퓨터공학');");
			printTable(stmt);
			
			stmt.executeUpdate("update student set id='0189011' where name='아무개'");			
			printTable(stmt);
			
			stmt.executeUpdate("delete from student where name='아무개'");
			printTable(stmt);
			
			conn.close();
		}catch(ClassNotFoundException e) {
			e.printStackTrace();
			System.out.println("JDBC 드라이버 로드 에러");
		} catch (SQLException e) {
			e.printStackTrace();
			System.out.println("SQL 실행 에러");
		}

	}
	
	private static void printTable(Statement stmt) throws SQLException {
		ResultSet srs = stmt.executeQuery("select * from student");
		
		while(srs.next()) {
			System.out.print(new String(srs.getString("name")));
			System.out.print("\t|\t" + srs.getString("id"));
			System.out.println("\t|\t" + new String(srs.getString("dept")));
		}
		
		System.out.println(""); //insert 한 결과, update 한 결과, delete 한 결과 순으로 출력
	}

}

Comments