java_jungsuk3_슰ì−µë¬¸ì€œì€—ì²´_ hwp

Similar documents
32 Java 의정석定石 2 판 - 연습문제풀이 Chapter 6 객체지향프로그래밍 I Object-oriented Programming I

Chapter 객체지향프로그래밍 I Object-oriented Programming I

java_jungsuk3_슰ì−µë¬¸ì€œì€—ì²´_ hwp

2 Java 의정석定石 2 판 - 연습문제풀이 안녕하십니까? Java 의정석의저자남궁성입니다. 요즘제가 Java예제를정리한 Java1000제를집필하고있는데요. Java의정석에연습문제가있었으면좋겠다는독자분들의요청을많이받았습니다. 그래서 Java1000제의일부를연습문제로만

PowerPoint Presentation

PowerPoint 프레젠테이션

Microsoft PowerPoint - Java7.pptx

JAVA 프로그래밍실습 실습 1) 실습목표 - 메소드개념이해하기 - 매개변수이해하기 - 새메소드만들기 - Math 클래스의기존메소드이용하기 ( ) 문제 - 직사각형모양의땅이있다. 이땅의둘레, 면적과대각

PowerPoint Presentation

PowerPoint 프레젠테이션

슬라이드 1

<4D F736F F F696E74202D20C1A63038C0E520C5ACB7A1BDBABFCD20B0B4C3BC4928B0ADC0C729205BC8A3C8AF20B8F0B5E55D>

q 이장에서다룰내용 1 객체지향프로그래밍의이해 2 객체지향언어 : 자바 2

JAVA PROGRAMMING 실습 08.다형성

JAVA PROGRAMMING 실습 09. 예외처리

PowerPoint Presentation

TEST BANK & SOLUTION

Microsoft PowerPoint - 2강

gnu-lee-oop-kor-lec06-3-chap7

Microsoft PowerPoint 자바-기본문법(Ch2).pptx

PowerPoint 프레젠테이션

PowerPoint Presentation

PowerPoint Presentation

Java ...

JAVA PROGRAMMING 실습 02. 표준 입출력

금오공대 컴퓨터공학전공 강의자료

슬라이드 1

슬라이드 1

PowerPoint Presentation

쉽게

PowerPoint Presentation

슬라이드 1

Infinity(∞) Strategy

(Microsoft PowerPoint - java1-lecture11.ppt [\310\243\310\257 \270\360\265\345])

Cluster management software

비긴쿡-자바 00앞부속

Design Issues

슬라이드 1

PowerPoint 프레젠테이션

PowerPoint 프레젠테이션

Microsoft PowerPoint - CSharp-10-예외처리

02 C h a p t e r Java

C++ Programming

11장 포인터

Microsoft PowerPoint - C++ 5 .pptx

쉽게 풀어쓴 C 프로그래밍

제11장 프로세스와 쓰레드

PowerPoint Presentation

09-interface.key

5장.key

Microsoft PowerPoint - chap02-C프로그램시작하기.pptx

Microsoft Word - java19-1-midterm-answer.doc

Microsoft PowerPoint - 04-UDP Programming.ppt

PowerPoint Presentation

JAVA PROGRAMMING 실습 02. 표준 입출력

[ 마이크로프로세서 1] 2 주차 3 차시. 포인터와구조체 2 주차 3 차시포인터와구조체 학습목표 1. C 언어에서가장어려운포인터와구조체를설명할수있다. 2. Call By Value 와 Call By Reference 를구분할수있다. 학습내용 1 : 함수 (Functi

4장.문장

Microsoft PowerPoint - chap06-1Array.ppt

KNK_C_05_Pointers_Arrays_structures_summary_v02

PowerPoint Presentation

Microsoft PowerPoint - Lect04.pptx

Microsoft PowerPoint - ch07 - 포인터 pm0415

JAVA PROGRAMMING 실습 02. 표준 입출력

(8) getpi() 함수는정적함수이므로 main() 에서호출할수있다. (9) class Circle private double radius; static final double PI= ; // PI 이름으로 로초기화된정적상수 public

슬라이드 1

PowerPoint Presentation

PowerPoint Presentation

쉽게 풀어쓴 C 프로그래밍

PowerPoint 프레젠테이션

프로그래밍개론및실습 2015 년 2 학기프로그래밍개론및실습과목으로본내용은강의교재인생능출판사, 두근두근 C 언어수업, 천인국지음을발췌수정하였음

PowerPoint Presentation

OCW_C언어 기초

JAVA PROGRAMMING 실습 05. 객체의 활용

PowerPoint Presentation

Microsoft PowerPoint - chap06-2pointer.ppt

비트와바이트 비트와바이트 비트 (Bit) : 2진수값하나 (0 또는 1) 를저장할수있는최소메모리공간 1비트 2비트 3비트... n비트 2^1 = 2개 2^2 = 4개 2^3 = 8개... 2^n 개 1 바이트는 8 비트 2 2

12-file.key

PowerPoint Template

<322EBCF8C8AF28BFACBDC0B9AEC1A6292E687770>

JVM 메모리구조

10.0pt1height.7depth.3width±â10.0pt1height.7depth.3widthÃÊ10.0pt1height.7depth.3widthÅë10.0pt1height.7depth.3width°è10.0pt1height.7depth.3widthÇÁ10.0pt1height.7depth.3width·Î10.0pt1height.7depth.3width±×10.0pt1height.7depth.3width·¡10.0pt1height.7depth.3width¹Ö pt1height.7depth.3widthŬ10.0pt1height.7depth.3width·¡10.0pt1height.7depth.3width½º, 10.0pt1height.7depth.3width°´10.0pt1height.7depth.3widthü, 10.0pt1height.7depth.3widthº¯10.0pt1height.7depth.3width¼ö, 10.0pt1height.7depth.3width¸Þ10.0pt1height.7depth.3width¼Ò10.0pt1height.7depth.3widthµå

Microsoft PowerPoint - java1-lab5-ImageProcessorTestOOP.pptx

Microsoft PowerPoint - Chapter 6.ppt

다른 JSP 페이지호출 forward() 메서드 - 하나의 JSP 페이지실행이끝나고다른 JSP 페이지를호출할때사용한다. 예 ) <% RequestDispatcher dispatcher = request.getrequestdispatcher(" 실행할페이지.jsp");

쉽게 풀어쓴 C 프로그래밍

파일로입출력하기II - 파일출력클래스중에는데이터를일정한형태로출력하는기능을가지고있다. - PrintWriter와 PrintStream을사용해서원하는형태로출력할수있다. - PrintStream은구버전으로가능하면 PrintWriter 클래스를사용한다. PrintWriter

0. 표지에이름과학번을적으시오. (6) 1. 변수 x, y 가 integer type 이라가정하고다음빈칸에 x 와 y 의계산결과값을적으시오. (5) x = (3 + 7) * 6; x = 60 x = (12 + 6) / 2 * 3; x = 27 x = 3 * (8 / 4

자바 프로그래밍

PowerPoint 프레젠테이션

Microsoft PowerPoint - chap03-변수와데이터형.pptx

PowerPoint 프레젠테이션

중간고사

PowerPoint 프레젠테이션

PowerPoint Presentation

01-OOPConcepts(2).PDF

PowerPoint 프레젠테이션

쉽게 풀어쓴 C 프로그래밍

JUNIT 실습및발표

예제 2) Test.java class A intvar= 10; void method() class B extends A intvar= 20; 1"); void method() 2"); void method1() public class Test 3"); args) A

Microsoft PowerPoint - C프로그래밍-chap03.ppt [호환 모드]

Transcription:

Java의 정석定石 3판 - 연습문제 풀이 연습문제 풀이 ver.20170131v1 1

2 Java의정석定石 책이너무두꺼워지는것을막으려고불가피하게별도의 PDF파일로연습문제를 제공하게되었습니다. 많은양해바랍니다. 연습문제가먼저나오고풀이는뒷부 분에넣었습니다. 답을보기원하시면해당예제의번호로검색하시면답을찾으 실수있습니다. 연습문제중에좀어려운것들도있는데, 책안에답이있는경우가많이있습니 다. 문제가안풀릴때는책을다시한번살펴보세요. 복습도되고 1석2조입니 다. 문제가바로답을보기보다는제가운영하는카페 코드초보스터디 (http://cafe.naver.com/javachobostudy.cafe) 에오셔서질문하시면힌트를드리 겠습니다. 연습문제를못푼다고해서큰문제가되는것은아닙니다. 고민하고생각하고 자신의생각을정리하는방법을배우는것이중요한것이죠. 프로그래밍이라는 것은반드시창의적일필요는없다고생각합니다. 기존의것을잘활용하는것으 로도충분합니다. 문제의답을보고, 아, 이렇게하는구나. 라고이해하시고비 슷한상황에서응용하실수있으면됩니다. 이문서는 e-book의특성을살려서시간되는대로틈틈이업데이트할예정입니 다. 첫번째페이지의버전을꼭확인해주세요. 그리고좋은문제나오탈자, 문제 점등이있으면 castello@naver.com으로메일주세요. 단, 메일로질문은사절 합니다. 질문은카페게시판을이용해주세요. 마지막으로이문서는상업적인용도가아닌경우에는얼마든지자유롭게배포 하실수있습니다. 이문서가 Java를공부하시는많은분들에게도움이되길바 랍니다. 감사합니다. 2016년 2월 15일 남궁 성

Java의정석定石 3 [ 개정이력] 2016. 2. 15 - Java의정석 2 판의연습문제를바탕으로처음으로작성. (ver.20160215v1) 2016. 2. 27 - 연습문제 9-13, 9-14 (ver.20160227v1) 수정및답안추가 2016. 3. 18 - 연습문제 12-4 수정, 5-12 오타수정 (ver.20160318v1) 2017. 1. 31 - 연습문제 10-7 오타수정 (ver.20170131v1)

4 Java의정석定石 Chapter 변수 Variable

Java의정석定石 5 [ 연습문제 ] [2-1] 다음표의빈칸에 8 개의기본형(primitive type) 을알맞은자리에넣으시오. 종류 논리형 크기 1 byte 2 byte 4 byte 8 byte 문자형 정수형 실수형 [2-2] 주민등록번호를숫자로저장하고자한다. 이값을저장하기위해서는어떤자료형 (data type) 을선택해야할까? regno라는이름의변수를선언하고자신의주민등록번호로 초기화하는한줄의코드를적으시오. [2-3] 다음의문장에서리터럴, 변수, 상수, 키워드를적으시오. int i = 100; long l =100L; final float PI = 3.14f; - 리터럴 : - 변수 : - 키워드 : - 상수 : [2-4] 다음중기본형(primitive type) 이아닌것은? a. int b. Byte c. double d. boolean [2-5] 다음문장들의출력결과를적으세요. 오류가있는문장의경우, 괄호안에 오 류 라고적으시오. System.out.println( 1 + 2 ) ( ) System.out.println(true + ) ( ) System.out.println( A' + 'B') ( ) System.out.println('1' + 2) ( ) System.out.println('1' + '2') ( ) System.out.println('J' + ava ) ( ) System.out.println(true + null) ( )

6 Java의정석定石 [2-6] 다음중키워드가아닌것은?( 모두고르시오) a. if b. True c. NULL d. Class e. System [2-7] 다음중변수의이름으로사용할수있는것은? ( 모두고르시오) a. $ystem b. channel#5 c. 7eleven d. If e. 자바 f. new g. $MAX_NUM h. hello@com [2-8] 참조형변수(reference type) 와같은크기의기본형(primitive type) 은? ( 모두고 르시오 ) a. int b. long c. short d. float e. double [2-9] 다음중형변환을생략할수있는것은? ( 모두고르시오) byte b = 10; char ch = 'A'; int i = 100; long l = 1000L; a. b = (byte)i; b. ch = (char)b; c. short s = (short)ch; d. float f = (float)l; e. i = (int)ch; [2-10] char 타입의변수에저장될수있는정수값의범위는? (10 진수로적으시오)

Java의정석定石 7 [2-11] 다음중변수를잘못초기화한것은? ( 모두고르시오) a. byte b = 256; b. char c = ''; c. char answer = 'no'; d. float f = 3.14 e. double d = 1.4e3f; [2-12] 다음중 main 메서드의선언부로알맞은것은? ( 모두고르시오) a. public static void main(string[] args) b. public static void main(string args[]) c. public static void main(string[] arv) d. public void static main(string[] args) e. static public void main(string[] args) [2-13] 다음중타입과기본값이잘못연결된것은? ( 모두고르시오) a. boolean - false b. char - '\u0000' c. float - 0.0 d. int - 0 e. long - 0 f. String - ""

8 Java의정석定石 Chapter 연산자 Operator

Java의정석定石 9 [ 연습문제 ] [3-1] 다음연산의결과를적으시오. [ 연습문제]/ch3/Exercise3_1.java class Exercise3_1 { public static void main(string[] args) { int x = 2; int y = 5; char c = 'A'; // 'A' 의문자코드는 65 System.out.println(1 + x << 33); System.out.println(y >= 5 x < 0 && x > 2); System.out.println(y += 10 - x++); System.out.println(x+=2); System.out.println(!('A' <= c && c <='Z') ); System.out.println('C'-c); System.out.println('5'-'0'); System.out.println(c+1); System.out.println(++c); System.out.println(c++); System.out.println(c); [3-2] 아래의코드는사과를담는데필요한바구니( 버켓) 의수를구하는코드이다. 만일 사과의수가 123개이고하나의바구니에는 10 개의사과를담을수있다면, 13개의바구니 가필요할것이다. (1) 에알맞은코드를넣으시오. [ 연습문제]/ch3/Exercise3_2.java class Exercise3_2 { public static void main(string[] args) { int numofapples = 123; // 사과의개수 int sizeofbucket = 10; // 바구니의크기( 바구니에담을수있는사과의개수) int numofbucket = ( /* (1) */ ); // 모든사과를담는데필요한바구니의수 System.out.println(" 필요한바구니의수 :"+numofbucket); 실행결과 [ ] 13

10 Java의정석定石 [3-3] 아래는변수 num의값에따라 양수, 음수, 0 을출력하는코드이다. 삼항연산 자를이용해서 (1) 에알맞은코드를넣으시오. [Hint] 삼항연산자를두번사용하라. [ 연습문제]/ch3/Exercise3_3.java class Exercise3_3 { public static void main(string[] args) { int num = 10; System.out.println( /* (1) */ ); [ 실행결과] 양수 [3-4] 아래는변수 num 의값중에서백의자리이하를버리는코드이다. 만일변수 num 의값이 456 이라면 400 이되고, 111 이라면 100 이된다. (1) 에알맞은코드를넣으 시오. [ 연습문제]/ch3/Exercise3_4.java class Exercise3_4 { public static void main(string[] args) { int num = 456; System.out.println( /* (1) */ ); [ 실행결과] 400 [3-5] 아래는변수 num의값중에서일의자리를 1 로바꾸는코드이다. 만일변수 num의 값이 333이라면 331 이되고, 777이라면 771 이된다. (1) 에알맞은코드를넣으시오. [ 연습문제]/ch3/Exercise3_5.java class Exercise3_5 { public static void main(string[] args) { int num = 333; System.out.println( /* (1) */ ); 실행결과 [ ] 331

Java의정석定石 11 [3-6] 아래는변수 num의값보다크면서도가장가까운 10의배수에서변수 num의값을 뺀나머지를구하는코드이다. 예를들어, 24의크면서도가장가까운 10의배수는 30이 다. 19의경우 20 이고, 81의경우 90 이된다. 30에서 24를뺀나머지는 6이기때문에변 수 num의값이 24라면 6 을결과로얻어야한다. (1) 에알맞은코드를넣으시오. [Hint] 나머지연산자를사용하라. [ 연습문제]/ch3/Exercise3_6.java class Exercise3_6 { public static void main(string[] args) { int num = 24; System.out.println( /* (1) */ ); [ 실행결과] 6 [3-7] 아래는화씨(Fahrenheit) 를섭씨(Celcius) 로변환하는코드이다. 변환공식이 'C = 5/9 (F - 32)' 라고할때, (1) 에알맞은코드를넣으시오. 단, 변환결과값은소수점 셋째자리에서반올림해야한다.(Math.round() 를사용하지않고처리할것) [ 연습문제]/ch3/Exercise3_7.java class Exercise3_7 { public static void main(string[] args) { int fahrenheit = 100; float celcius = ( /* (1) */ ); System.out.println("Fahrenheit:"+fahrenheit); System.out.println("Celcius:"+celcius); 실행결과 [ ] Fahrenheit:100 Celcius:37.78

12 Java의정석定石 [3-8] 아래코드의문제점을수정해서실행결과와같은결과를얻도록하시오. [ 연습문제]/ch3/Exercise3_8.java class Exercise3_8 { public static void main(string[] args) { byte a = 10; byte b = 20; byte c = a + b; char ch = 'A'; ch = ch + 2; float f = 3 / 2; long l = 3000 * 3000 * 3000; float f2 = 0.1f; double d = 0.1; boolean result = d==f2; System.out.println("c="+c); System.out.println("ch="+ch); System.out.println("f="+f); System.out.println("l="+l); System.out.println("result="+result); [ 실행결과] c=30 ch=c f=1.5 l=27000000000 result=true [3-9] 다음은문자형변수 ch 가영문자( 대문자또는소문자) 이거나숫자일때만변수 b 의값이 true 가되도록하는코드이다. (1) 에알맞은코드를넣으시오. [ 연습문제]/ch3/Exercise3_9.java class Exercise3_9 { public static void main(string[] args) { char ch = 'z'; boolean b = ( /* (1) */ ); System.out.println(b); 실행결과 [ ] true

Java의정석定石 13 [3-10] 다음은대문자를소문자로변경하는코드인데, 문자 ch에저장된문자가대문자 인경우에만소문자로변경한다. 문자코드는소문자가대문자보다 32 만큼더크다. 예를 들어 'A 의코드는 65 이고 a' 의코드는 97 이다. (1)~(2) 에알맞은코드를넣으시오. [ 연습문제]/ch3/Exercise3_10.java class Exercise3_10 { public static void main(string[] args) { char ch = 'A'; char lowercase = ( /* (1) */ )? ( /* (2) */ ) : ch; System.out.println("ch:"+ch); System.out.println("ch to lowercase:"+lowercase); 실행결과 [ ] ch:a ch to lowercase:a

14 Java의정석定石 Chapter 조건문과반복문 if, switch, for, while

Java의정석定石 15 [ 연습문제 ] [4-1] 다음의문장들을조건식으로표현하라. 1. int형변수 x가 10보다크고 20보다작을때 true인조건식 2. char형변수 ch가공백이나탭이아닐때 true인조건식 3. char형변수 ch 가 x' 또는 X' 일때 true인조건식 4. char형변수 ch 가숫자( 0 ~ 9 ) 일때 true인조건식 5. char형변수 ch 가영문자( 대문자또는소문자) 일때 true인조건식 6. int형변수 year가 400으로나눠떨어지거나또는 4로나눠떨어지고 100으로나눠떨어지지 않을때 true인조건식 7. boolean형변수 poweron가 false일때 true인조건식 8. 문자열참조변수 str 이 yes 일때 true인조건식 [4-2] 1부터 20까지의정수중에서 2 또는 3 의배수가아닌수의총합을구하시오. [4-3] 1+(1+2)+(1+2+3)+(1+2+3+4)+...+(1+2+3+...+10) 의결과를계산하시오. [4-4] 1+(-2)+3+(-4)+... 과같은식으로계속더해나갔을때, 몇까지더해야총합이 100 이상이되는지구하시오. [4-5] 다음의 for문을 while 문으로변경하시오. [ 연습문제]/ch4/Exercise4_5.java public class Exercise4_5 { public static void main(string[] args) { for(int i=0; i<=10; i++) { for(int j=0; j<=i; j++) System.out.print("*"); System.out.println(); // end of main // end of class [4-6] 두개의주사위를던졌을때, 눈의합이 6이되는모든경우의수를출력하는프 로그램을작성하시오.

16 Java의정석定石 [4-7] Math.random() 을이용해서 1부터 6사이의임의의정수를변수 value에저장하는 코드를완성하라. (1) 에알맞은코드를넣으시오. [ 연습문제]/ch4/Exercise4_7.java class Exercise4_7 { public static void main(string[] args) { int value = ( /* (1) */ ); System.out.println("value:"+value); [4-8] 방정식 2x+4y=10 의모든해를구하시오. 단, x와 y는정수이고각각의범위는 0<=x<=10, 0<=y<=10 이다. 실행결과 [ ] x=1, y=2 x=3, y=1 x=5, y=0 [4-9] 숫자로이루어진문자열 str 이있을때, 각자리의합을더한결과를출력하는코 드를완성하라. 만일문자열이 "12345" 라면, 1+2+3+4+5 의결과인 15를출력이출력되 어야한다. (1) 에알맞은코드를넣으시오. [Hint] String클래스의 charat(int i) 을사용 [ 연습문제]/ch4/Exercise4_9.java class Exercise4_9 { public static void main(string[] args) { String str = "12345"; int sum = 0; for(int i=0; i < str.length(); i++) { /* (1) 알맞은코드를넣어완성하시오. */ System.out.println("sum="+sum); [ 실행결과] 15

Java의정석定石 17 [4-10] int타입의변수 num 이있을때, 각자리의합을더한결과를출력하는코드를 완성하라. 만일변수 num의값이 12345라면, 1+2+3+4+5 의결과인 15를출력하라. (1) 에알맞은코드를넣으시오. [ 주의] 문자열로변환하지말고숫자로만처리해야한다. [ 연습문제]/ch4/Exercise4_10.java class Exercise4_10 { public static void main(string[] args) { int num = 12345; int sum = 0; /* (1) 알맞은코드를넣어완성하시오. */ System.out.println("sum="+sum); [ 실행결과] 15 [4-11] 피보나치(Fibonnaci) 수열( 數列 ) 은앞을두수를더해서다음수를만들어나가 는수열이다. 예를들어앞의두수가 1과 1이라면그다음수는 2가되고그다음수는 1과 2를더해서 3이되어서 1,1,2,3,5,8,13,21,... 과같은식으로진행된다. 1과 1부터 시작하는피보나치수열의 10 번째수는무엇인지계산하는프로그램을완성하시오. [ 연습문제]/ch4/Exercise4_11.java public class Exercise4_11 { public static void main(string[] args) { // Fibonnaci 수열의시작의첫두숫자를 1, 1 로한다. int num1 = 1; int num2 = 1; int num3 = 0; // 세번째값 System.out.print(num1+","+num2); for (int i = 0 ; i < 8 ; i++ ) { /* (1) 알맞은코드를넣어완성하시오. */ // end of main // end of class 실행결과 [ ] 1,1,2,3,5,8,13,21,34,55

18 Java의정석定石 [4-12] 구구단의일부분을다음과같이출력하시오. [ 실행결과] 2*1=2 3*1=3 4*1=4 2*2=4 3*2=6 4*2=8 2*3=6 3*3=9 4*3=12 5*1=5 6*1=6 7*1=7 5*2=10 6*2=12 7*2=14 5*3=15 6*3=18 7*3=21 8*1=8 9*1=9 8*2=16 9*2=18 8*3=24 9*3=27 [4-13] 다음은주어진문자열(value) 이숫자인지를판별하는프로그램이다. (1) 에알맞 은코드를넣어서프로그램을완성하시오. [ 연습문제]/ch4/Exercise4_13.java class Exercise4_13 { public static void main(string[] args) { String value = "12o34"; char ch = ' '; boolean isnumber = true; // 반복문과 charat(int i) 를이용해서문자열의문자를 // 하나씩읽어서검사한다. for(int i=0; i < value.length() ;i++) { /* (1) 알맞은코드를넣어완성하시오. */ if (isnumber) { System.out.println(value+" 는숫자입니다."); else { System.out.println(value+" 는숫자가아닙니다."); // end of main // end of class [ 실행결과] 12o34 는숫자가아닙니다.

Java의정석定石 19 [4-14] 다음은숫자맞추기게임을작성한것이다. 1과 100사이의값을반복적으로입력 해서컴퓨터가생각한값을맞추면게임이끝난다. 사용자가값을입력하면, 컴퓨터는자 신이생각한값과비교해서결과를알려준다. 사용자가컴퓨터가생각한숫자를맞추면 게임이끝나고몇번만에숫자를맞췄는지알려준다. (1)~(2) 에알맞은코드를넣어프 로그램을완성하시오. [ 연습문제]/ch4/Exercise4_14.java class Exercise4_14 { public static void main(string[] args) { // 1~100사이의임의의값을얻어서 answer 에저장한다. int answer = /* (1) */; int input = 0; // 사용자입력을저장할공간 int count = 0; // 시도횟수를세기위한변수 // 화면으로부터사용자입력을받기위해서 Scanner클래스사용 java.util.scanner s = new java.util.scanner(system.in); do { count++; System.out.print("1과 100 사이의값을입력하세요 :"); input = s.nextint(); // 입력받은값을변수 input 에저장한다. /* (2) 알맞은코드를넣어완성하시오. */ while(true); // 무한반복문 // end of main // end of class HighLow [ 실행결과] 1과 100 사이의값을입력하세요 :50 더큰수를입력하세요. 1과 100 사이의값을입력하세요 :75 더큰수를입력하세요. 1과 100 사이의값을입력하세요 :87 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :80 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :77 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :76 맞췄습니다. 시도횟수는 6 번입니다.

20 Java의정석定石 [4-15] 다음은회문수를구하는프로그램이다. 회문수(palindrome) 란, 숫자를거꾸로읽 어도앞으로읽는것과같은수를말한다. 예를들면 12321 이나 13531 같은수를말한 다. (1) 에알맞은코드를넣어서프로그램을완성하시오. [Hint] 나머지연산자를이용하시오. [ 연습문제]/ch4/Exercise4_15.java class Exercise4_15 { public static void main(string[] args) { int number = 12321; int tmp = number; int result =0; // 변수 number를거꾸로변환해서담을변수 while(tmp!=0) { /* (1) 알맞은코드를넣어완성하시오. */ if(number == result) System.out.println( number + " 는회문수입니다."); else System.out.println( number + " 는회문수가아닙니다."); // main [ 실행결과] 12321 는회문수입니다.

Java의정석定石 21 Chapter 배열 Array

22 Java의정석定石 [ 연습문제 ] [5-1] 다음은배열을선언하거나초기화한것이다. 잘못된것을고르고그이유를설명 하시오. a. int[] arr[]; b. int[] arr = {1,2,3,; c. int[] arr = new int[5]; d. int[] arr = new int[5]{1,2,3,4,5; e. int arr[5]; f. int[] arr[] = new int[3][]; [5-2] 다음과같은배열이있을때, arr[3].length 의값은얼마인가? int[][] arr = { { 5, 5, 5, 5, 5, { 10, 10, 10, { 20, 20, 20, 20, { 30, 30 ; [5-3] 배열 arr 에담긴모든값을더하는프로그램을완성하시오. [ 연습문제]/ch5/Exercise5_3.java class Exercise5_3 { public static void main(string[] args) { int[] arr = {10, 20, 30, 40, 50; int sum = 0; /* */ (1) 알맞은코드를넣어완성하시오. System.out.println("sum="+sum); 실행결과 [ ] sum=150

Java의정석定石 23 [5-4] 2차원배열 arr 에담긴모든값의총합과평균을구하는프로그램을완성하시오. [ 연습문제]/ch5/Exercise5_4.java class Exercise5_4 { public static void main(string[] args) { int[][] arr = { { 5, 5, 5, 5, 5, {10,10,10,10,10, {20,20,20,20,20, {30,30,30,30,30 ; int total = 0; float average = 0; /* */ (1) 알맞은코드를넣어완성하시오. System.out.println("total="+total); System.out.println("average="+average); // end of main // end of class 실행결과 [ ] total=325 average=16.25

24 Java의정석定石 [5-5] 다음은 1과 9사이의중복되지않은숫자로이루어진 3자리숫자를만들어내는프 로그램이다. (1)~(2) 에알맞은코드를넣어서프로그램을완성하시오. [ 참고] Math.random() 을사용했기때문에실행결과와다를수있다. [ 연습문제]/ch5/Exercise5_5.java class Exercise5_5 { public static void main(string[] args) { int[] ballarr = {1,2,3,4,5,6,7,8,9; int[] ball3 = new int[3]; // 배열 ballarr 의임의의요소를골라서위치를바꾼다. for(int i=0; i< ballarr.length;i++) { int j = (int)(math.random() * ballarr.length); int tmp = 0; /* */ (1) 알맞은코드를넣어완성하시오. // 배열 ballarr의앞에서 3개의수를배열 ball3 로복사한다. /* (2) */ for(int i=0;i<ball3.length;i++) { System.out.print(ball3[i]); // end of main // end of class 실행결과 [ ] 486

Java의정석定石 25 [5-6] 다음은거스름돈을몇개의동전으로지불할수있는지를계산하는문제이다. 변 수 money의금액을동전으로바꾸었을때각각몇개의동전이필요한지계산해서출력하 라. 단, 가능한한적은수의동전으로거슬러주어야한다. (1) 에알맞은코드를넣어서 프로그램을완성하시오. [Hint] 나눗셈연산자와나머지연산자를사용해야한다. [ 연습문제]/ch5/Exercise5_6.java class Exercise5_6 { public static void main(string args[]) { // 큰금액의동전을우선적으로거슬러줘야한다. int[] coinunit = {500, 100, 50, 10; int money = 2680; System.out.println("money="+money); for(int i=0;i<coinunit.length;i++) { /* (1) 알맞은코드를넣어완성하시오. */ // main [ 실행결과] money=2680 500 원: 5 100 원: 1 50 원: 1 10 원: 3

26 Java의정석定石 [5-7] 문제 5-6 에동전의개수를추가한프로그램이다. 커맨드라인으로부터거슬러줄 금액을입력받아계산한다. 보유한동전의개수로거스름돈을지불할수없으면, 거스름 돈이부족합니다. 라고출력하고종료한다. 지불할돈이충분히있으면, 거스름돈을지불 한만큼가진돈에서빼고남은동전의개수를화면에출력한다. (1) 에알맞은코드를넣 어서프로그램을완성하시오. [ 연습문제]/ch5/Exercise5_7.java class Exercise5_7 { public static void main(string args[]) { if(args.length!=1) { System.out.println("USAGE: java Exercise5_7 3120"); System.exit(0); // 문자열을숫자로변환한다. 입력한값이숫자가아닐경우예외가발생한다. int money = Integer.parseInt(args[0]); System.out.println("money="+money); int[] coinunit = {500, 100, 50, 10 ; // int[] coin = {5, 5, 5, 5; // 동전의단위단위별동전의개수 for(int i=0;i<coinunit.length;i++) { int coinnum = 0; /* (1) 아래의로직에맞게코드를작성하시오. 1. 금액(money) 을동전단위로나눠서필요한동전의개수(coinNum) 를구한다. 2. 배열 coin에서 coinnum 만큼의동전을뺀다. ( 만일충분한동전이없다면배열 coin 에있는만큼만뺀다.) 3. 금액에서동전의개수(coinNum) 와동전단위를곱한값을뺀다. */ System.out.println(coinUnit[i]+" 원: "+coinnum); if(money > 0) { System.out.println(" 거스름돈이부족합니다."); System.exit(0); // 프로그램을종료한다. System.out.println("= 남은동전의개수 ="); for(int i=0;i<coinunit.length;i++) { System.out.println(coinUnit[i]+" 원:"+coin[i]); // main [ 참고] 실행결과는다음페이지에있다.

Java의정석定石 27 [ 실행결과] C:\jdk1.8\work\ch5>java Exercise5_7 USAGE: java Exercise5_7 3120 C:\jdk1.8\work\ch5>java Exercise5_7 3170 money=3170 500 원: 5 100 원: 5 50 원: 3 10 원: 2 = 남은동전의개수 = 500 원:0 100 원:0 50 원:2 10 원:3 C:\jdk1.8\work\ch5>java Exercise5_7 3510 money=3510 500 원: 5 100 원: 5 50 원: 5 10 원: 5 거스름돈이부족합니다. [5-8] 다음은배열 answer 에담긴데이터를읽고각숫자의개수를세어서개수만큼 * 을찍어서그래프를그리는프로그램이다. (1)~(2) 에알맞은코드를넣어서완성하시오. [ 연습문제]/ch5/Exercise5_8.java class Exercise5_8 { public static void main(string[] args) { int[] answer = { 1,4,4,3,1,4,4,2,1,3,2 ; int[] counter = new int[4]; for(int i=0; i < answer.length;i++) { /* (1) 알맞은코드를넣어완성하시오. */ for(int i=0; i < counter.length;i++) { /* (2) 알맞은코드를넣어완성하시오. */ System.out.println(); // end of main // end of class 실행결과 [ ] 3*** 2** 2** 4****

28 Java의정석定石 [5-9] 주어진배열을시계방향으로 90 도회전시켜서출력하는프로그램을완성하시오. [ 연습문제]/ch5/Exercise5_9.java class Exercise5_9 { public static void main(string[] args) { char[][] star = { {'*','*',' ',' ',' ', {'*','*',' ',' ',' ', {'*','*','*','*','*', {'*','*','*','*','*' ; char[][] result = new char[star[0].length][star.length]; for(int i=0; i < star.length;i++) { for(int j=0; j < star[i].length;j++) { System.out.print(star[i][j]); System.out.println(); System.out.println(); for(int i=0; i < star.length;i++) { for(int j=0; j < star[i].length;j++) { /* (1) 알맞은코드를넣어완성하시오. */ for(int i=0; i < result.length;i++) { for(int j=0; j < result[i].length;j++) { System.out.print(result[i][j]); System.out.println(); // end of main // end of class [ 실행결과] ** ** ***** ***** **** **** ** ** **

Java의정석定石 29 [5-10] 다음은알파벳과숫자를아래에주어진암호표로암호화하는프로그램이다. (1) 에알맞은코드를넣어서완성하시오. a b c d e f g h i j k l m n o p q r s t ` ~! @ # $ % ^ & * ( ) - _ + = [ ] { u v w x y z ; :,. / 0 1 2 3 4 5 6 7 8 9 q w e r t y u i o p [ 연습문제]/ch5/Exercise5_10.java class Exercise5_10 { public static void main(string[] args) { char[] abccode = { '`','~','!','@','#','$','%','^','&','*', '(',')','-','_','+','=',' ','[',']','{', '',';',':',',','.','/'; // 0 1 2 3 4 5 6 7 8 9 char[] numcode = {'q','w','e','r','t','y','u','i','o','p'; String src = "abc123"; String result = ""; // 문자열 src의문자를 charat() 으로하나씩읽어서변환후 result에저장 for(int i=0; i < src.length();i++) { char ch = src.charat(i); /* (1) 알맞은코드를넣어완성하시오. */ System.out.println("src:"+src); System.out.println("result:"+result); // end of main // end of class 실행결과 [ ] src:abc123 result:`~!wer

30 Java의정석定石 [5-11] 주어진 2차원배열의데이터보다가로와세로로 1이더큰배열을생성해서배열 의행과열의마지막요소에각열과행의총합을저장하고출력하는프로그램이다. (1) 에알맞은코드를넣어서완성하시오. [ 연습문제]/ch5/Exercise5_11.java class Exercise5_11 { public static void main(string[] args) { int[][] score = { {100, 100, 100, {20, 20, 20, {30, 30, 30, {40, 40, 40, {50, 50, 50 ; int[][] result = new int[score.length+1][score[0].length+1]; for(int i=0; i < score.length;i++) { for(int j=0; j < score[i].length;j++) { /* (1) 알맞은코드를넣어완성하시오. */ for(int i=0; i < result.length;i++) { for(int j=0; j < result[i].length;j++) { System.out.printf("%4d",result[i][j]); System.out.println(); // main [ 실행결과] 100 100 100 300 20 20 20 60 30 30 30 90 40 40 40 120 50 50 50 150 240 240 240 720

Java의정석定石 31 [5-12] 예제5-23 을변경하여, 아래와같은결과가나오도록하시오. [ 실행결과] Q1. chair 의뜻은? dmlwk 틀렸습니다. 정답은의자입니다 Q2. computer 의뜻은? 컴퓨터정답입니다. Q3. integer 의뜻은? 정수정답입니다. 전체 3문제중 2 문제맞추셨습니다. [5-13] 단어의글자위치를섞어서보여주고원래의단어를맞추는예제이다. 실행결과와 같이동작하도록예제의빈곳을채우시오. [ 연습문제5-13]/ch5/Excercise5_13.java import java.util.scanner; class Exercise5_13 { public static void main(string args[]) { String[] words = { "television", "computer", "mouse", "phone" ; Scanner scanner = new Scanner(System.in); for(int i=0;i<words.length;i++) { char[] question = words[i].tochararray(); // String을 char[] 로변환 /* */ (1) 알맞은코드를넣어완성하시오. char배열 question 에담긴문자의위치를임의로바꾼다. System.out.printf("Q%d. %s 의정답을입력하세요.>", i+1, new String(question)); String answer = scanner.nextline(); // trim() 으로 answer 의좌우공백을제거한후, equals로 word[i] 와비교 if(words[i].equals(answer.trim())) System.out.printf(" 맞았습니다.%n%n"); else System.out.printf(" 틀렸습니다.%n%n"); // main의끝

32 Java의정석定石 [ 실행결과] Q1. lvtsieeoin 의정답을입력하세요.>television 맞았습니다. Q2. otepcumr 의정답을입력하세요.>computer 맞았습니다. Q3. usemo 의정답을입력하세요.>asdf 틀렸습니다. 의정답을입력하세요 Q4. ohpne.>phone 맞았습니다.

Java의정석定石 33 Chapter 객체지향프로그래밍 I Object-oriented Programming I

34 Java의정석定石 [ 연습문제 ] [6-1] 다음과같은멤버변수를갖는 SutdaCard 클래스를정의하시오. 타입변수명설명 int num 카드의숫자.(1~10 사이의정수) boolean iskwang 광( 光 ) 이면 true, 아니면 false [6-2] 문제6-1에서정의한 SutdaCard클래스에두개의생성자와 info() 를추가해서실행 결과와같은결과를얻도록하시오. [ 연습문제]/ch6/Exercise6_2.java class Exercise6_2 { public static void main(string args[]) { SutdaCard card1 = new SutdaCard(3, false); SutdaCard card2 = new SutdaCard(); System.out.println(card1.info()); System.out.println(card2.info()); class SutdaCard { /* (1) 알맞은코드를넣어완성하시오. */ 실행결과 [ ] 3 1K [6-3] 다음과같은멤버변수를갖는 Student 클래스를정의하시오. 타입 변수명 설명 String name 학생이름 int ban 반 int no 번호 int kor 국어점수 int eng 영어점수 int math 수학점수

Java의정석定石 35 [6-4] 문제6-3에서정의한 Student클래스에다음과같이정의된두개의메서드 gettotal() 과 getaverage() 를추가하시오. 1. 메서드명 : gettotal 기 능 : 국어(kor), 영어(eng), 수학(math) 의점수를모두더해서반환한다. 반환타입 : int 매개변수 : 없음 2. 메서드명 : getaverage 기 능 : 총점( 국어점수+ 영어점수+ 수학점수) 을과목수로나눈평균을구한다. 소수점둘째자리에서반올림할것. 반환타입 : float 매개변수 : 없음 [ 연습문제]/ch6/Exercise6_4.java class Exercise6_4 { public static void main(string args[]) { Student s = new Student(); s.name = " 홍길동"; s.ban = 1; s.no = 1; s.kor = 100; s.eng = 60; s.math = 76; System.out.println(" 이름:"+s.name); System.out.println(" 총점:"+s.getTotal()); System.out.println(" 평균:"+s.getAverage()); class Student { /* (1) 알맞은코드를넣어완성하시오. */ [ 실행결과] 이름: 홍길동총점 :236 평균 :78.7

36 Java의정석定石 [6-5] 다음과같은실행결과를얻도록 Student클래스에생성자와 info() 를추가하시오. [ 연습문제]/ch6/Exercise6_5.java class Exercise6_5 { public static void main(string args[]) { Student s = new Student(" 홍길동",1,1,100,60,76); System.out.println(s.info()); class Student { /* (1) 알맞은코드를넣어완성하시오. */ [ 실행결과] 홍길동,1,1,100,60,76,236,78.7 [6-6] 두점의거리를계산하는 getdistance() 를완성하시오. [Hint] 제곱근계산은 Math.sqrt(double a) 를사용하면된다. [ 연습문제]/ch6/Exercise6_6.java class Exercise6_6 { // 두점 (x,y) 와 (x1,y1) 간의거리를구한다. static double getdistance(int x, int y, int x1, int y1) { /* (1) 알맞은코드를넣어완성하시오. */ public static void main(string args[]) { System.out.println(getDistance(1,1,2,2)); 실행결과 [ ] 1.4142135623730951

Java의정석定石 37 [6-7] 문제6-6에서작성한클래스메서드 getdistance() 를 MyPoint클래스의인스턴스메서 드로정의하시오. [ 연습문제]/ch6/Exercise6_7.java class MyPoint { int x; int y; MyPoint(int x, int y) { this.x = x; this.y = y; /* */ (1) 인스턴스메서드 getdistance 를작성하시오. class Exercise6_7 { public static void main(string args[]) { MyPoint p = new MyPoint(1,1); // p 와 (2,2) 의거리를구한다. System.out.println(p.getDistance(2,2)); 실행결과 [ ] 1.4142135623730951 [6-8] 다음의코드에정의된변수들을종류별로구분해서적으시오. class PlayingCard { int kind; int num; static int width; static int height; PlayingCard(int k, int n) { kind = k; num = n; public static void main(string args[]) { PlayingCard card = new PlayingCard(1,1); - 클래스변수(static 변수) : - 인스턴스변수 : - 지역변수 :

38 Java의정석定石 [6-9] 다음은컴퓨터게임의병사(marine) 를클래스로정의한것이다. 이클래스의멤버 중에 static 을붙여야하는것은어떤것들이고그이유는무엇인가? ( 단, 모든병사의공격력과방어력은같아야한다.) class Marine { int x=0, y=0; // Marine 의위치좌표(x,y) int hp = 60; // 현재체력 int weapon = 6; // 공격력 int armor = 0; // 방어력 void weaponup() { weapon++; void armorup() { armor++; void move(int x, int y) { this.x = x; this.y = y; [6-10] 다음중생성자에대한설명으로옳지않은것은? ( 모두고르시오) a. 모든생성자의이름은클래스의이름과동일해야한다. b. 생성자는객체를생성하기위한것이다. c. 클래스에는생성자가반드시하나이상있어야한다. d. 생성자가없는클래스는컴파일러가기본생성자를추가한다. e. 생성자는오버로딩할수없다. [6-11] 다음중 this 에대한설명으로맞지않은것은? ( 모두고르시오) a. 객체자신을가리키는참조변수이다. b. 클래스내에서라면어디서든사용할수있다. c. 지역변수와인스턴스변수를구별할때사용한다. d. 클래스메서드내에서는사용할수없다. [6-12] 다음중오버로딩이성립하기위한조건이아닌것은? ( 모두고르시오) a. 메서드의이름이같아야한다. b. 매개변수의개수나타입이달라야한다. c. 리턴타입이달라야한다. d. 매개변수의이름이달라야한다.

Java의정석定石 39 [6-13] 다음중아래의 add 메서드를올바르게오버로딩한것은? ( 모두고르시오) long add(int a, int b) { return a+b; a. long add(int x, int y) { return x+y; b. long add(long a, long b) { return a+b; c. int add(byte a, byte b) { return a+b; d. int add(long a, int b) { return (int)(a+b); [6-14] 다음중초기화에대한설명으로옳지않은것은? ( 모두고르시오) a. 멤버변수는자동초기화되므로초기화하지않고도값을참조할수있다. b. 지역변수는사용하기전에반드시초기화해야한다. c. 초기화블럭보다생성자가먼저수행된다. d. 명시적초기화를제일우선적으로고려해야한다. e. 클래스변수보다인스턴스변수가먼저초기화된다. [6-15] 다음중인스턴스변수의초기화순서가올바른것은? a. 기본값-명시적초기화-초기화블럭-생성자 b. 기본값-명시적초기화-생성자-초기화블럭 c. 기본값-초기화블럭-명시적초기화-생성자 d. 기본값-초기화블럭-생성자-명시적초기화 [6-16] 다음중지역변수에대한설명으로옳지않은것은? ( 모두고르시오) a. 자동초기화되므로별도의초기화가필요없다. b. 지역변수가선언된메서드가종료되면지역변수도함께소멸된다. c. 매서드의매개변수로선언된변수도지역변수이다. d. 클래스변수나인스턴스변수보다메모리부담이적다. e. 힙(heap) 영역에생성되며가비지컬렉터에의해소멸된다. [6-17] 호출스택이다음과같은상황일때옳지않은설명은? ( 모두고르시오) println method1 method2 main a. 제일먼저호출스택에저장된것은 main 메서드이다. b. println 메서드를제외한나머지메서드들은모두종료된상태이다. c. method2메서드를호출한것은 main 메서드이다. d. println메서드가종료되면 method1 메서드가수행을재개한다. e. main-method2-method1-println 의순서로호출되었다. f. 현재실행중인메서드는 println 뿐이다.

40 Java의정석定石 [6-18] 다음의코드를컴파일하면에러가발생한다. 컴파일에러가발생하는라인과그 이유를설명하시오. class MemberCall { int iv = 10; static int cv = 20; int iv2 = cv; static int cv2 = iv; static void staticmethod1() { System.out.println(cv); System.out.println(iv); void instancemethod1() { System.out.println(cv); System.out.println(iv); static void staticmethod2() { staticmethod1(); instancemethod1(); void instancemethod2() { staticmethod1(); instancemethod1(); // 라인 A // 라인 B // 라인 C // 라인 D // 라인 E [6-19] 다음코드의실행결과를예측하여적으시오. [ 연습문제]/ch6/Exercise6_19.java class Exercise6_19 { public static void change(string str) { str += "456"; public static void main(string[] args) { String str = "ABC123"; System.out.println(str); change(str); System.out.println("After change:"+str);

Java의정석定石 41 [6-20] 다음과같이정의된메서드를작성하고테스트하시오. [ 주의] Math.random() 을사용하는경우실행결과와다를수있음. 메서드명 : shuffle 기 능 : 주어진배열에담긴값의위치를바꾸는작업을반복하여뒤섞이게한다. 처리한배열을반환한다. 반환타입 : int[] 매개변수 : int[] arr - 정수값이담긴배열 [ 연습문제]/ch6/Exercise6_20.java class Exercise6_20 { /* (1) shuffle 메서드를작성하시오. */ public static void main(string[] args) { int[] original = {1,2,3,4,5,6,7,8,9; System.out.println(java.util.Arrays.toString(original)); int[] result = shuffle(original); System.out.println(java.util.Arrays.toString(result)); [ 실행결과] [1, 2, 3, 4, 5, 6, 7, 8, 9] [4, 6, 8, 3, 2, 9, 7, 1, 5] [6-21] Tv 클래스를주어진로직대로완성하시오. 완성한후에실행해서주어진실행결과 와일치하는지확인하라. [ 참고] 코드를단순히하기위해서유효성검사는로직에서제외했다. [ 연습문제]/ch6/Exercise6_21.java class MyTv { boolean ispoweron; int channel; int volume; final int MAX_VOLUME = 100; final int MIN_VOLUME = 0; final int MAX_CHANNEL = 100; final int MIN_CHANNEL = 1; void turnonoff() { // (1) ispoweron의값이 true면 false 로, false면 true 로바꾼다.

42 Java의정석定石 void volumeup() { // (2) volume의값이 MAX_VOLUME보다작을때만값을 1 증가시킨다. void volumedown() { // (3) volume의값이 MIN_VOLUME보다클때만값을 1 감소시킨다. void channelup() { // (4) channel의값을 1 증가시킨다. // 만일 channel이 MAX_CHANNEL 이면, channel의값을 MIN_CHANNEL 로바꾼다. void channeldown() { // (5) channel의값을 1 감소시킨다. // 만일 channel이 MIN_CHANNEL 이면, channel의값을 MAX_CHANNEL 로바꾼다. // class MyTv class Exercise6_21 { public static void main(string args[]) { MyTv t = new MyTv(); t.channel = 100; t.volume = 0; System.out.println("CH:"+t.channel+", VOL:"+ t.volume); t.channeldown(); t.volumedown(); System.out.println("CH:"+t.channel+", VOL:"+ t.volume); t.volume = 100; t.channelup(); t.volumeup(); System.out.println("CH:"+t.channel+", VOL:"+ t.volume); 실행결과 [ ] CH:100, VOL:0 CH:99, VOL:0 CH:100, VOL:100

Java의정석定石 43 [6-22] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : isnumber 기능 : 주어진문자열이모두숫자로만이루어져있는지확인한다. 모두숫자로만이루어져있으면 true 를반환하고, 그렇지않으면 false 를반환한다. 만일주어진문자열이 null 이거나빈문자열 이라면 false 를반환한다. 반환타입 : boolean 매개변수 : String str - 검사할문자열 [Hint] String클래스의 charat(int i) 메서드를사용하면문자열의 i 번째위치한문자를얻을수있다. [ 연습문제]/ch6/Exercise6_22.java class Exercise6_22 { /* (1) isnumber 메서드를작성하시오. */ public static void main(string[] args) { String str = "123"; System.out.println(str+" 는숫자입니까? "+isnumber(str)); str = "1234o"; System.out.println(str+" 는숫자입니까? "+isnumber(str)); [ 실행결과] 123 는숫자입니까? true 1234o 는숫자입니까? false [6-23] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : max 기능 : 주어진 int 형배열의값중에서제일큰값을반환한다. 반환타입 : int 만일주어진배열이 null이거나크기가 0 인경우, -999999 를반환한다. 매개변수 : int[] arr - 최대값을구할배열 [ 연습문제]/ch6/Exercise6_23.java class Exercise6_23{ /* (1) max 메서드를작성하시오. */

44 Java의정석定石 public static void main(string[] args) { int[] data = {3,2,9,4,7; System.out.println(java.util.Arrays.toString(data)); System.out.println(" 최대값:"+max(data)); System.out.println(" 최대값:"+max(null)); System.out.println(" 최대값:"+max(new int[]{)); // 크기가 0인배열 [ 실행결과] [3, 2, 9, 4, 7] 최대값 :9 최대값 :-999999 최대값 :-999999 [6-24] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : abs 기능 : 주어진값의절대값을반환한다. 반환타입 : int 매개변수 : int value [ 연습문제]/ch6/Exercise6_24.java class Exercise6_24 { /* (1) abs 메서드를작성하시오. */ public static void main(string[] args) { int value = 5; System.out.println(value+" 의절대값:"+abs(value)); value = -10; System.out.println(value+" 의절대값:"+abs(value)); [ 실행결과] 5 의절대값:5-10 의절대값:10

Java의정석定石 45 Chapter 객체지향프로그래밍 II Object-oriented Programming II

46 Java의정석定石 [ 연습문제 ] [7-1] 섯다카드 20 장을포함하는섯다카드한벌(SutdaDeck 클래스) 을정의한것이다. 섯 다카드 20장을담는 SutdaCard 배열을초기화하시오. 단, 섯다카드는 1부터 10까지의숫자 가적힌카드가한쌍씩있고, 숫자가 1, 3, 8 인경우에는둘중의한장은광(Kwang) 이 어야한다. 즉, SutdaCard의인스턴스변수 iskwang의값이 true 이어야한다. [ 연습문제]/ch7/Exercise7_1.java class SutdaDeck { final int CARD_NUM = 20; SutdaCard[] cards = new SutdaCard[CARD_NUM]; SutdaDeck() { /* (1) 배열 SutdaCard 를적절히초기화하시오. */ class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; // info() 대신 Object클래스의 tostring() 을오버라이딩했다. public String tostring() { return num + ( iskwang? "K":""); class Exercise7_1 { public static void main(string args[]) { SutdaDeck deck = new SutdaDeck(); for(int i=0; i < deck.cards.length;i++) System.out.print(deck.cards[i]+","); 실행결과 [ ] 1K,2,3K,4,5,6,7,8K,9,10,1,2,3,4,5,6,7,8,9,10,

Java의정석定石 47 [7-2] 문제7-1의 SutdaDeck클래스에다음에정의된새로운메서드를추가하고테스트하 시오. [ 주의] Math.random() 을사용하는경우실행결과와다를수있음. 1. 메서드명 : shuffle 기능 : 배열 cards 에담긴카드의위치를뒤섞는다.(Math.random() 사용) 반환타입 : 없음 매개변수 : 없음 2. 메서드명 : pick 기능 : 배열 cards에서지정된위치의 SutdaCard 를반환한다. 반환타입 : SutdaCard 매개변수 : int index - 위치 3. 메서드명 : pick 기능 : 배열 cards에서임의의위치의 SutdaCard 를반환한다.(Math.random() 사용) 반환타입 : SutdaCard 매개변수 : 없음 [ 연습문제]/ch7/Exercise7_2.java class SutdaDeck { final int CARD_NUM = 20; SutdaCard[] cards = new SutdaCard[CARD_NUM]; SutdaDeck() { /* 문제 7-1의답이므로내용생략 */ /* (1) 위에정의된세개의메서드를작성하시오. */ // SutdaDeck class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public String tostring() {

48 Java의정석定石 return num + ( iskwang? "K":""); class Exercise7_2 { public static void main(string args[]) { SutdaDeck deck = new SutdaDeck(); System.out.println(deck.pick(0)); System.out.println(deck.pick()); deck.shuffle(); for(int i=0; i < deck.cards.length;i++) System.out.print(deck.cards[i]+","); System.out.println(); System.out.println(deck.pick(0)); 실행결과 [ ] 1K 7 2,6,10,1K,7,3,10,5,7,8,5,1,2,9,6,9,4,8K,4,3K, 2 [7-3] 오버라이딩의정의와필요성에대해서설명하시오. [7-4] 다음중오버라이딩의조건으로옳지않은것은? ( 모두고르시오) a. 조상의메서드와이름이같아야한다. b. 매개변수의수와타입이모두같아야한다. c. 접근제어자는조상의메서드보다좁은범위로만변경할수있다. d. 조상의메서드보다더많은수의예외를선언할수있다.

Java의정석定石 49 [7-5] 다음의코드는컴파일하면에러가발생한다. 그이유를설명하고에러를수정하기 위해서는코드를어떻게바꾸어야하는가? [ 연습문제]/ch7/Exercise7_5.java class Product { int price; // 제품의가격 int bonuspoint; // 제품구매시제공하는보너스점수 Product(int price) { this.price = price; bonuspoint =(int)(price/10.0); class Tv extends Product { Tv() { public String tostring() { return "Tv"; class Exercise7_5 { public static void main(string[] args) { Tv t = new Tv(); [7-6] 자손클래스의생성자에서조상클래스의생성자를호출해야하는이유는무엇인 가?

50 Java의정석定石 [7-7] 다음코드의실행했을때호출되는생성자의순서와실행결과를적으시오. [ 연습문제]/ch7/Exercise7_7.java class Parent { int x=100; Parent() { this(200); Parent(int x) { this.x = x; int getx() { return x; class Child extends Parent { int x = 3000; Child() { this(1000); Child(int x) { this.x = x; class Exercise7_7 { public static void main(string[] args) { Child c = new Child(); System.out.println("x="+c.getX());

Java의정석定石 51 [7-8] 다음중접근제어자를접근범위가넓은것에서좁은것의순으로바르게나열한것은? a. public-protected-(default)-private b. public-(default)-protected-private c. (default)-public-protected-private d. private-protected-(default)-public [7-9] 다음중제어자 final 을붙일수있는대상과붙였을때그의미를적은것이다. 옳지않은것은? ( 모두고르시오) a. 지역변수 - 값을변경할수없다. b. 클래스 - 상속을통해클래스에새로운멤버를추가할수없다. c. 메서드 - 오버로딩을할수없다. d. 멤버변수 - 값을변경할수없다. [7-10] MyTv2클래스의멤버변수 ispoweron, channel, volume을클래스외부에서접근할 수없도록제어자를붙이고대신이멤버변수들의값을어디서나읽고변경할수있도록 getter와 setter 메서드를추가하라. [ 연습문제]/ch7/Exercise7_10.java class MyTv2 { boolean ispoweron; int channel; int volume; final int MAX_VOLUME = 100; final int MIN_VOLUME = 0; final int MAX_CHANNEL = 100; final int MIN_CHANNEL = 1; /* */ (1) 알맞은코드를넣어완성하시오. class Exercise7_10 { public static void main(string args[]) { MyTv2 t = new MyTv2(); t.setchannel(10); System.out.println("CH:"+t.getChannel()); t.setvolume(20); System.out.println("VOL:"+t.getVolume()); 실행결과 [ ] CH:10 VOL:20

52 Java의정석定石 [7-11] 문제7-10에서작성한 MyTv2 클래스에이전채널(previous channel) 로이동하는 기능의메서드를추가해서실행결과와같은결과를얻도록하시오. [Hint] 이전채널의값을저장할멤버변수를정의하라. 메서드명 : gotoprevchannel 기능 : 현재채널을이전채널로변경한다. 반환타입 : 없음 매개변수 : 없음 [ 연습문제]/ch7/Exercise7_11.java class MyTv2 { /* (1) 문제7-10의 MyTv2클래스에 gotoprevchannel 메서드를추가하여완성하시오. */ class Exercise7_11 { public static void main(string args[]) { MyTv2 t = new MyTv2(); t.setchannel(10); System.out.println("CH:"+t.getChannel()); t.setchannel(20); System.out.println("CH:"+t.getChannel()); t.gotoprevchannel(); System.out.println("CH:"+t.getChannel()); t.gotoprevchannel(); System.out.println("CH:"+t.getChannel()); 실행결과 [ ] CH:10 CH:20 CH:10 CH:20 [7-12] 다음중접근제어자에대한설명으로옳지않은것은? ( 모두고르시오) a. public 은접근제한이전혀없는접근제어자이다. b. (default) 가붙으면, 같은패키지내에서만접근이가능하다. c. 지역변수에도접근제어자를사용할수있다. d. protected 가붙으면, 같은패키지내에서도접근이가능하다. e. protected 가붙으면, 다른패키지의자손클래스에서접근이가능하다. [7-13] Math클래스의생성자는접근제어자가 private 이다. 그이유는무엇인가?

Java의정석定石 53 [7-14] 문제7-1 에나오는섯다카드의숫자와종류(isKwang) 는사실한번값이지정되면 변경되어서는안되는값이다. 카드의숫자가한번잘못바뀌면똑같은카드가두장이 될수도있기때문이다. 이러한문제점이발생하지않도록아래의 SutdaCard를수정하시 오. [ 연습문제]/ch7/Exercise7_14.java class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public String tostring() { return num + ( iskwang? "K":""); class Exercise7_14 { public static void main(string args[]) { SutdaCard card = new SutdaCard(1, true); [7-15] 클래스가다음과같이정의되어있을때, 형변환을올바르게하지않은것은? ( 모두고르시오.) class Unit { class AirUnit extends Unit { class GroundUnit extends Unit { class Tank extends GroundUnit { class AirCraft extends AirUnit { Unit u = new GroundUnit(); Tank t = new Tank(); AirCraft ac = new AirCraft(); a. u = (Unit)ac; b. u = ac; c. GroundUnit gu = (GroundUnit)u; d. AirUnit au = ac; e. t = (Tank)u; f. GroundUnit gu = t;

54 Java의정석定石 [7-16] 다음중연산결과가 true 가아닌것은? ( 모두고르시오) class Car { class FireEngine extends Car implements Movable { class Ambulance extends Car { FireEngine fe = new FireEngine(); a. fe instanceof FireEngine b. fe instanceof Movable c. fe instanceof Object d. fe instanceof Car e. fe instanceof Ambulance [7-17] 아래세개의클래스로부터공통부분을뽑아서 Unit 이라는클래스를만들고, 이 클래스를상속받도록코드를변경하시오. class Marine { // 보병 int x, y; // 현재위치 void move(int x, int y) { /* 지정된위치로이동 */ void stop() { /* 현재위치에정지 */ void stimpack() { /* 스팀팩을사용한다.*/ class Tank { // 탱크 int x, y; // 현재위치 void move(int x, int y) { /* 지정된위치로이동 */ void stop() { /* 현재위치에정지 */ void changemode() { /* 공격모드를변환한다. */ class Dropship { // 수송선 int x, y; // 현재위치 void move(int x, int y) { /* 지정된위치로이동 */ void stop() { /* 현재위치에정지 */ void load() { /* 선택된대상을태운다.*/ void unload() { /* 선택된대상을내린다.*/

Java의정석定石 55 [7-18] 다음과같은실행결과를얻도록코드를완성하시오. [Hint] instanceof 연산자를사용해서형변환한다. 메서드명 : action 기능 : 주어진객체의메서드를호출한다. 반환타입 : 없음 DanceRobot 인경우, dance() 를호출하고, SingRobot 인경우, sing() 을호출하고, DrawRobot 인경우, draw() 를호출한다. 매개변수 : Robot r - Robot인스턴스또는 Robot의자손인스턴스 [ 연습문제]/ch7/Exercise7_18.java class Exercise7_18 { /* (1) action 메서드를작성하시오. */ public static void main(string[] args) { Robot[] arr = { new DanceRobot(), new SingRobot(), new DrawRobot(); for(int i=0; i< arr.length;i++) action(arr[i]); // main class Robot { class DanceRobot extends Robot { void dance() { System.out.println(" 춤을춥니다."); class SingRobot extends Robot { void sing() { System.out.println(" 노래를합니다."); class DrawRobot extends Robot { void draw() { System.out.println(" 그림을그립니다."); 실행결과 [ ] 춤을춥니다. 노래를합니다. 그림을그립니다.

56 Java의정석定石 [7-19] 다음은물건을구입하는사람을정의한 Buyer 클래스이다. 이클래스는멤버변수 로돈(money) 과장바구니(cart) 를가지고있다. 제품을구입하는기능의 buy메서드와장 바구니에구입한물건을추가하는 add 메서드, 구입한물건의목록과사용금액, 그리고남 은금액을출력하는 summary 메서드를완성하시오. 1. 메서드명 : buy 기능 : 지정된물건을구입한다. 가진돈(money) 에서물건의가격을빼고, 반환타입 : 없음 장바구니(cart) 에담는다. 만일가진돈이물건의가격보다적다면바로종료한다. 매개변수 : Product p - 구입할물건 2. 메서드명 : add 기능 : 지정된물건을장바구니에담는다. 반환타입 : 없음 만일장바구니에담을공간이없으면, 장바구니의크기를 2 배로늘린다음에담는다. 매개변수 : Product p - 구입할물건 3. 메서드명 : summary 기능 : 구입한물건의목록과사용금액, 남은금액을출력한다. 반환타입 : 없음 매개변수 : 없음 [ 연습문제]/ch7/Exercise7_19.java class Exercise7_19 { public static void main(string args[]) { Buyer b = new Buyer(); b.buy(new Tv()); b.buy(new Computer()); b.buy(new Tv()); b.buy(new Audio()); b.buy(new Computer()); b.buy(new Computer()); b.buy(new Computer()); b.summary(); class Buyer { int money = 1000; Product[] cart = new Product[3]; // 구입한제품을저장하기위한배열 int i = 0; // Product배열 cart에사용될 index void buy(product p) { /* (1) 아래의로직에맞게코드를작성하시오. 1.1 가진돈과물건의가격을비교해서가진돈이적으면메서드를종료한다. 1.2 가진돈이충분하면, 제품의가격을가진돈에서빼고 1.3 장바구니에구입한물건을담는다.(add 메서드호출)

Java의정석定石 57 */ void add(product p) { /* (2) 아래의로직에맞게코드를작성하시오. 1.1 i의값이장바구니의크기보다같거나크면 1.1.1 기존의장바구니보다 2 배큰새로운배열을생성한다. 1.1.2 기존의장바구니의내용을새로운배열에복사한다. 1.1.3 새로운장바구니와기존의장바구니를바꾼다. 1.2 물건을장바구니(cart) 에저장한다. 그리고 i의값을 1 증가시킨다. */ // add(product p) void summary() { /* (3) 아래의로직에맞게코드를작성하시오. 1.1 장바구니에담긴물건들의목록을만들어출력한다. 1.2 장바구니에담긴물건들의가격을모두더해서출력한다. 1.3 물건을사고남은금액(money) 를출력한다. */ // summary() class Product { int price; // 제품의가격 Product(int price) { this.price = price; class Tv extends Product { Tv() { super(100); public String tostring() { return "Tv"; class Computer extends Product { Computer() { super(200); public String tostring() { return "Computer"; class Audio extends Product { Audio() { super(50); public String tostring() { return "Audio"; [ 실행결과] 잔액이부족하여 Computer 을/ 를살수없습니다. 구입한물건 :Tv,Computer,Tv,Audio,Computer,Computer, 사용한금액 :850 남은금액 :150

58 Java의정석定石 [7-20] 다음의코드를실행한결과를적으시오. [ 연습문제]/ch7/Exercise7_20.java class Exercise7_20 { public static void main(string[] args) { Parent p = new Child(); Child c = new Child(); System.out.println("p.x = " + p.x); p.method(); System.out.println("c.x = " + c.x); c.method(); class Parent { int x = 100; void method() { System.out.println("Parent Method"); class Child extends Parent { int x = 200; void method() { System.out.println("Child Method"); [7-21] 다음과같이 attack 메서드가정의되어있을때, 이메서드의매개변수로가능한 것두가지를적으시오. interface Movable { void move(int x, int y); void attack(movable f) { /* 내용생략 */

Java의정석定石 59 [7-22] 아래는도형을정의한 Shape 클래스이다. 이클래스를조상으로하는 Circle클래 스와 Rectangle 클래스를작성하시오. 이때, 생성자도각클래스에맞게적절히추가해야 한다. (1) 클래스명 : Circle 조상클래스 : Shape 멤버변수 : double r - 반지름 (2) 클래스명 : Rectangle 조상클래스 : Shape 멤버변수 메서드 : : double width - 폭 double height - 높이 1. 메서드명 : issquare 기능 : 정사각형인지아닌지를알려준다. 반환타입 : boolean 매개변수 : 없음 [ 연습문제]/ch7/Exercise7_22.java abstract class Shape { Point p; Shape() { this(new Point(0,0)); Shape(Point p) { this.p = p; abstract double calcarea(); // 도형의면적을계산해서반환하는메서드 Point getposition() { return p; void setposition(point p) { this.p = p; class Point { int x; int y; Point() { this(0,0); Point(int x, int y) { this.x=x; this.y=y;

60 Java의정석定石 public String tostring() { return "["+x+","+y+"]"; [7-23] 문제7-22에서정의한클래스들의면적을구하는메서드를작성하고테스트하시 오. 1. 메서드명 : sumarea 기능 : 주어진배열에담긴도형들의넓이를모두더해서반환한다. 반환타입 : double 매개변수 : Shape[] arr [ 연습문제]/ch7/Exercise7_23.java class Exercise7_23 { /* (1) sumarea 메서드를작성하시오. */ public static void main(string[] args) { Shape[] arr = {new Circle(5.0), new Rectangle(3,4), new Circle(1); System.out.println(" 면적의합:"+sumArea(arr)); 실행결과 [ ] 면적의합 :93.68140899333463 [7-24] 다음중인터페이스의장점이아닌것은? a. 표준화를가능하게해준다. b. 서로관계없는클래스들에게관계를맺어줄수있다. c. 독립적인프로그래밍이가능하다. d. 다중상속을가능하게해준다. e. 패키지간의연결을도와준다.

Java의정석定石 61 [7-25] Outer클래스의내부클래스 Inner의멤버변수 iv 의값을출력하시오. [ 연습문제]/ch7/Exercise7_25.java class Outer { class Inner { int iv=100; class Exercise7_25 { public static void main(string[] args) { /* (1) 알맞은코드를넣어완성하시오. */ [ 실행결과] 100 [7-26] Outer클래스의내부클래스 Inner의멤버변수 iv 의값을출력하시오. [ 연습문제]/ch10/Exercise7_26.java class Outer { static class Inner { int iv=200; class Exercise7_26 { public static void main(string[] args) { /* (1) 알맞은코드를넣어완성하시오. */ 실행결과 [ ] 200

62 Java의정석定石 [7-27] 다음과같은실행결과를얻도록 (1)~(4) 의코드를완성하시오. [ 연습문제]/ch7/Exercise7_27.java class Outer { int value=10; class Inner { int value=20; void method1() { int value=30; System.out.println(/* (1) */); System.out.println(/* (2) */); System.out.println(/* (3) */); // Inner클래스의끝 // Outer클래스의끝 class Exercise7_27 { public static void main(string args[]) { /* (4) 알맞은코드를넣어완성하시오. */ inner.method1(); 실행결과 [ ] 30 20 10

Java의정석定石 63 [7-28] 아래의 EventHandler 를익명클래스(anonymous class) 로변경하시오. [ 연습문제]/ch7/Exercise7_28.java import java.awt.*; import java.awt.event.*; class Exercise7_28 { public static void main(string[] args) { Frame f = new Frame(); f.addwindowlistener(new EventHandler()); class EventHandler extends WindowAdapter { public void windowclosing(windowevent e) { e.getwindow().setvisible(false); e.getwindow().dispose(); System.exit(0); [7-29] 지역클래스에서외부클래스의인스턴스멤버와 static멤버에모두접근할수 있지만, 지역변수는 final 이붙은상수만접근할수있는이유무엇인가?

64 Java의정석定石 Chapter 예외처리 Exception Handling

Java의정석定石 65 [ 연습문제 ] [8-1] 예외처리의정의와목적에대해서설명하시오. [8-2] 다음은실행도중예외가발생하여화면에출력된내용이다. 이에대한설명중옳 지않은것은? java.lang.arithmeticexception : / by zero at ExceptionEx18.method2(ExceptionEx18.java:12) at ExceptionEx18.method1(ExceptionEx18.java:8) at ExceptionEx18.main(ExceptionEx18.java:4) a. 위의내용으로예외가발생했을당시호출스택에존재했던메서드를알수있다. b. 예외가발생한위치는 method2 메서드이며, ExceptionEx18.java파일의 12 번째줄이다. c. 발생한예외는 ArithmeticException 이며, 0 으로나누어서예외가발생했다. d. method2메서드가 method1메서드를호출하였고그위치는 ExceptionEx18.java파일의 8 번째줄이다. [8-3] 다음중오버라이딩이잘못된것은? ( 모두고르시오) void add(int a, int b) throws InvalidNumberException, NotANumberException { class NumberException extends Exception { class InvalidNumberException extends NumberException { class NotANumberException extends NumberException { a. void add(int a, int b) throws InvalidNumberException, NotANumberException { b. void add(int a, int b) throws InvalidNumberException { c. void add(int a, int b) throws NotANumberException { d. void add(int a, int b) throws Exception { e. void add(int a, int b) throws NumberException {

66 Java의정석定石 [8-4] 다음과같은메서드가있을때, 예외를잘못처리한것은? ( 모두고르시오) void method() throws InvalidNumberException, NotANumberException { class NumberException extends RuntimeException { class InvalidNumberException extends NumberException { class NotANumberException extends NumberException { a. try {method(); catch(exception e) { b. try {method(); catch(numberexception e) { catch(exception e) { c. try {method(); catch(exception e) { catch(numberexception e) { d. try {method(); catch(invalidnumberexception e) { catch(notanumberexception e) { e. try {method(); catch(numberexception e) { f. try {method(); catch(runtimeexception e) { [8-5] 아래의코드가수행되었을때의실행결과를적으시오. [ 연습문제]/ch8/Exercise8_5.java class Exercise8_5 { static void method(boolean b) { try { System.out.println(1); if(b) throw new ArithmeticException(); System.out.println(2); catch(runtimeexception r) { System.out.println(3); return; catch(exception e) { System.out.println(4); return; finally { System.out.println(5); System.out.println(6); public static void main(string[] args) { method(true); method(false); // main

Java의정석定石 67 [8-6] 아래의코드가수행되었을때의실행결과를적으시오. [ 연습문제]/ch8/Exercise8_6.java class Exercise8_6 { public static void main(string[] args) { try { method1(); catch(exception e) { System.out.println(5); static void method1() { try { method2(); System.out.println(1); catch(arithmeticexception e) { System.out.println(2); finally { System.out.println(3); System.out.println(4); // method1() static void method2() { throw new NullPointerException();

68 Java의정석定石 [8-7] 아래의코드가수행되었을때의실행결과를적으시오. [ 연습문제]/ch8/Exercise8_7.java class Exercise8_7 { static void method(boolean b) { try { System.out.println(1); if(b) System.exit(0); System.out.println(2); catch(runtimeexception r) { System.out.println(3); return; catch(exception e) { System.out.println(4); return; finally { System.out.println(5); System.out.println(6); public static void main(string[] args) { method(true); method(false); // main

Java의정석定石 69 [8-8] 다음은 1~100사이의숫자를맞추는게임을실행하던도중에숫자가아닌영문자를 넣어서발생한예외이다. 예외처리를해서숫자가아닌값을입력했을때는다시입력을 받도록보완하라. 1과 100 사이의값을입력하세요 :50 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :asdf Exception in thread "main" java.util.inputmismatchexception at java.util.scanner.throwfor(scanner.java:819) at java.util.scanner.next(scanner.java:1431) at java.util.scanner.nextint(scanner.java:2040) at java.util.scanner.nextint(scanner.java:2000) at Exercise8_8.main(Exercise8_8.java:16) [ 연습문제]/ch8/Exercise8_8.java import java.util.*; class Exercise8_8 { public static void main(string[] args) { // 1~100사이의임의의값을얻어서 answer 에저장한다. int answer = (int)(math.random() * 100) + 1; int input = 0; // 사용자입력을저장할공간 int count = 0; // 시도횟수를세기위한변수 do { count++; System.out.print("1과 100 사이의값을입력하세요 :"); input = new Scanner(System.in).nextInt(); if(answer > input) { System.out.println(" 더큰수를입력하세요."); else if(answer < input) { System.out.println(" 더작은수를입력하세요."); else { System.out.println(" 맞췄습니다."); System.out.println(" 시도횟수는 "+count+" 번입니다."); break; // do-while문을벗어난다 while(true); // 무한반복문 // end of main // end of class HighLow [ 실행결과] 1과 100 사이의값을입력하세요 :50 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :asdf 유효하지않은값입니다. 다시값을입력해주세요. 1과 100 사이의값을입력하세요 :25 더큰수를입력하세요.

70 Java의정석定石 1과 100 사이의값을입력하세요 :38 더큰수를입력하세요. 1과 100 사이의값을입력하세요 :44 맞췄습니다. 시도횟수는 5 번입니다. [8-9] 다음과같은조건의예외클래스를작성하고테스트하시오. [ 참고] 생성자는실행결과를보고알맞게작성해야한다. * 클래스명 : UnsupportedFuctionException * 조상클래스명 : RuntimeException * 멤버변수 : 이 름 : ERR_CODE 저장값 : 에러코드 타 입 : int 기본값 : 100 제어자 : final private * 메서드 : 1. 메서드명 : geterrorcode 기능 : 에러코드(ERR_CODE) 를반환한다. 반환타입 : int 매개변수 : 없음 제어자 : public 2. 메서드명 : getmessage 기능 : 메세지의내용을반환한다.(Exception클래스의 getmessage() 를오버라이딩) 반환타입 : String 매개변수 : 없음 제어자 : public [ 연습문제]/ch8/Exercise8_9.java class Exercise8_9 { public static void main(string[] args) throws Exception { throw new UnsupportedFuctionException(" 지원하지않는기능입니다.",100); 실행결과 [ ] Exception in thread "main" UnsupportedFuctionException: [100] 지원하지않는기능입니다. at Exercise8_9.main(Exercise8_9.java:5)

Java의정석定石 71 [8-10] 아래의코드가수행되었을때의실행결과를적으시오. [ 연습문제]/ch8/Exercise8_10.java class Exercise8_10 { public static void main(string[] args) { try { method1(); System.out.println(6); catch(exception e) { System.out.println(7); static void method1() throws Exception { try { method2(); System.out.println(1); catch(nullpointerexception e) { System.out.println(2); throw e; catch(exception e) { System.out.println(3); finally { System.out.println(4); System.out.println(5); // method1() static void method2() { throw new NullPointerException();

72 Java의정석定石 Chapter java.lang 패키지와유용한클래스 java.lang package & util classes

Java의정석定石 73 [ 연습문제 ] [9-1] 다음과같은실행결과를얻도록 SutdaCard클래스의 equals() 를멤버변수인 num, iskwang 의값을비교하도록오버라이딩하고테스트하시오. [ 연습문제]/ch9/Exercise9_1.java class Exercise9_1 { public static void main(string[] args) { SutdaCard c1 = new SutdaCard(3,true); SutdaCard c2 = new SutdaCard(3,true); System.out.println("c1="+c1); System.out.println("c2="+c2); System.out.println("c1.equals(c2):"+c1.equals(c2)); class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public boolean equals(object obj) { /* (1) 매개변수로넘겨진객체의 num, iskwang과멤버변수 num, iskwang 을비교하도록오버라이딩하시오. */ public String tostring() { return num + ( iskwang? "K":""); 실행결과 [ ] c1=3k c2=3k c1.equals(c2):true

74 Java의정석定石 [9-2] 다음과같은실행결과를얻도록 Point3D클래스의 equals() 를멤버변수인 x, y, z 의값을비교하도록오버라이딩하고, tostring() 은실행결과를참고해서적절히오버라이 딩하시오. [ 연습문제]/ch9/Exercise9_2.java class Exercise9_2 { public static void main(string[] args) { Point3D p1 = new Point3D(1,2,3); Point3D p2 = new Point3D(1,2,3); System.out.println(p1); System.out.println(p2); System.out.println("p1==p2?"+(p1==p2)); System.out.println("p1.equals(p2)?"+(p1.equals(p2))); class Point3D { int x,y,z; Point3D(int x, int y, int z) { this.x=x; this.y=y; this.z=z; Point3D() { this(0,0,0); public boolean equals(object obj) { /* (1) 인스턴스변수 x, y, z 를비교하도록오버라이딩하시오. */ public String tostring() { /* (2) 인스턴스변수 x, y, z 의내용을출력하도록오버라이딩하시오. */ 실행결과 [ ] [1,2,3] [1,2,3] p1==p2?false p1.equals(p2)?true

Java의정석定石 75 [9-3] 다음과같은실행결과가나오도록코드를완성하시오. [ 연습문제]/ch9/Exercise9_3.java class Exercise9_3 { public static void main(string[] args) { String fullpath = "c:\\jdk1.8\\work\\pathseparatetest.java"; String path = ""; String filename = ""; /* */ (1) 알맞은코드를넣어완성하시오. System.out.println("fullPath:"+fullPath); System.out.println("path:"+path); System.out.println("fileName:"+fileName); [ 실행결과] fullpath:c:\jdk1.8\work\pathseparatetest.java path:c:\jdk1.8\work filename:pathseparatetest.java [9-4] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : printgraph 기능 : 주어진배열에담긴값만큼주어진문자를가로로출력한후, 값을출력한다. 반환타입 : 없음 매개변수 : int[] dataarr - 출력할그래프의데이터 char ch - 그래프로출력할문자. [ 연습문제]/ch9/Exercise9_4.java class Exercise9_4 { static void printgraph(int[] dataarr, char ch) { /* (1) printgraph 메서드를작성하시오. */ public static void main(string[] args) { printgraph(new int[]{3,7,1,4,'*'); 실행결과 [ ] ***3 *******7 *1 ****4

76 Java의정석定石 [9-5] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : count 기능 : 주어진문자열(src) 에찾으려는문자열(target) 이몇번나오는지세어서반환한다. 반환타입 : int 매개변수 : String src String target [Hint] String클래스의 indexof(string str, int fromindex) 를사용할것 [ 연습문제]/ch9/Exercise9_5.java class Exercise9_5 { public static int count(string src, String target) { int count = 0; // 찾은횟수 int pos = 0; // 찾기시작할위치 /* */ (1) 반복문을사용해서아래의과정을반복한다. 1. src에서 target을 pos 의위치부터찾는다. 2. 찾으면 count의값을 1 증가시키고, pos의값을 target.length 만큼증가시킨다. 3. indexof의결과가 -1이면반복문을빠져나가서 count 를반환한다. public static void main(string[] args) { System.out.println(count("12345AB12AB345AB","AB")); System.out.println(count("12345","AB")); 실행결과 [ ] 3 0 [9-6] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : fillzero 기능 : 주어진문자열( 숫자) 로주어진길이의문자열로만들고, 왼쪽빈공간은 '0' 으로 채운다. 만일주어진문자열이 null이거나문자열의길이가 length의값과같으면그대로 반환한다. 반환타입 : String 만일주어진 length의값이 0 보다같거나작은값이면, 빈문자열("") 을반환한다. 매개변수 : String src - 변환할문자열 int length - 변환한문자열의길이

Java의정석定石 77 [ 연습문제]/ch9/Exercise9_6.java class Exercise9_6 { public static String fillzero(string src, int length) { /* (1) fillzero 메서드를작성하시오. 1. src가널이거나 src.length() 가 length와같으면 src 를그대로반환한다. 2. length의값이 0 보다같거나작으면빈문자열("") 을반환한다. 3. src의길이가 length의값보다크면 src를 length 만큼잘라서반환한다. 4. 길이가 length인 char 배열을생성한다. 5. 4에서생성한 char 배열을 '0' 으로채운다. 6. src에서문자배열을뽑아내서 4 에서생성한배열에복사한다. 7. 4에서생성한배열로 String 을생성해서반환한다. */ public static void main(string[] args) { String src = "12345"; System.out.println(fillZero(src,10)); System.out.println(fillZero(src,-1)); System.out.println(fillZero(src,3)); [ 실행결과] 0000012345 123 [9-7] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : contains 기능 : 첫번째문자열(src) 에두번째문자열(target) 이포함되어있는지확인한다. 반환타입 : boolean 매개변수 : String src 포함되어있으면 true, 그렇지않으면 false 를반환한다. String target [Hint] String클래스의 indexof() 를사용할것 [ 연습문제]/ch9/Exercise9_7.java class Exercise9_7 { /* (1) contains 메서드를작성하시오. */ public static void main(string[] args) { System.out.println(contains("12345","23")); System.out.println(contains("12345","67")); 실행결과 [ ] true false

78 Java의정석定石 [9-8] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : round 기능 : 주어진값을반올림하여, 소수점이하 n 자리의값을반환한다. 반환타입 : double 예를들어 n의값이 3 이면, 소수점 4째자리에서반올림하여소수점이하 3자리의 수를반환한다. 매개변수 : double d - 변환할값 int n - 반올림한결과의소수점자리 [Hint] Math.round() 와 Math.pow() 를이용하라. [ 연습문제]/ch9/Exercise9_8.java class Exercise9_8 { /* (1) round 메서드를작성하시오. */ public static void main(string[] args) { System.out.println(round(3.1415,1)); System.out.println(round(3.1415,2)); System.out.println(round(3.1415,3)); System.out.println(round(3.1415,4)); System.out.println(round(3.1415,5)); 실행결과 [ ] 3.1 3.14 3.142 3.1415 3.1415

Java의정석定石 79 [9-9] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : delchar 기능 : 주어진문자열에서금지된문자들을제거하여반환한다. 반환타입 : String 매개변수 : String src - 변환할문자열 String delch - 제거할문자들로구성된문자열 [ 힌트] StringBuffer와 String클래스의 charat(int i) 과 indexof(int ch) 를사용하라. [ 연습문제]/ch9/Exercise9_9.java class Exercise9_9 { /* (1) delchar 메서드를작성하시오. */ public static void main(string[] args) { System.out.println("(1!2@3^4~5)"+" -> " + delchar("(1!2@3^4~5)","~!@#$%^&*()")); System.out.println("(1 2 3 4\t5)"+" -> " + delchar("(1 2 3 4\t5)"," \t")); 실행결과 [ ] (1!2@3^4~5) -> 12345 (1 2 3 4 5) -> (12345)

80 Java의정석定石 [9-10] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : format 기능 : 주어진문자열을지정된크기의문자열로변환한다. 나머지공간은공백으로채운다. 반환타입 : String 매개변수 : String str - 변환할문자열 int length - 변환된문자열의길이 int alignment - 변환된문자열의정렬조건 (0: 왼쪽정렬, 1: 가운데정렬, 2: 오른쪽정렬) [ 연습문제]/ch9/Exercise9_10.java class Exercise9_10 { /* (1) format 메서드를작성하시오. 1. length의값이 str의길이보다작으면 length 만큼만잘라서반환한다. 2. 1 의경우가아니면, length크기의 char 배열을생성하고공백으로채운다. 3. 정렬조건(alignment) 의값에따라문자열(str) 을복사할위치를결정한다. (System.arraycopy() 사용) 4. 2에서생성한 char 배열을문자열로만들어서반환한다. */ public static void main(string[] args) { String str = " 가나다"; System.out.println(format(str,7,0)); // 왼쪽정렬 System.out.println(format(str,7,1)); // 가운데정렬 System.out.println(format(str,7,2)); // 오른쪽정렬 실행결과 [ ] 가나다가나다가나다

Java의정석定石 81 [9-11] 커맨드라인으로 2~9사이의두개의숫자를받아서두숫자사이의구구단을출력 하는프로그램을작성하시오. 예를들어 3과 5를입력하면 3단부터 5 단까지출력한다. [ 실행결과] C:\jdk1.8\work\ch9>java Exercise9_11 2 시작단과끝단, 두개의정수를입력해주세요. USAGE : GugudanTest 3 5 C:\jdk1.8\work\ch9>java Exercise9_11 1 5 단의범위는 2와 9 사이의값이어야합니다. USAGE : GugudanTest 3 5 C:\jdk1.8\work\ch9>java Exercise9_11 3 5 3*1=3 3*2=6 3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27 4*1=4 4*2=8 4*3=12 4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45

82 Java의정석定石 [9-12] 다음과같이정의된메서드를작성하고테스트하시오. [ 주의] Math.random() 을사용하는경우실행결과와다를수있음. 메서드명 : getrand 기능 : 주어진범위(from~to) 에속한임의의정수값을반환한다. 반환타입 : int ( 양쪽경계값모두범위에포함) from의값이 to 의값보다클경우도처리되어야한다. 매개변수 : int from - 범위의시작값 int to - 범위의끝값 [Hint] Math.random() 과절대값을반환하는 Math.abs(int a), 그리고둘중에작은값을반환하는 Math.min(int a, int b) 를사용하라. [ 연습문제]/ch9/Exercise9_12.java class Exercise9_12 { /* (1) getrand 메서드를작성하시오. */ public static void main(string[] args) { for(int i=0; i< 20; i++) System.out.print(getRand(1,-3)+","); 실행결과 [ ] 0,-1,1,0,-2,-2,1,1,-3,0,-1,1,1,1,0,-1,1,0,-1,-3,

Java의정석定石 83 [9-13] 다음은하나의긴문자열(source) 중에서특정문자열과일치하는문자열의개수 를구하는예제이다. 빈곳을채워예제를완성하시오. [ 연습문제]/ch9/Exercise9_13.java public class Exercise9_13 { public static void main(string[] args) { String src = "aabbccaabbccaa"; System.out.println(src); System.out.println("aa 를 " + stringcount(src, "aa") +" 개찾았습니다."); static int stringcount(string src, String key) { return stringcount(src, key, 0); static int stringcount(string src, String key, int pos) { int count = 0; int index = 0; if (key == null key.length() == 0) return 0; /* */ (1) 알맞은코드를넣어완성하시오. return count; [ 실행결과] aabbccaabbccaa aa를 2 개찾았습니다. [9-14] 다음은화면으로부터전화번호의일부를입력받아일치하는전화번호를주어진 문자열배열에서찾아서출력하는프로그램이다. 알맞은코드를넣어프로그램을완성하 시오. [Hint] Pattern, Matcher클래스를사용할것 [ 연습문제]/ch9/Exercise9_14.java import java.util.*; import java.util.regex.*; class Exercise9_14 { public static void main(string[] args) { String[] phonenumarr = { "012-3456-7890", "099-2456-7980", "088-2346-9870", "013-3456-7890" ;

84 Java의정석定石 ArrayList list = new ArrayList(); Scanner s = new Scanner(System.in); while(true) { System.out.print(">>"); String input = s.nextline().trim(); if(input.equals("")) { continue; else if(input.equalsignorecase("q")) { System.exit(0); /* */ (1) 알맞은코드를넣어완성하시오. if(list.size()>0) { System.out.println(list); list.clear(); else { System.out.println(" 일치하는번호가없습니다."); // main 실행결과 [ ] >> >> >>asdf 일치하는번호가없습니다. >> >> >>0 [012-3456-7890, 099-2456-7980, 088-2346-9870, 013-3456-7890] >>234 [012-3456-7890, 088-2346-9870] >>7890 [012-3456-7890, 013-3456-7890] >>q

Java의정석定石 85 Chapter 날짜와시간 & 형식화 date, time and formatting

86 Java의정석定石 [ 연습문제 ] [10-1] Calendar클래스와 SimpleDateFormat클래스를이용해서 2010년의매월두번째 일요일의날짜를출력하시오. [ 실행결과] 2010-01-10은 2 번째일요일입니다. 2010-02-14은 2 번째일요일입니다. 2010-03-14은 2 번째일요일입니다. 2010-04-11은 2 번째일요일입니다. 2010-05-09은 2 번째일요일입니다. 2010-06-13은 2 번째일요일입니다. 2010-07-11은 2 번째일요일입니다. 2010-08-08은 2 번째일요일입니다. 2010-09-12은 2 번째일요일입니다. 2010-10-10은 2 번째일요일입니다. 2010-11-14은 2 번째일요일입니다. 2010-12-12은 2 번째일요일입니다. [10-2] 어떤회사의월급날이매월 21 일이다. 두날짜사이에월급날이몇번있는지계 산해서반환하는메서드를작성하고테스트하시오. [ 연습문제]/ch10/Exercise10_2.java import java.util.*; import java.text.*; class Exercise10_2 { static int paycheckcount(calendar from, Calendar to) { /* (1) 아래의로직에맞게코드를작성하시오. 1. from 또는 to가 null이면 0 을반환한다. 2. from와 to가같고날짜가 21일이면 1 을반환한다. 3. to와 from이몇개월차이인지계산해서변수 mondiff 에담는다. 4. mondiff가음수이면 0 을반환한다. 5. 만일 from 의일(DAY_OF_MONTH) 이 21일이거나이전이고 to 의일(DAY_OF_MONTH) 이 21일이거나이후이면 mondiff의값을 1 증가시킨다. 6. 만일 from 의일(DAY_OF_MONTH) 이 21일이후고 to 의일(DAY_OF_MONTH) 이 21일이전이면 mondiff의값을 1 감소시킨다. */ return mondiff; static void printresult(calendar from, Calendar to) { Date fromdate = from.gettime(); Date todate = to.gettime(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

Java의정석定石 87 System.out.print(sdf.format(fromDate)+" ~ " +sdf.format(todate)+":"); System.out.println(paycheckCount(from, to)); public static void main(string[] args) { Calendar fromcal = Calendar.getInstance(); Calendar tocal = Calendar.getInstance(); fromcal.set(2010,0,1); tocal.set(2010,0,1); printresult(fromcal, tocal); fromcal.set(2010,0,21); tocal.set(2010,0,21); printresult(fromcal, tocal); fromcal.set(2010,0,1); tocal.set(2010,2,1); printresult(fromcal, tocal); fromcal.set(2010,0,1); tocal.set(2010,2,23); printresult(fromcal, tocal); fromcal.set(2010,0,23); tocal.set(2010,2,21); printresult(fromcal, tocal); fromcal.set(2011,0,22); tocal.set(2010,2,21); printresult(fromcal, tocal); [ 실행결과] 2010-01-01 ~ 2010-01-01:0 2010-01-21 ~ 2010-01-21:1 2010-01-01 ~ 2010-03-01:2 2010-01-01 ~ 2010-03-23:3 2010-01-23 ~ 2010-03-21:2 2011-01-22 ~ 2010-03-21:0 [10-3] 문자열 123,456,789.5 를소수점첫번째자리에서반올림하고, 그값을만단 위마다콤마(,) 로구분해서출력하시오. [ 실행결과] data:123,456,789.5 반올림 :123456790 만단위 :1,2345,6790

88 Java의정석定石 [10-4] 화면으로부터날짜를 2007/05/11 의형태로입력받아서무슨요일인지출력하 는프로그램을작성하시오. 단, 입력된날짜의형식이잘못된경우메세지를보여주고다시입력받아야한다. [ 실행결과] 날짜를 yyyy/mm/dd 의형태로입력해주세요.( 입력예:2007/05/11) >>2009-12-12 날짜를 yyyy/mm/dd 의형태로입력해주세요.( 입력예:2007/05/11) >>2009/12/12 입력하신날짜는토요일입니다. [10-5] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : getdaydiff 기능 : yyyymmdd 형식의두문자열을넘겨받으면두날짜의차이를일(day) 단위로반환한다. 반환타입 : int 단, 첫번째날짜빼기두번째날짜의결과를반환한다. 만일주어진문자열이유효하지않으면 매개변수 : String yyyymmdd1 - 시작날짜 String yyyymmdd2 - 끝날짜 0 을반환한다. [ 연습문제]/ch10/Exercise10_5.java import java.util.*; class Exercise10_5 { /* (1) getdaydiff 메서드를작성하시오. */ public static void main(string[] args){ System.out.println(getDayDiff("20010103","20010101")); System.out.println(getDayDiff("20010103","20010103")); System.out.println(getDayDiff("20010103","200103")); 실행결과 [ ] 2 0 0

Java의정석定石 89 [10-6] 자신이태어난날부터지금까지며칠이지났는지계산해서출력하시오. [ 실행결과] birth day=2000-01-01 today =2016-01-29 5872 days [10-7] 2016년 12월네번째화요일의날짜를아래의실행결과와같은형식으로출력하시 오. [ 실행결과] 2016-12-27 [10-8] 서울과뉴욕간의시차가얼마인지계산하여출력하시오. 실행결과 [ ] 2016-01-28T23:01:00.136+09:00[Asia/Seoul] 2016-01-28T09:01:00.138-05:00[America/New_York] sec1=32400 sec2=-18000 diff=14 hrs

90 Java의정석定石 Chapter 컬렉션프레임웍 Collections Framework

Java의정석定石 91 [ 연습문제 ] [11-1] 다음은정수집합 1,2,3,4와 3,4,5,6 의교집합, 차집합, 합집합을구하는코드이 다. 코드를완성하여실행결과와같은결과를출력하시오. [Hint] ArrayList클래스의 addall(), removeall(), retainall() 을사용하라. [ 연습문제]/ch11/Exercise11_1.java import java.util.*; class Exercise11_1 { public static void main(string[] args) { ArrayList list1 = new ArrayList(); ArrayList list2 = new ArrayList(); ArrayList kyo = new ArrayList(); // 교집합 ArrayList cha = new ArrayList(); // 차집합 ArrayList hap = new ArrayList(); // 합집합 list1.add(1); list1.add(2); list1.add(3); list1.add(4); list2.add(3); list2.add(4); list2.add(5); list2.add(6); /* */ (1) 알맞은코드를넣어완성하시오. System.out.println("list1="+list1); System.out.println("list2="+list2); System.out.println("kyo="+kyo); System.out.println("cha="+cha); System.out.println("hap="+hap); 실행결과 [ ] list1=[1, 2, 3, 4] list2=[3, 4, 5, 6] kyo=[3, 4] cha=[1, 2] hap=[1, 2, 3, 4, 5, 6]

92 Java의정석定石 [11-2] 다음코드의실행결과를적으시오. [ 연습문제]/ch11/Exercise11_2.java import java.util.*; class Exercise11_2 { public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(3); list.add(6); list.add(2); list.add(2); list.add(2); list.add(7); HashSet set = new HashSet(list); TreeSet tset = new TreeSet(set); Stack stack = new Stack(); stack.addall(tset); while(!stack.empty()) System.out.println(stack.pop()); [11-3] 다음중 ArrayList 에서제일비용이많이드는작업은? 단, 작업도중에 ArrayList 의크기변경이발생하지않는다고가정한다. a. b. c. d. 첫번째요소삭제 마지막요소삭제 마지막에새로운요소추가 중간에새로운요소추가 [11-4] LinkedList 클래스는이름과달리실제로는이중원형연결리스트(doubly circular linked list) 로구현되어있다. LinkedList인스턴스를생성하고 11개의요소를 추가했을때, 이 11 개의요소중접근시간(access time) 이가장오래걸리는요소는몇 번째요소인가?

Java의정석定石 93 [11-5] 다음에제시된 Student클래스가 Comparable인터페이스를구현하도록변경해서 이름(name) 이기본정렬기준이되도록하시오. [ 연습문제]/ch11/Exercise11_5.java import java.util.*; class Student { String name; int ban; int no; int kor, eng, math; Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; int gettotal() { return kor+eng+math; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage(); class Exercise11_5 { public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(new Student(" 홍길동",1,1,100,100,100)); list.add(new Student(" 남궁성",1,2,90,70,80)); list.add(new Student(" 김자바",1,3,80,80,90)); list.add(new Student(" 이자바",1,4,70,90,70)); list.add(new Student(" 안자바",1,5,60,100,80)); Collections.sort(list); Iterator it = list.iterator(); while(it.hasnext()) System.out.println(it.next()); [ 실행결과] 김자바,1,3,80,80,90,250,83.3 남궁성,1,2,90,70,80,240,80.0 안자바,1,5,60,100,80,240,80.0 이자바,1,4,70,90,70,230,76.7 홍길동,1,1,100,100,100,300,100.0

94 Java의정석定石 [11-6] 다음의코드는성적평균의범위별로학생수를세기위한것이다. TreeSet이학 생들의평균을기준으로정렬하도록 주면해당범위에속한학생의수를반환하는 [Hint] TreeSet의 subset(object from, Object to) 를사용하라. compare(object o1, Object o2) 와평균점수의범위를 getgroupcount() 를완성하라. [ 연습문제]/ch11/Exercise11_6.java import java.util.*; class Student implements Comparable { String name; int ban; int no; int kor; int eng; int math; Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; int gettotal() { return kor+eng+math; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage() ; public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return name.compareto(tmp.name); else { return -1; // class Student

Java의정석定石 95 class Exercise11_6 { static int getgroupcount(treeset tset, int from, int to) { /* (1) 알맞은코드를넣어완성하시오. */ public static void main(string[] args) { TreeSet set = new TreeSet(new Comparator() { public int compare(object o1, Object o2) { /* (2) 알맞은코드를넣어완성하시오. */ ); set.add(new Student(" 홍길동",1,1,100,100,100)); set.add(new Student(" 남궁성",1,2,90,70,80)); set.add(new Student(" 김자바",1,3,80,80,90)); set.add(new Student(" 이자바",1,4,70,90,70)); set.add(new Student(" 안자바",1,5,60,100,80)); Iterator it = set.iterator(); while(it.hasnext()) System.out.println(it.next()); System.out.println("[60~69] :"+getgroupcount(set,60,70)); System.out.println("[70~79] :"+getgroupcount(set,70,80)); System.out.println("[80~89] :"+getgroupcount(set,80,90)); System.out.println("[90~100] :"+getgroupcount(set,90,101)); [ 실행결과] 이자바,1,4,70,90,70,230,76.7 남궁성,1,2,90,70,80,240,80.0 김자바,1,3,80,80,90,250,83.3 홍길동,1,1,100,100,100,300,100.0 [60~69] :0 [70~79] :1 [80~89] :2 [90~100] :1

96 Java의정석定石 [11-7] 다음에제시된 BanNoAscending 클래스를완성하여, ArrayList에담긴 Student인 스턴스들이반(ban) 과번호(no) 로오름차순정렬되게하시오.( 반이같은경우번호를비 교해서정렬한다.) [ 연습문제]/ch11/Exercise11_7.java import java.util.*; class Student { String name; int ban; int no; int kor; int eng; int math; Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; int gettotal() { return kor+eng+math; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage() ; // class Student class BanNoAscending implements Comparator { public int compare(object o1, Object o2) { /* (1) 알맞은코드를넣어완성하시오. */ class Exercise11_7 { public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(new Student(" 이자바",2,1,70,90,70));

Java의정석定石 97 list.add(new Student(" 안자바",2,2,60,100,80)); list.add(new Student(" 홍길동",1,3,100,100,100)); list.add(new Student(" 남궁성",1,1,90,70,80)); list.add(new Student(" 김자바",1,2,80,80,90)); Collections.sort(list, new BanNoAscending()); Iterator it = list.iterator(); while(it.hasnext()) System.out.println(it.next()); [ 실행결과] 남궁성,1,1,90,70,80,240,80.0 김자바,1,2,80,80,90,250,83.3 홍길동,1,3,100,100,100,300,100.0 이자바,2,1,70,90,70,230,76.7 안자바,2,2,60,100,80,240,80.0

98 Java의정석定石 [11-8] 문제11-7의 Student 클래스에총점(total) 과전교등수(schoolRank) 를저장하기 위한인스턴스변수를추가하였다. Student 클래스의기본정렬을이름(name) 이아닌총점 (total) 을기준으로한내림차순으로변경한다음, 총점을기준으로각학생의전교등수 를계산하고전교등수를기준으로오름차순정렬하여출력하시오. [ 연습문제]/ch11/Exercise11_8.java import java.util.*; class Student implements Comparable { String name; int ban; int no; int kor; int eng; int math; int total; // 총점 int schoolrank; // 전교등수 Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; total = kor+eng+math; int gettotal() { return total; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public int compareto(object o) { /* (1) 알맞은코드를넣어완성하시오. */ public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage() +","+schoolrank // 새로추가

Java의정석定石 99 ; // class Student class Exercise11_8 { public static void calculateschoolrank(list list) { Collections.sort(list); // 먼저 list 를총점기준내림차순으로정렬한다. int prevrank = -1; // 이전전교등수 int prevtotal = -1; // 이전총점 int length = list.size(); /* (2) 아래의로직에맞게코드를작성하시오. 1. 반복문을이용해서 list에저장된 Student 객체를하나씩읽는다. 1.1 총점(total) 이이전총점(prevTotal) 과같으면이전등수(prevRank) 를등수(schoolRank) 로한다. 1.2 총점이서로다르면, 등수(schoolRank) 의값을알맞게계산해서저장한다. 이전에동점자였다면, 그다음등수는동점자의수를고려해야한다. ( 실행결과참고) 1.3 현재총점과등수를이전총점(prevTotal) 과이전등수(prevRank) 에저장한다. */ public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(new Student(" 이자바",2,1,70,90,70)); list.add(new Student(" 안자바",2,2,60,100,80)); list.add(new Student(" 홍길동",1,3,100,100,100)); list.add(new Student(" 남궁성",1,1,90,70,80)); list.add(new Student(" 김자바",1,2,80,80,90)); calculateschoolrank(list); Iterator it = list.iterator(); while(it.hasnext()) System.out.println(it.next()); [ 실행결과] 홍길동,1,3,100,100,100,300,100.0,1 김자바,1,2,80,80,90,250,83.3,2 안자바,2,2,60,100,80,240,80.0,3 남궁성,1,1,90,70,80,240,80.0,3 이자바,2,1,70,90,70,230,76.7,5

100 Java의정석定石 [11-9] 문제11-8의 Student 클래스에반등수(classRank) 를저장하기위한인스턴스변수 를추가하였다. 반등수를계산하고반과반등수로오름차순정렬하여결과를출력하시오. (1)~(2) 에알맞은코드를넣어완성하시오. [ 연습문제]/ch11/Exercise11_9.java import java.util.*; class Student implements Comparable { String name; int ban; int no; int kor; int eng; int math; int total; int schoolrank; // 전교등수 int classrank; // 반등수 Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; total = kor+eng+math; int gettotal() { return total; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return tmp.total - this.total; else { return -1; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math

Java의정석定石 101 +","+gettotal() +","+getaverage() +","+schoolrank +","+classrank // ; // class Student 새로추가 class ClassTotalComparator implements Comparator { public int compare(object o1, Object o2) { /* (1) 알맞은코드를넣어완성하시오. */ class Exercise11_9 { public static void calculateclassrank(list list) { // 먼저반별총점기준내림차순으로정렬한다. Collections.sort(list, new ClassTotalComparator()); int prevban = -1; int prevrank = -1; int prevtotal = -1; int length = list.size(); /* (2) 아래의로직에맞게코드를작성하시오. 1. 반복문을이용해서 list에저장된 Student 객체를하나씩읽는다. 1.1 반이달라지면,(ban과 prevban 이다르면) 이전등수(prevRank) 와이전총점(prevTotal) 을초기화한다. 1.2 총점(total) 이이전총점(prevTotal) 과같으면이전등수(prevRank) 를등수(classRank) 로한다. 1.3 총점이서로다르면, 등수(classRank) 의값을알맞게계산해서저장한다. 이전에동점자였다면, 그다음등수는동점자의수를고려해야한다. ( 실행결과참고) 1.4 현재반과총점과등수를이전반(prevBan), 이전총점(prevTotal), 이전등수(prevRank) 에저장한다. */ // public static void calculateclassrank(list list) { public static void calculateschoolrank(list list) { /* 내용생략 */ public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(new Student(" 이자바",2,1,70,90,70)); list.add(new Student(" 안자바",2,2,60,100,80)); list.add(new Student(" 홍길동",1,3,100,100,100)); list.add(new Student(" 남궁성",1,1,90,70,80)); list.add(new Student(" 김자바",1,2,80,80,90));

102 Java의정석定石 calculateschoolrank(list); calculateclassrank(list); Iterator it = list.iterator(); while(it.hasnext()) System.out.println(it.next()); [ 실행결과] 홍길동,1,3,100,100,100,300,100.0,1,1 김자바,1,2,80,80,90,250,83.3,2,2 남궁성,1,1,90,70,80,240,80.0,3,3 안자바,2,2,60,100,80,240,80.0,3,1 이자바,2,1,70,90,70,230,76.7,5,2 [11-10] 다음예제의빙고판은 1~30 사이의숫자들로만든것인데, 숫자들의위치가잘 섞이지않는다는문제가있다. 이러한문제가발생하는이유와이문제를개선하기위한 방법을설명하고, 이를개선한새로운코드를작성하시오. [ 연습문제]/ch11/Exercise11_10.java import java.util.*; class Exercise11_10 { public static void main(string[] args) { Set set = new HashSet(); int[][] board = new int[5][5]; for(int i=0; set.size() < 25; i++) { set.add((int)(math.random()*30)+1+""); Iterator it = set.iterator(); for(int i=0; i < board.length; i++) { for(int j=0; j < board[i].length; j++) { board[i][j] = Integer.parseInt((String)it.next()); System.out.print((board[i][j] < 10? " " : " ") + board[i][j]); System.out.println(); // main

Java의정석定石 103 [11-11] 다음은 SutdaCard클래스를 HashSet 에저장하고출력하는예제이다. HashSet에 중복된카드가저장되지않도록 SutdaCard의 hashcode() 를알맞게오버라이딩하시오. [Hint] String클래스의 hashcode() 를사용하라. [ 연습문제]/ch11/Exercise11_11.java import java.util.*; class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public boolean equals(object obj) { if(obj instanceof SutdaCard) { SutdaCard c = (SutdaCard)obj; return num==c.num && iskwang==c.iskwang; else { return false; public String tostring() { return num + ( iskwang? "K":""); class Exercise11_11 { public static void main(string[] args) { SutdaCard c1 = new SutdaCard(3,true); SutdaCard c2 = new SutdaCard(3,true); SutdaCard c3 = new SutdaCard(1,true); HashSet set = new HashSet(); set.add(c1); set.add(c2); set.add(c3); System.out.println(set); 실행결과 [ ] [3K, 1K]

104 Java의정석定石 [11-12] 다음은섯다게임에서카드의순위를결정하는등급목록( 족보) 이다. HashMap에 등급과점수를저장하는 registerjokbo() 와게임참가자의점수를계산해서반환하는 getpoint() 를완성하시오. [ 참고] 섯다게임은두장의카드의숫자를더한값을 10 으로나눈나머지가높은쪽이이기는게임이다. 그외에 도특정숫자로구성된카드로이루어진등급( 족보) 이있어서높은등급의카드가이긴다. 카드1 카드2 점수 K K 4000 10 10 3100 9 9 3090 8 8 3080 7 7 3070 6 6 3060 5 5 3050 4 4 3040 3 3 3030 2 2 3020 1 1 3010 - - - 카드1 카드2 점수 1 2 2060 2 1 2060 1 4 2050 4 1 2050 1 9 2040 9 1 2040 1 10 2030 10 1 2030 4 10 2020 10 4 2020 4 6 2010 6 4 2010 [ 연습문제]/ch11/Exercise11_12.java import java.util.*; class Exercise11_12 { public static void main(string args[]) throws Exception { SutdaDeck deck = new SutdaDeck(); deck.shuffle(); Player p1 = new Player(" 타짜", deck.pick(), deck.pick()); Player p2 = new Player(" 고수", deck.pick(), deck.pick()); System.out.println(p1+" "+deck.getpoint(p1)); System.out.println(p2+" "+deck.getpoint(p2)); class SutdaDeck { final int CARD_NUM = 20; SutdaCard[] cards = new SutdaCard[CARD_NUM]; int pos = 0; // 다음에가져올카드의위치 HashMap jokbo = new HashMap(); // 족보를저장할 HashMap SutdaDeck() { for(int i=0;i < cards.length;i++) { int num = i%10+1; boolean iskwang = i < 10 && (num==1 num==3 num==8); cards[i] = new SutdaCard(num,isKwang);

Java의정석定石 105 registerjokbo(); // 족보를등록한다. void registerjokbo() { /* (1) 아래의로직에맞게코드를작성하시오. 1. jokbo(hashmap) 에족보를저장한다. 두카드의값을문자열로붙여서 key 로, 점수를 value 로저장한다. */ int getpoint(player p) { if(p==null) return 0; SutdaCard c1 = p.c1; SutdaCard c2 = p.c2; Integer result = 0; /* */ (2) 아래의로직에맞게코드를작성하시오. 1. 카드두장이모두광이면, jokbo 에서키를 "KK" 로해서점수를조회한다. 2. 두카드의숫자(num) 로 jokbo 에서등급을조회한다. 3. 해당하는등급이없으면, 아래의공식으로점수를계산한다. (c1.num + c2.num) % 10 + 1000 4. Player 의점수(point) 에계산한값을저장한다. return result.intvalue(); SutdaCard pick() throws Exception { SutdaCard c = null; if(0 <= pos && pos < CARD_NUM) { c = cards[pos]; cards[pos++] = null; else { throw new Exception(" 남아있는카드가없습니다."); return c; void shuffle() { for(int x=0; x < CARD_NUM * 2; x++) { int i = (int)(math.random() * CARD_NUM); int j = (int)(math.random() * CARD_NUM); SutdaCard tmp = cards[i]; cards[i] = cards[j]; cards[j] = tmp; // SutdaDeck

106 Java의정석定石 class Player { String name; SutdaCard c1; SutdaCard c2; int point; // 카드의등급에따른점수 - 새로추가 Player(String name, SutdaCard c1, SutdaCard c2) { this.name = name ; this.c1 = c1 ; this.c2 = c2 ; public String tostring() { return "["+name+"]"+ c1.tostring() +","+ c2.tostring(); // class Player class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public String tostring() { return num + ( iskwang? "K":""); [ 실행결과] [ 타짜]5,9 1004 [ 고수]1,1K 3010

Java의정석定石 107 [11-13] 다음코드는문제11-12를발전시킨것으로각 Player 들의점수를계산하고, 점 수가제일높은사람을출력하는코드이다. TreeMap의정렬기준을점수가제일높은사람 부터내림차순이되도록아래의코드를완성하시오. 단, 동점자처리는하지않는다. [ 연습문제]/ch11/Exercise11_13.java import java.util.*; class Exercise11_13 { public static void main(string args[]) throws Exception { SutdaDeck deck = new SutdaDeck(); deck.shuffle(); Player[] parr = { new Player(" 타짜", deck.pick(), deck.pick()), new Player(" 고수", deck.pick(), deck.pick()), new Player(" 물주", deck.pick(), deck.pick()), new Player(" 중수", deck.pick(), deck.pick()), new Player(" 하수", deck.pick(), deck.pick()) ; TreeMap rank = new TreeMap(new Comparator(){ public int compare(object o1, Object o2) { /* (1) 알맞은코드를넣어완성하시오. */ ); for(int i=0; i < parr.length;i++) { Player p = parr[i]; rank.put(p, deck.getpoint(p)); System.out.println(p+" "+deck.getpoint(p)); System.out.println(); System.out.println("1 위는 "+rank.firstkey()+" 입니다."); class SutdaDeck { final int CARD_NUM = 20; SutdaCard[] cards = new SutdaCard[CARD_NUM]; int pos = 0; // 다음에가져올카드의위치 HashMap jokbo = new HashMap(); // 족보를저장할 HashMap SutdaDeck() { for(int i=0;i < cards.length;i++) { int num = i%10+1; boolean iskwang = i < 10 && (num==1 num==3 num==8); cards[i] = new SutdaCard(num,isKwang);

108 Java의정석定石 registerjokbo(); // 족보를등록한다. void registerjokbo() { jokbo.put("kk", 4000); jokbo.put("1010",3100); jokbo.put("12", 2060); jokbo.put("99", 3090); jokbo.put("21", 2060); jokbo.put("88", 3080); jokbo.put("14", 2050); jokbo.put("77", 3070); jokbo.put("41", 2050); jokbo.put("66", 3060); jokbo.put("19", 2040); jokbo.put("55", 3050); jokbo.put("91", 2040); jokbo.put("44", 3040); jokbo.put("110", 2030); jokbo.put("33", 3030); jokbo.put("101", 2030); jokbo.put("22", 3020); jokbo.put("104", 2020); jokbo.put("11", 3010); jokbo.put("410", 2020); jokbo.put("46", 2010); jokbo.put("64", 2010); int getpoint(player p) { if(p==null) return 0; SutdaCard c1 = p.c1; SutdaCard c2 = p.c2; Integer result = 0; if(c1.iskwang && c2.iskwang) { result = (Integer)jokbo.get("KK"); else { result = (Integer)jokbo.get(""+c1.num+c2.num); if(result==null) { result = new Integer((c1.num + c2.num) % 10 + 1000); p.point = result.intvalue(); return result.intvalue(); SutdaCard pick() throws Exception { SutdaCard c = null; if(0 <= pos && pos < CARD_NUM) { c = cards[pos]; cards[pos++] = null; else { throw new Exception(" 남아있는카드가없습니다."); return c;

Java의정석定石 109 void shuffle() { for(int x=0; x < CARD_NUM * 2; x++) { int i = (int)(math.random() * CARD_NUM); int j = (int)(math.random() * CARD_NUM); SutdaCard tmp = cards[i]; cards[i] = cards[j]; cards[j] = tmp; // SutdaDeck class Player { String name; SutdaCard c1; SutdaCard c2; int point; Player(String name, SutdaCard c1, SutdaCard c2) { this.name = name ; this.c1 = c1 ; this.c2 = c2 ; public String tostring() { return "["+name+"]"+ c1.tostring() +","+ c2.tostring(); // class Player class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public String tostring() { return num + ( iskwang? "K":""); [ 실행결과] [ 타짜]7,2 1009 [ 고수]2,5 1007 [ 물주]1,7 1008 [ 중수]10,4 2020 [ 하수]9,6 1005 1 위는 [ 중수]10,4 입니다.

110 Java의정석定石 [11-14] 다음은성적처리프로그램의일부이다. Scanner클래스를이용해서화면으로부 터데이터를입력하고보여주는기능을완성하시오. [ 연습문제]/ch11/Exercise11_14.java import java.io.*; import java.util.*; class Exercise11_14 { static ArrayList record = new ArrayList(); // 성적데이터를저장할공간 static Scanner s = new Scanner(System.in); public static void main(string args[]) { while(true) { switch(displaymenu()) { case 1 : inputrecord(); break; case 2 : displayrecord(); break; case 3 : System.out.println(" 프로그램을종료합니다."); System.exit(0); // while(true) // menu를보여주는메서드 static int displaymenu(){ System.out.println("**************************************************"); System.out.println("* 성적관리프로그램 *"); System.out.println("**************************************************"); System.out.println(); System.out.println(" 1. 학생성적입력하기 "); System.out.println(); System.out.println(" 2. 학생성적보기"); System.out.println(); System.out.println(" 3. 프로그램종료 "); System.out.println(); System.out.print(" 원하는메뉴를선택하세요.(1~3) : "); int menu = 0; /* */ (1) 아래의로직에맞게코드를작성하시오. 1. 화면으로부터메뉴를입력받는다. 메뉴의값은 1~3 사이의값이어야한다. 2. 1~3 사이의값을입력받지않으면, 메뉴의선택이잘못되었음을알려주고다시입력받는다.( 유효한값을입력받을때까지반복해서입력받는다.) return menu; // public static int displaymenu(){ // 데이터를입력받는메서드

Java의정석定石 111 static void inputrecord() { System.out.println("1. 학생성적입력하기"); System.out.println(" 이름, 반, 번호, 국어성적, 영어성적, 수학성적' 의순서로공백없이입력하세요."); System.out.println(" 입력을마치려면 q 를입력하세요. 메인화면으로돌아갑니다."); while(true) { System.out.print(">>"); /* (2) 아래의로직에맞게코드를작성하시오. 1. Scanner 를이용해서화면으로부터데이터를입력받는다.(',' 를구분자로) 2. 입력받은값이 q 또는 Q 이면메서드를종료하고, 그렇지않으면입력받은값으로 Student인스턴스를생성하고 record 에추가한다. 3. 입력받은데이터에서예외가발생하면, " 입력오류입니다." 를보여주고다시입력받는다. 4. q 또는 Q가입력될때까지 2~3 의작업을반복한다. */ // end of while // public static void inputrecord() { // 데이터목록을보여주는메서드 static void displayrecord() { int koreantotal = 0; int englishtotal = 0; int mathtotal = 0; int total = 0; int length = record.size(); if(length > 0) { System.out.println(); System.out.println(" 이름반번호국어영어수학총점평균전교등수반등수"); System.out.println("===================================================="); for (int i = 0; i < length ; i++) { Student student = (Student)record.get(i); System.out.println(student); koreantotal += student.kor; mathtotal += student.math; englishtotal += student.eng; total += student.total; System.out.println("===================================================="); System.out.println(" 총점: "+koreantotal+" "+englishtotal +" "+mathtotal+" "+total); System.out.println(); else { System.out.println("===================================================="); System.out.println(" 데이터가없습니다."); System.out.println("===================================================="); // static void displayrecord() {

112 Java의정석定石 class Student implements Comparable { String name; int ban; int no; int kor; int eng; int math; int total; int schoolrank; int classrank; // 반등수 Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; total = kor+eng+math; int gettotal() { return total; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return tmp.total - this.total; else { return -1; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage() +","+schoolrank +","+classrank ; // class Student

Java의정석定石 113 [ 실행결과] ************************************************** * 성적관리프로그램 * ************************************************** 1. 학생성적입력하기 2. 학생성적보기 3. 프로그램종료 원하는메뉴를선택하세요.(1~3) : 5 메뉴를잘못선택하셨습니다. 다시입력해주세요. 원하는메뉴를선택하세요.(1~3) : 2 ==================================================== 데이터가없습니다. ==================================================== ************************************************** * 성적관리프로그램 * ************************************************** 1. 학생성적입력하기 2. 학생성적보기 3. 프로그램종료 원하는메뉴를선택하세요.(1~3) : 1 1. 학생성적입력하기이름, 반, 번호, 국어성적, 영어성적, 수학성적' 의순서로공백없이입력하세요. 입력을마치려면 q 를입력하세요. 메인화면으로돌아갑니다. >> 입력오류입니다. 이름, 반, 번호, 국어성적, 영어성적, 수학성적' 의순서로입력하세요. >> 자바짱,1,1,100,100,100 잘입력되었습니다. 입력을마치려면 q 를입력하세요. >> 김자바,1,2,80,80,80 잘입력되었습니다. 입력을마치려면 q 를입력하세요. >>q ************************************************** * 성적관리프로그램 * ************************************************** 1. 학생성적입력하기 2. 학생성적보기 3. 프로그램종료 원하는메뉴를선택하세요.(1~3) : 2 이름반번호국어영어수학총점평균전교등수반등수 ==================================================== 자바짱,1,1,100,100,100,300,100.0,0,0 김자바,1,2,80,80,80,240,80.0,0,0 ====================================================

114 Java의정석定石 총점 : 180 180 180 540 ************************************************** * 성적관리프로그램 * ************************************************** 1. 학생성적입력하기 2. 학생성적보기 3. 프로그램종료 원하는메뉴를선택하세요.(1~3) : 3 프로그램을종료합니다.

Java의정석定石 115 Chapter 지네릭스, 열거형, 애너테이션 Generics, Enumeration, Annotation

116 Java의정석定石 [ 연습문제 ] [12-1] 클래스 Box 가다음과같이정의되어있을때, 다음중오류가발생하는문장은? 경고가발생하는문장은? class Box<T> { // 지네릭타입 T를선언 T item; void setitem(t item) { this.item = item; T getitem() { return item; a. Box<Object> b = new Box<String>(); b. Box<Object> b = (Object)new Box<String>(); c. new Box<String>().setItem(new Object()); d. new Box<String>().setItem("ABC"); [12-2] 지네릭메서드 makejuice() 가아래와같이정의되어있을때, 이메서드를올바 르게호출한문장을모두고르시오. (Apple과 Grape는 Fruit 의자손이라고가정하자.) class Juicer { static <T extends Fruit> String makejuice(fruitbox<t> box) { String tmp = ""; for(fruit f : box.getlist()) tmp += f + " "; return tmp; a. Juicer.<Apple>makeJuice(new FruitBox<Fruit>()); b. Juicer.<Fruit>makeJuice(new FruitBox<Grape>()); c. Juicer.<Fruit>makeJuice(new FruitBox<Fruit>()); d. Juicer.makeJuice(new FruitBox<Apple>()); e. Juicer.makeJuice(new FruitBox<Object>()); [12-3] 다음중올바르지않은문장을모두고르시오. class Box<T extends Fruit> { // 지네릭타입 T를선언 T item; void setitem(t item) { this.item = item; T getitem() { return item; a. Box<?> b = new Box(); b. Box<?> b = new Box<>(); c. Box<?> b = new Box<Object>(); d. Box<Object> b = new Box<Fruit>(); e. Box b = new Box<Fruit>(); f. Box<? extends Fruit> b = new Box<Apple>(); g. Box<? extends Object> b = new Box<? extends Fruit>();

Java의정석定石 117 [12-4] 아래의메서드는두개의 ArrayList 를매개변수로받아서, 하나의새로운 ArrayList 로병합하는메서드이다. 이를지네릭메서드로변경하시오. public static ArrayList<? extends Product> merge( ArrayList<? extends Product> list, ArrayList<? extends Product> list2) { ArrayList<? extends Product> newlist = new ArrayList<>(list); newlist.addall(list2); return newlist; [12-5] 아래는예제7-3에열거형 Kind와 Number 를새로정의하여적용한것이다. (1) 에 알맞은코드를넣어예제를완성하시오. (Math.random() 을사용했으므로실행결과가달라 질수있다.) [ 연습문제]/ch12/Exercise12_5.java class DeckTest { public static void main(string args[]) { Deck d = new Deck(); // 카드한벌(Deck) 을만든다. Card c = d.pick(0); // 섞기전에제일위의카드를뽑는다. System.out.println(c); // System.out.println(c.toString()); 과같다. d.shuffle(); // 카드를섞는다. c = d.pick(0); // 섞은후에제일위의카드를뽑는다. System.out.println(c); class Deck { final int CARD_NUM = Card.Kind.values().length * Card.Number.values().length; // 카드의개수 Card cardarr[] = new Card[CARD_NUM]; // Card객체배열을포함 Deck () { /* (1) 알맞은코드를넣어서완성하시오. Deck 의카드를초기화한다. */ Card pick(int index) { // 지정된위치(index) 에있는카드하나를꺼내서반환 return cardarr[index]; Card pick() { // Deck 에서카드하나를선택한다. int index = (int)(math.random() * CARD_NUM); return pick(index); 카드의순서를섞는다 void shuffle() { //. for(int i=0; i < cardarr.length; i++) { int r = (int)(math.random() * CARD_NUM);

118 Java의정석定石 Card temp = cardarr[i]; cardarr[i] = cardarr[r]; cardarr[r] = temp; // Deck클래스의끝 // Card 클래스 class Card { enum Kind { CLOVER, HEART, DIAMOND, SPADE enum Number { ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING Kind kind; Number num; Card() { this(kind.spade, Number.ACE); Card(Kind kind, Number num) { this.kind = kind; this.num = num; public String tostring() { return "[" + kind.name() + "," + num.name() + "]"; // tostring() 의끝 // Card 클래스의끝 실행결과 [ ] [CLOVER,ACE] [HEART,TEN] [12-6] 다음중메타애너테이션이아닌것을모두고르시오. a. Documented b. Target c. Native d. Inherited

Java의정석定石 119 [12-7] 애너테이션 TestInfo 가다음과같이정의되어있을대, 이애너테이션이올바르 게적용되지않은것은? @interface TestInfo { int count() default 1; String[] value() default "aaa"; a. @TestInfo class Exercise12_7 { b. @TestInfo(1) class Exercise12_7 { c. @TestInfo("bbb") class Exercise12_7 { d. @TestInfo("bbb","ccc") class Exercise12_7 {

120 Java의정석定石 Chapter 쓰레드 thread

Java의정석定石 121 [ 연습문제 ] [13-1] 쓰레드를구현하는방법에는 Thread클래스로부터상속받는것과 Runnable인터페 이스를구현하는것두가지가있는데, 다음의코드는 Thread클래스를상속받아서쓰레드 를구현한것이다. 이코드를 Runnable 인터페이스를구현하도록변경하시오. [ 연습문제]/ch13/Exercise13_1.java class Exercise13_1 { public static void main(string args[]) { Thread1 th1 = new Thread1(); th1.start(); class Thread1 extends Thread { public void run() { for(int i=0; i < 300; i++) { System.out.print('-'); [13-2] 다음코드의실행결과로옳은것은? [ 연습문제]/ch13/Exercise13_2.java class Exercise13_2 { public static void main(string[] args) { Thread2 t1 = new Thread2(); t1.run(); for(int i=0; i < 10; i++) System.out.print(i); class Thread2 extends Thread { public void run() { for(int i=0; i < 10; i++) System.out.print(i); a. 01021233454567689789처럼 0부터 9 까지의숫자가섞여서출력된다. b. 01234567890123456789처럼 0부터 9 까지의숫자가순서대로출력된다. c. IllegalThreadStateException 이발생한다.

122 Java의정석定石 [13-3] 다음중쓰레드를일시정지상태(WAITING) 로만드는것이아닌것은? ( 모두고르 시오 ) a. suspend() b. resume() c. join() d. sleep() e. wait() f. notify() [13-4] 다음중 interrupt() 에의해서실행대기상태(RUNNABLE) 가되지않는경우는? ( 모두고르시오) a. sleep() 에의해서일시정지상태인쓰레드 b. join() 에의해서일시정지상태인쓰레드 c. wait() 에의해서일시정지상태인쓰레드 d. suspend() 에의해서일시정지상태인쓰레드 [13-5] 다음의코드를실행한결과를예측하고, 직접실행한결과와비교하라. 만일예 측한결과와실행한결과의차이가있다면그이유를설명하라. [ 연습문제]/ch13/Exercise13_5.java class Exercise13_5 { public static void main(string[] args) throws Exception { Thread3 th1 = new Thread3(); th1.start(); try { Thread.sleep(5*1000); catch(exception e) { throw new Exception(" 꽝~!!!"); class Thread3 extends Thread { public void run() { for(int i=0; i < 10; i++) { System.out.println(i); try { Thread.sleep(1000); catch(exception e) { // run()

Java의정석定石 123 [13-6] 다음의코드를실행한결과를예측하고, 직접실행한결과와비교하라. 만일예 측한결과와실행한결과의차이가있다면그이유를설명하라. [ 연습문제]/ch13/Exercise13_6.java class Exercise13_6 { public static void main(string[] args) throws Exception { Thread4 th1 = new Thread4(); th1.setdaemon(true); th1.start(); try { th1.sleep(5*1000); catch(exception e) { throw new Exception(" 꽝~!!!"); class Thread4 extends Thread { public void run() { for(int i=0; i < 10; i++) { System.out.println(i); try { Thread.sleep(1000); catch(exception e) { // run()

124 Java의정석定石 [13-7] 다음의코드는쓰레드 th1을생성해서실행시킨다음 6초후에정지시키는코드 이다. 그러나실제로실행시켜보면쓰레드를정지시킨다음에도몇초가지난후에서야 멈춘다. 그이유를설명하고, 쓰레드를정지시키면지체없이바로정지되도록코드를개 선하시오. [ 연습문제]/ch13/Exercise13_7.java class Exercise13_7 { static boolean stopped = false; public static void main(string[] args) { Thread5 th1 = new Thread5(); th1.start(); try { Thread.sleep(6*1000); catch(exception e) { stopped = true; // 쓰레드를정지시킨다. System.out.println("stopped"); class Thread5 extends Thread { public void run() { // Exercise13_7.stopped의값이 false 인동안반복한다. for(int i=0;!exercise13_7.stopped; i++) { System.out.println(i); try { Thread.sleep(3*1000); catch(exception e) { // run() 실행결과 [ ] 0 1 2 stopped

Java의정석定石 125 [13-8] 다음의코드는텍스트기반의타자연습게임인데 WordGenerator라는쓰레드가 Vector에 2 초마다단어를하나씩추가하고, 사용자가단어를입력하면 Vector에서일치하 는단어를삭제하도록되어있다. WordGenerator의 run() 을완성하시오. [ 연습문제]/ch13/Exercise13_8.java import java.util.*; class Exercise13_8 { Vector words = new Vector(); String[] data = {" 태연"," 유리"," 윤아"," 효연"," 수영"," 서현"," 티파니"," 써니"," 제시카"; int interval = 2 * 1000; // 2 초 WordGenerator wg = new WordGenerator(); public static void main(string args[]) { Exercise13_9 game = new Exercise13_9(); game.wg.start(); Vector words = game.words; while(true) { System.out.println(words); String prompt = ">>"; System.out.print(prompt); // 화면으로부터라인단위로입력받는다. Scanner s = new Scanner(System.in); String input = s.nextline().trim(); int index = words.indexof(input); if(index!=-1) { words.remove(index); // main class WordGenerator extends Thread { public void run() { /* (1) 아래의로직에맞게코드를작성하시오. 1. interval(2 초) 마다배열 data의값중하나를임의로선택해서 2. words 에저장한다. */ // end of run() // class WordGenerator // Exercise13_9

126 Java의정석定石 [ 실행결과] [] >> [ 서현] >> 서현 [ 수영, 윤아] >> 수영 [ 윤아, 유리] >> 유리 [ 윤아, 티파니] >> 티파니 [ 윤아, 윤아, 유리] >> 윤아 [ 윤아, 유리] >> 유리 [ 윤아, 효연] >> 효연 [ 윤아, 티파니] >> 윤아 [ 티파니, 윤아] >> 티파니 [ 윤아, 수영, 써니] >> [13-9] 다음은사용자의입력을출력하고종료하는프로그램을작성한것으로, 10초동 안입력이없으면자동종료되어야한다. 그러나실행결과를보면, 사용자의입력이 10초 안에이루어졌음에도불구하고프로그램이즉시종료되지않는다. 사용자로부터입력받는 즉시프로그램이종료되도록수정하시오. [ 연습문제]/ch13/Exercise13_9.java import javax.swing.joptionpane; class Exercise13_9 { public static void main(string[] args) throws Exception { Exercise13_9_1 th1 = new Exercise13_9_1(); th1.start(); String input = JOptionPane.showInputDialog(" 아무값이나입력하세요."); System.out.println(" 입력하신값은 " + input + " 입니다."); th1.interrupt(); // 쓰레드에게작업을멈추라고요청한다. class Exercise13_9_1 extends Thread { public void run() { int i = 10; while(i!=0 &&!isinterrupted()) {

Java의정석定石 127 System.out.println(i--); try { Thread.sleep(1000); // 1 초지연 catch(interruptedexception e) { System.out.println(" 카운트가종료되었습니다."); // main [ 실행결과] 10 9 8 입력하신값은 abcd 입니다. 7 6 5 4 3 2 1 카운트가종료되었습니다.

128 Java의정석定石 Chapter 람다와스트림 Lambda & Stream

Java의정석定石 129 [ 연습문제 ] [14-1] 메서드를람다식으로변환하여아래의표를완성하시오. 메서드 int max(int a, int b) { return a > b? a : b; int printvar(string name, int i) { System.out.println(name+"="+i ); int square(int x) { return x * x; int roll() { return (int)(math.random() * 6); int sumarr(int[] arr) { int sum = 0; for(int i : arr) sum += i; return sum; int[] emptyarr() { return new int[]{; 람다식 (int a, int b) -> a > b? a : b (a) (b) (c) (d) (e) [14-2] 람다식을메서드참조로변환하여표를완성하시오. ( 변환이불가능한경우, 변환불가 라고적어야함.) 람다식 (String s) -> s.length() ()-> new int[]{ arr -> Arrays.stream(arr) (String str1, String str2) -> str1.equals(str2) (a, b) -> Integer.compare(a, b) (String kind, int num) -> new Card(kind, num) (x) -> System.out.println(x) ()-> Math.random() (str) -> str.touppercase() () -> new NullPointerException() (Optional opt) -> opt.get() (StringBuffer sb, String s) -> sb.append(s) (String s) -> System.out.println(s) 메서드참조

130 Java의정석定石 [14-3] 아래의괄호안에알맞은함수형인터페이스는? ( ) f; // 함수형인터페이스타입의참조변수 f 를선언. f = (int a, int b) -> a > b? a : b; a. Function b. BiFunction c. Predicate d. BinaryOperator e. IntFunction [14-4] 두개의주사위를굴려서나온눈의합이 6 인경우를모두출력하시오. [Hint] 배열을사용하시오. [ 실행결과] [1, 5] [2, 4] [3, 3] [4, 2] [5, 1] [14-5] 문자열배열 strarr 의모든문자열의길이를더한결과를출력하시오. String[] strarr = { "aaa","bb","c", "dddd" ; [ 실행결과] sum=10 [14-6] 문자열배열 strarr 의문자열중에서가장긴것의길이를출력하시오. String[] strarr = { "aaa","bb","c", "dddd" ; 실행결과 [ ] 4

Java의정석定石 131 [14-7] 임의의로또번호(1~45) 를정렬해서출력하시오. [ 실행결과] 1 20 25 33 35 42 [14-8] 다음은불합격(150 점미만) 한학생의수를남자와여자로구별하여출력하는프 로그램이다. (1) 에알맞은코드를넣어완성하시오. [ 연습문제]/ch14/Exercise14_8.java import java.util.*; import java.util.function.*; import java.util.stream.*; import static java.util.stream.collectors.*; import static java.util.comparator.*; class Student { String name; boolean ismale; // 성별 int hak; // 학년 int ban; // 반 int score; Student(String name, boolean ismale, int hak, int ban, int score) { this.name = name; this.ismale = ismale; this.hak = hak; this.ban = ban; this.score = score; String getname() { return name; boolean ismale() { return ismale; int gethak() { return hak; int getban() { return ban; int getscore() { return score; public String tostring() { return String.format("[%s, %s, %d 학년 %d 반, %3d 점]", name, ismale? " 남":" 여", hak, ban, score); // groupingby() 에서사용 enum Level { HIGH, MID, LOW // 성적을상, 중, 하세단계로분류 class Exercise14_8 { public static void main(string[] args) { Student[] stuarr = {

132 Java의정석定石 new Student(" 나자바", true, 1, 1, 300), new Student(" 김지미", false, 1, 1, 250), new Student(" 김자바", true, 1, 1, 200), new Student(" 이지미", false, 1, 2, 150), new Student(" 남자바", true, 1, 2, 100), new Student(" 안지미", false, 1, 2, 50), new Student(" 황지미", false, 1, 3, 100), new Student(" 강지미", false, 1, 3, 150), new Student(" 이자바", true, 1, 3, 200), ; new Student(" 나자바", true, 2, 1, 300), new Student(" 김지미", false, 2, 1, 250), new Student(" 김자바", true, 2, 1, 200), new Student(" 이지미", false, 2, 2, 150), new Student(" 남자바", true, 2, 2, 100), new Student(" 안지미", false, 2, 2, 50), new Student(" 황지미", false, 2, 3, 100), new Student(" 강지미", false, 2, 3, 150), new Student(" 이자바", true, 2, 3, 200) Map<Boolean, Map<Boolean, Long>> failedstubysex = /* (1) 알맞은코드를넣으시오. */ long failedmalestunum = failedstubysex.get(true).get(true); long failedfemalestunum = failedstubysex.get(false).get(true); System.out.println(" 불합격[ 남자]:"+ failedmalestunum +" 명"); System.out.println(" 불합격[ 여자]:"+ failedfemalestunum +" 명"); [ 실행결과] 불합격[ 남자]:2명불합격[ 여자]:4명

Java의정석定石 133 [14-9] 다음은각반별총점을학년별로나누어출력하는프로그램이다. (1) 에알맞은 코드를넣어완성하시오. [ 연습문제]/ch14/Exercise14_9.java import java.util.*; import java.util.function.*; import java.util.stream.*; import static java.util.stream.collectors.*; import static java.util.comparator.*; class Student { String name; boolean ismale; // 성별 int hak; // 학년 int ban; // 반 int score; Student(String name, boolean ismale, int hak, int ban, int score) { this.name = name; this.ismale = ismale; this.hak = hak; this.ban = ban; this.score = score; String getname() { return name; boolean ismale() { return ismale; int gethak() { return hak; int getban() { return ban; int getscore() { return score; public String tostring() { return String.format("[%s, %s, %d 학년 %d 반, %3d 점]", name, ismale? " 남":" 여", hak, ban, score); enum Level { HIGH, MID, LOW class Exercise14_9 { public static void main(string[] args) { Student[] stuarr = { new Student(" 나자바", true, 1, 1, 300), new Student(" 김지미", false, 1, 1, 250), new Student(" 김자바", true, 1, 1, 200), new Student(" 이지미", false, 1, 2, 150), new Student(" 남자바", true, 1, 2, 100), new Student(" 안지미", false, 1, 2, 50), new Student(" 황지미", false, 1, 3, 100), new Student(" 강지미", false, 1, 3, 150), new Student(" 이자바", true, 1, 3, 200), new Student(" 나자바", true, 2, 1, 300), new Student(" 김지미", false, 2, 1, 250),

134 Java의정석定石 ; new Student(" 김자바", true, 2, 1, 200), new Student(" 이지미", false, 2, 2, 150), new Student(" 남자바", true, 2, 2, 100), new Student(" 안지미", false, 2, 2, 50), new Student(" 황지미", false, 2, 3, 100), new Student(" 강지미", false, 2, 3, 150), new Student(" 이자바", true, 2, 3, 200) Map<Integer, Map<Integer, Long>> totalscorebyhakandban = /* (1) 알맞은코드를넣으시오. */ for(object e : totalscorebyhakandban.entryset()) { System.out.println(e); // main 의끝 실행결과 [ ] 1={1=750, 2=300, 3=450 2={1=750, 2=300, 3=450

Java의정석定石 135 Chapter 입출력 I/O

136 Java의정석定石 [ 연습문제 ] [15-1] 커맨드라인으로부터파일명과숫자를입력받아서, 입력받은파일의내용의처음 부터입력받은숫자만큼의라인을출력하는프로그램(FileHead.java) 을작성하라. [Hint] BufferedReader의 readline() 을사용하라. [ 실행결과] C:\jdk1.8\work\ch15>java FileHead 10 USAGE: java FileHead 10 FILENAME C:\jdk1.8\work\ch15>java FileHead 10 aaa aaa 은/ 는디렉토리이거나, 존재하지않는파일입니다. C:\jdk1.8\work\ch15>java FileHead 10 FileHead.java 1:import java.io.*; 2: 3:class FileHead 4:{ 5: public static void main(string[] args) 6: { 7: try { 8: int line = Integer.parseInt(args[0]); 9: String filename = args[1]; 10: C:\jdk1.8\work\ch15> [15-2] 지정된이진파일의내용을실행결과와같이 16진수로보여주는프로그램 (HexaViewer.java) 을작성하라. [Hint] PrintStream과 printf() 를사용하라. [ 실행결과] C:\jdk1.8\work\ch15>java HexaViewer HexaViewer.class CA FE BA BE 00 00 00 31 00 44 0A 00 0C 00 1E 09 00 1F 00 20 08 00 21 0A 00 08 00 22 0A 00 1F 00 23 07 00 24 0A 00 06 00 25 07 00 26 0A 00 08 00 27 0A 00 06 00 28 08 00 29 07 00 2A 0A 00 2B 00 2C 0A 00 08 00 2D 0A 00 08 00 2E 0A 00 06 00 2F 0A 00 08 00 2F 07 00 30 0A 00 12 00 31 07 00 32 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 01 00 04 6D 61 69 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53... 중간생략 C:\jdk1.8\work\ch15>

Java의정석定石 137 [15-3] 다음은디렉토리의요약정보를보여주는프로그램이다. 파일의개수, 디렉토리의 개수, 파일의총크기를계산하는 countfiles() 를완성하시오. [ 연습문제]/ch15/DirectoryInfoTest.java import java.io.*; class DirectoryInfoTest { static int totalfiles = 0; static int totaldirs = 0; static int totalsize = 0; public static void main(string[] args) { if(args.length!= 1) { System.out.println("USAGE : java DirectoryInfoTest DIRECTORY"); System.exit(0); File dir = new File(args[0]); if(!dir.exists()!dir.isdirectory()) { System.out.println(" 유효하지않은디렉토리입니다."); System.exit(0); countfiles(dir); System.out.println(); System.out.println(" 총 " + totalfiles + " 개의파일"); System.out.println(" 총 " + totaldirs + " 개의디렉토리"); System.out.println(" 크기 " + totalsize + " bytes"); // main public static void countfiles(file dir) { /* (1) 아래의로직에맞게코드를작성하시오. 1. dir 의파일목록(File[]) 을얻어온다. 2. 얻어온파일목록의파일중에서... 디렉토리이면, totaldirs의값을증가시키고 countfiles() 를재귀호출한다. 3. 파일이면, totalfiles를증가시키고파일의크기를 totalsize 에더한다. */ // countfiles [ 실행결과] C:\jdk1.8\work\ch15>java DirectoryInfoTest. 총 786개의파일총 27개의디렉토리크기 2566228 bytes C:\jdk1.8\work\ch15>

138 Java의정석定石 [15-4] 커맨드라인으로부터여러파일의이름을입력받고, 이파일들을순서대로합쳐 서새로운파일을만들어내는프로그램(FileMergeTest.java) 을작성하시오. 단, 합칠파 일의개수에는제한을두지않는다. [ 실행결과] C:\jdk1.8\work\ch15>java FileMergeTest USAGE: java FileMergeTest MERGE_FILENAME FILENAME1 FILENAME2... C:\jdk1.8\work\ch15>java FileMergeTest result.txt 1.txt 2.txt 3.txt C:\jdk1.8\work\ch15>type result.txt 1111111111 2222222222 33333333333333 C:\jdk1.8\work\ch15>java FileMergeTest result.txt 1.txt 2.txt C:\jdk1.8\work\ch15>type result.txt 1111111111 2222222222 C:\jdk1.8\work\ch15>type 1.txt 1111111111 C:\jdk1.8\work\ch15>type 2.txt 2222222222 C:\jdk1.8\work\ch15>type 3.txt 33333333333333 C:\jdk1.8\work\ch15>

Java의정석定石 139 [15-5] 다음은 FilterWriter를상속받아서직접구현한 HtmlTagFilterWriter를사용해 서주어진파일에있는태그를모두제거하는프로그램이다. HtmlTagFilterWriter의 write() 가태그를제거하도록코드를완성하시오. [ 연습문제]/ch15/Exercise15_5.java import java.io.*; class Exercise15_5 { public static void main(string[] args) { if(args.length!= 2) { System.out.println("USAGE: java Exercise15_5 TAGET_FILE RESULT_FILE"); System.exit(0); String inputfile = args[0]; String outputfile = args[1]; try { BufferedReader input = new BufferedReader(new FileReader(inputFile)); HtmlTagFilterWriter output = new HtmlTagFilterWriter(new FileWriter(outputFile)); int ch = 0; while((ch=input.read())!=-1) { output.write(ch); input.close(); output.close(); catch(ioexception e) { class HtmlTagFilterWriter extends FilterWriter { StringWriter tmp = new StringWriter(); boolean intag = false; HtmlTagFilterWriter(Writer out) { super(out); public void write(int c) throws IOException { /* (1) 아래의로직에맞게코드를작성하시오. 1. 출력할문자(c) 가 '<' 이면 intag의값을 true 로한다. 2. 출력할문자(c) 가 '>' 이면 intag의값을 false 로한다. 새로운 StringWriter 를생성한다.( 기존 StringWriter 의내용을버린다.) 3. intag의값이 true 이면, StringWriter 에문자(c) 를출력하고

140 Java의정석定石 intag의값이 false 이면, out 에문자(c) 를출력한다. [ 참고] 태그가시작되면 StringWriter에출력하고태그가끝나면 StringWriter 는비워진다. */ public void close() throws IOException { out.write(tmp.tostring()); // StringWriter의내용을출력하고 super.close(); // 조상의 close() 를호출해서기반스트림을닫는다. [ 실행결과] C:\jdk1.8\work\ch15>java Exercise15_5 test.html result.txt C:\jdk1.8\work\ch15>type result.txt New Document > 안녕하세요. 태그없애기테스트용파일입니다. < 태그가열린채로끝난것은태그로처리하지마세요. C:\jdk1.8\work\ch15>type test.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE> New Document </TITLE> </HEAD> <BODY> > 안녕하세요. 태그없애기테스트용파일입니다. </BODY> < 태그가열린채로끝난것은태그로처리하지마세요.

Java의정석定石 141 [15-6] 다음은콘솔명령어중에서디렉토리를변경하는 cd 명령을구현한것이다. 알맞 은코드를넣어 cd() 를완성하시오. [ 연습문제]/ch15/Exercise15_6.java import java.io.*; import java.util.*; import java.util.regex.*; class Exercise15_6 { static String[] argarr; // 입력한매개변수를담기위한문자열배열 static File curdir; // 현재디렉토리 static { try { curdir = new File(System.getProperty("user.dir")); catch(exception e) { public static void main(string[] args) { Scanner s = new Scanner(System.in); while(true) { try { String prompt = curdir.getcanonicalpath() + ">>"; System.out.print(prompt); // 화면으로부터라인단위로입력받는다. String input = s.nextline(); input = input.trim(); // 입력받은값에서불필요한앞뒤공백을제거한다. argarr = input.split(" +"); String command = argarr[0].trim(); if("".equals(command)) continue; command = command.tolowercase(); // 명령어를소문자로바꾼다. if(command.equals("q")) { // q 또는 Q 를입력하면실행종료한다. System.exit(0); else if(command.equals("cd")) { cd(); else { for(int i=0; i < argarr.length;i++) { System.out.println(argArr[i]); catch(exception e) { e.printstacktrace(); System.out.println(" 입력오류입니다."); // while(true) // main public static void cd() {

142 Java의정석定石 if(argarr.length==1) { System.out.println(curDir); return; else if(argarr.length > 2) { System.out.println("USAGE : cd directory"); return; String subdir = argarr[1]; /* (1) 아래의로직에맞게코드를작성하시오. 1. 입력된디렉토리(subDir) 가 ".." 이면, 1.1 현재디렉토리의조상디렉토리를얻어서현재디렉토리로지정한다. (File클래스의 getparentfile() 을사용) 2. 입력된디렉토리(subDir) 가 "." 이면, 단순히현재디렉토리의경로를화면에출력한다. 3. 1 또는 2 의경우가아니면, 3.1 입력된디렉토리(subDir) 가현재디렉토리의하위디렉토리인지확인한다. 3.2 확인결과가 true 이면, 현재디렉토리(curDir) 을입력된디렉토리(subDir) 로변경한다. 3.3 확인결과가 false 이면, " 유효하지않은디렉토리입니다." 고화면에출력한다. */ // cd() [ 실행결과] C:\jdk1.8\work\ch15>java Exercise15_6 C:\jdk1.8\work\ch15>> C:\jdk1.8\work\ch15>>cd ch15 유효하지않은디렉토리입니다. C:\jdk1.8\work\ch15>>cd.. C:\jdk1.8\work>>cd ch15 C:\jdk1.8\work\ch15>> C:\jdk1.8\work\ch15>>cd. C:\jdk1.8\work\ch15 C:\jdk1.8\work\ch15>>q C:\jdk1.8\work\ch15>

Java의정석定石 143 [15-7] 다음의코드는대화내용을파일에저장할수있는채팅프로그램이다. 저장 버튼을누르면대화내용이저장되도록알맞은코드를넣어완성하시오. [ 연습문제]/ch15/ChatWin.java import java.io.*; import java.awt.*; import java.awt.event.*; class ChatWin extends Frame { String nickname = ""; TextArea ta = new TextArea(); Panel p = new Panel(); TextField tf = new TextField(30); Button bsave = new Button(" 저장"); ChatWin(String nickname) { super("chatting"); this.nickname = nickname; setbounds(200, 100, 300, 200); p.setlayout(new FlowLayout()); p.add(tf); p.add(bsave); add(ta, "Center"); add(p, "South"); addwindowlistener(new WindowAdapter(){ public void windowclosing(windowevent e) { System.exit(0); ); bsave.addactionlistener(new ActionListener(){ public void actionperformed(actionevent ae) { FileDialog filesave = new FileDialog(ChatWin.this, " 파일저장", FileDialog.SAVE); filesave.setvisible(true); String filename = filesave.getdirectory() + filesave.getfile(); saveas(filename); ); EventHandler handler = new EventHandler(); ta.addfocuslistener(handler); tf.addfocuslistener(handler); tf.addactionlistener(handler); ta.settext("#" + nickname + " 님즐거운채팅되세요."); ta.seteditable(false); setresizable(false); setvisible(true); tf.requestfocus();

144 Java의정석定石 void saveas(string filename) { /* (1) 알맞은코드를넣어완성하시오. */ // saveas메서드의끝 public static void main(string[] args) { if(args.length!= 1) { System.out.println("USAGE : java ChatWin NICKNAME"); System.exit(0); new ChatWin(args[0]); // main class EventHandler extends FocusAdapter implements ActionListener { public void actionperformed(actionevent ae) { String msg = tf.gettext(); if("".equals(msg)) return; ta.append("\r\n" + nickname +">"+ msg); tf.settext(""); public void focusgained(focusevent e) { tf.requestfocus(); // class EventHandler // class [ 실행결과]

Java의정석定石 145 [15-8] 다음의코드는파일로부터한줄씩데이터를읽어서보여주는프로그램이다. 버 튼을이용해서첫줄, 다음줄, 이전줄, 마지막줄로이동할수있으며, 각줄의개행문 자는 를사용한다. (1)~(2) 에알맞은코드를넣어완성하시오. [ 연습문제]/ch15/WordStudy.java import java.util.*; import java.io.*; import java.awt.*; import java.awt.event.*; class WordStudy extends Frame { Button first = new Button("<<"); Button prev = new Button("<"); Button next = new Button(">"); Button last = new Button(">>"); Panel buttons = new Panel(); TextArea ta = new TextArea(); ArrayList wordlist = new ArrayList(); final String WORD_FILE = "word_data.txt"; final String CR_LF = System.getProperty("line.separator"); int pos = 0; WordStudy(String title) { super(title); buttons.add(first); buttons.add(prev); buttons.add(next); buttons.add(last); add("south", buttons); add("center", ta); EventHandler handler = new EventHandler(); addwindowlistener(handler); first.addactionlistener(handler); prev.addactionlistener(handler); next.addactionlistener(handler); last.addactionlistener(handler); loadfile(word_file); setbackground(color.black); setsize(300, 200); setlocation(200, 200); setresizable(true); setvisible(true); showfirst(); void showfirst() { pos = 0; display(pos);

146 Java의정석定石 void showprevious() { pos = (pos > 0)? --pos : 0; display(pos); void shownext() { int size = wordlist.size(); pos = (pos < size-1)? ++pos : size-1; display(pos); void showlast() { pos = wordlist.size()-1; display(pos); void display(int pos) { // pos 위치에있는라인의내용을보여준다. /* (1) 아래의로직에맞게코드를작성하시오. 1. wordlist에서 pos 번째의위치에있는데이터를읽어온다. 2. StringTokenizer 를이용해서 를구분자로자른다. 3. 잘라진 Token 에개행문자(CR_LF) 를붙여서 StringBuffer 에붙인다.(append) 4. StringBuffer의내용을뽑아서 TextArea 에보여준다. */ void loadfile(string filename) { /* (2) 아래의로직에맞게코드를작성하시오. 1. BuffredReader와 FileReader 를이용해서파일의내용을라인단위로읽는다. 2. 읽어온라인을 wordlist 에저장한다. 3. 만일예외가발생하면프로그램을종료한다. */ public static void main(string args[]) { WordStudy mainwin = new WordStudy("Word Study"); class EventHandler extends WindowAdapter implements ActionListener { public void actionperformed(actionevent ae) { Button b = (Button)ae.getSource(); if(b==first) { showfirst(); else if(b==prev) { showprevious(); else if(b==next) { shownext(); else if(b==last) { showlast(); public void windowclosing(windowevent e) {

Java의정석定石 147 System.exit(0); // class EventHandler [ 실행결과] [word_data.txt] mandatory 1. 명령의 2. 통치를위임받은 3. 강제의, 의무의(obli-gatory); 필수의 preliminary 1. 사전준비 2. 예비시험 3. 주경기이전에펼쳐지는개막경기 commitment 1. 위탁, 위임; 위원회회부 2. 인도; 투옥, 구류, 수감 3. 언질[ 공약] 을주기 prominent 1. 현저한, 두드러진 2. 돌기한, 양각된 3. 탁월한, 걸출한, 유명한; 중요한 Tell me the reason for coming here. 여기에온이유를내게말해라. There is something different about you today. 너오늘평소와좀다르구나. He jumped up and down when he got the news. 그는뉴스를듣고펄쩍뛰었다. When I opened it, I found a surprise. 그것을열었을때, 나는놀라운것을발견했다. I have known him since he was a child. 나는그를어려서부터알고있다.

148 Java의정석定石 [15-9] 다음은메모장프로그램의일부인데, fileopen() 과 saveas() 가아직구현되어 있지않다. 이두메서드를구현하여프로그램을완성하시오. [ 연습문제]/ch15/Exercise15_9.java import java.awt.*; import java.awt.event.*; import java.io.*; class Exercise15_9 extends Frame { String filename; TextArea content; MenuBar mb; Menu mfile; MenuItem minew, miopen, misaveas, miexit; Exercise15_9(String title) { super(title); content = new TextArea(); add(content); mb mfile = new MenuBar(); = new Menu("File"); minew = new MenuItem("New"); miopen = new MenuItem("Open"); misaveas = new MenuItem("Save As..."); miexit = new MenuItem("Exit"); mfile.add(minew); mfile.add(miopen); mfile.add(misaveas); mfile.addseparator(); // 메뉴분리선(separator) 을넣는다. mfile.add(miexit); mb.add(mfile); // MenuBar에 Menu 를추가한다. setmenubar(mb); // Frame에 MenuBar 를포함시킨다. // 메뉴에이벤트핸들러를등록한다. MyHandler handler = new MyHandler(); minew.addactionlistener(handler); miopen.addactionlistener(handler); misaveas.addactionlistener(handler); miexit.addactionlistener(handler); setsize(300, 200); setvisible(true); // 선택된파일의내용을읽어서 TextArea에보여주는메서드 void fileopen(string filename) { /* (1) 아래의로직에맞게코드를작성하시오. 1. BuffredReader와 FileReader 를이용해서지정된파일을읽는다. 2. StringWriter 에출력한다. 3. StringWriter의내용을 content(textarea) 에보여준다. */ // fileopen메서드의끝 // TextArea 의내용을지정된파일에저장하는메서드

Java의정석定石 149 void saveas(string filename) { /* (2) 아래의로직에맞게코드를작성하시오. 1. BuffredWriter와 FileWriter 를생성한다. 2. content에있는내용을가져와서 BufferedWriter 에출력한다. 3. BufferedWriter 를닫는다. */ // saveas메서드의끝 public static void main(string args[]) { Exercise15_9 mainwin = new Exercise15_9("Text Editor"); // main 메서드의끝 // 메뉴를클릭했을때메뉴별처리코드 class MyHandler implements ActionListener { public void actionperformed(actionevent e) { String command = e.getactioncommand(); if(command.equals("new")) { content.settext(""); else if(command.equals("open")) { FileDialog fileopen = new FileDialog(Exercise15_9.this, " 파일열기"); fileopen.setvisible(true); filename = fileopen.getdirectory() + fileopen.getfile(); System.out.println(fileName); // 선택된파일의내용을 TextArea 에보여준다. fileopen(filename); else if(command.equals("save As...")) { FileDialog filesave = new FileDialog(Exercise15_9.this, " 파일저장",FileDialog.SAVE); filesave.setvisible(true); filename = filesave.getdirectory() + filesave.getfile(); System.out.println(fileName); // 현재 TextArea 의내용을선택된파일에저장한다. saveas(filename); else if(command.equals("exit")) { System.exit(0); // 프로그램을종료시킨다. // class MyHandler // Exercise15_9클래스의끝 [ 실행결과]

150 Java의정석定石 Chapter 네트워킹 Networking

Java의정석定石 151 [ 연습문제 ] [16-1] ip주소가 192.168.10.100 이고서브넷마스크(subnet mask) 가 255.255.255.0일 때, 네트워크주소와호스트주소를계산하여화면에출력하는프로그램을작성하시오. 단, 비트연산자를사용해서계산해야한다. [ 실행결과] 네트워크주소 :192.168.10.0. 호스트주소 :0.0.0.100. [16-2] 다음중 TCP 의특징이아닌것은? a. 전화와같은 1:1 연결기반의프로토콜이다. b. 데이터의전송순서가보장된다. c. UDP 보다전송속도가빠르다. d. 데이터의수신여부를확인한다. [16-3] TextField에 URL을입력하고 Enter키를누르면해당페이지의소스를보여주는 'Source Viwer' 프로그램이다. 예제16-4 를참고해서 (1) 에알맞은코드를넣어완성하시 오. [ 연습문제]/ch16/Exercise16_3.java import java.net.*; import java.io.*; import java.awt.*; import java.awt.event.*; class SourceViewer extends Frame { TextField tf = new TextField(); TextArea ta = new TextArea(); SourceViewer(String title) { super(title); add(tf, "North"); add(ta, "Center"); tf.addactionlistener(new ActionListener(){ public void actionperformed(actionevent ae) { displaysource(); );

152 Java의정석定石 addwindowlistener(new WindowAdapter() { public void windowclosing(windowevent we) { System.exit(0); ); setbounds(500, 200, 500, 300); setvisible(true); void displaysource() { URL url = null; BufferedReader input = null; String address = tf.gettext().trim(); String line = ""; ta.settext(""); try { if(!address.startswith("http://")) address = "http://"+address; /* (1) 알맞은코드를넣어완성하시오. */ input.close(); catch(exception e) { ta.settext(" 유효하지않은 URL 입니다."); // displaysource() public static void main(string[] args) { SourceViewer mainwin = new SourceViewer("Source Viewer"); [ 실행결과]

Java의정석定石 153 [16-4] 다음의코드는 TCP통신을하는예제16-6, 16-7을결합하여 GUI채팅프로그램을 작성한것이다. (1)~(4) 에알맞은코드를넣어프로그램을완성하시오. [ 연습문제]/ch16/ChatServer.java import java.net.*; import java.io.*; import java.awt.*; import java.awt.event.*; class ChatServer extends Frame { String nickname = ""; DataOutputStream out; DataInputStream in; Panel p = new Panel(); TextArea ta = new TextArea(); TextField tf = new TextField(); ChatServer(String nickname) { super("chatting"); this.nickname = nickname; p.setlayout(new BorderLayout()); p.add(tf, "Center"); add(ta, "Center"); add(p, "South"); addwindowlistener(new WindowAdapter(){ public void windowclosing(windowevent e) { System.exit(0); ); EventHandler handler = new EventHandler(); ta.addfocuslistener(handler); tf.addfocuslistener(handler); tf.addactionlistener(handler); ta.seteditable(false); setbounds(200, 200, 300, 200); setvisible(true); tf.requestfocus(); void startserver() { ServerSocket serversocket = null; Socket socket = null; try { /* (1) 아래의로직에맞게코드를작성하시오. 1. 서비소켓을생성하여 7777 번포트와결합시킨다. 2. ta 에 " 서버가준비되었습니다." 라고보여준다. 3. 상대방의연결을기다린다. 4. ta 에 " 상대방과연결되었습니다." 라고보여준다. ta.append("\r\n" +" 상대방과연결되었습니다.");

154 Java의정석定石 5. 연결된상대방소켓의입력스트림과출력스트립을얻어온다. 6. 반복문을이용해서입력스트림이 null이아닌동안입력스트림으로부터데이터를읽어서변수 msg 에저장한다. */ ta.append("\r\n" + msg); catch (Exception e) { e.printstacktrace(); public static void main(string[] args) { if(args.length!= 1) { System.out.println("USAGE : java ChatServer NICKNAME"); System.exit(0); ChatServer chatwin = new ChatServer(args[0]); chatwin.startserver(); // main class EventHandler extends FocusAdapter implements ActionListener { public void actionperformed(actionevent ae) { String msg = tf.gettext(); if("".equals(msg)) return; /* (2) 알맞은코드를넣어완성하시오. */ ta.append("\r\n" + nickname +">"+ msg); tf.settext(""); public void focusgained(focusevent e) { tf.requestfocus(); // class EventHandler // class [ 실행결과]

Java의정석定石 155 [ 연습문제]/ch16/ChatClient.java import java.net.*; import java.io.*; import java.awt.*; import java.awt.event.*; class ChatClient extends Frame { String nickname = ""; String serverip = ""; int serverport = 0; DataOutputStream out; DataInputStream in; Panel p = new Panel(); TextArea ta = new TextArea(); TextField tf = new TextField(); ChatClient(String nickname, String serverip, String serverport) { super("chatting with " + serverip +":" + serverport); this.nickname = nickname; this.serverip = serverip; this.serverport = Integer.parseInt(serverPort); setbounds(600, 200, 300, 200); p.setlayout(new BorderLayout()); p.add(tf, "Center"); add(ta, "Center"); add(p, "South"); addwindowlistener(new WindowAdapter(){ public void windowclosing(windowevent e) { System.exit(0); ); EventHandler handler = new EventHandler(); ta.addfocuslistener(handler); tf.addfocuslistener(handler); tf.addactionlistener(handler); ta.seteditable(false); setvisible(true); tf.requestfocus(); void startclient() { try { /* (3) 아래의로직에맞게코드를작성하시오. 1. 소켓을생성하여 serverip의 serverport 에연결한다. 2. ta 에 " 상대방과연결되었습니다." 라고보여준다. ta.settext(" 상대방과연결되었습니다."); 3. 연결된상대방소켓의입력스트림과출력스트립을얻어온다. 4. 반복문을이용해서입력스트림이 null이아닌동안

156 Java의정석定石 입력스트림으로부터데이터를읽어서변수 */ ta.append("\r\n" + msg); catch(connectexception ce) { ta.settext(" 상대방과연결할수없습니다."); ce.printstacktrace(); catch(ioexception ie) { ie.printstacktrace(); catch(exception e) { e.printstacktrace(); msg 에저장한다. public static void main(string[] args) { if(args.length!= 3) { System.out.println("USAGE : java ChatClient NICKNAME SERVER_IP SERVER_PORT"); System.exit(0); ChatClient chatwin = new ChatClient(args[0],args[1],args[2]); chatwin.startclient(); // main class EventHandler extends FocusAdapter implements ActionListener { public void actionperformed(actionevent ae) { String msg = tf.gettext(); if("".equals(msg)) return; /* (4) 알맞은코드를넣어완성하시오. */ ta.append("\r\n" + nickname +">"+ msg); tf.settext(""); public void focusgained(focusevent e) { tf.requestfocus(); // class EventHandler // class [ 실행결과]

Java의정석定石 157 [ 연습문제 - 모범답안 ] [2-1] 다음표의빈칸에 8 개의기본형(primitive type) 을알맞은자리에넣으시오. 크기종류논리형문자형 1 byte 2 byte 4 byte 8 byte boolean char 정수형 byte short int long 실수형 float double

158 Java의정석定石 [2-2] 주민등록번호를숫자로저장하고자한다. 이값을저장하기위해서는어떤자료형 (data type) 을선택해야할까? regno라는이름의변수를선언하고자신의주민등록번호로 초기화하는한줄의코드를적으시오. [ 정답] long regno = 7701011111222L; [ 해설] 정수형타입으로는보통 int 형을사용하지만, 주민등록번호는 13자리의정수이기 때문에 int 형의범위를넘어서는값이다. 그래서 long 형을사용해야한다. 그리고리터럴 의접미사 'L' 을잊어서는안된다.

Java의정석定石 159 [2-3] 다음의문장에서리터럴, 변수, 상수, 키워드를적으시오. int i = 100; long l = 100L; final float PI = 3.14f; - 리터럴 : 100, 100L, 3.14f - 변수 : i, l - 키워드 : int, long, final, float - 상수 : PI

160 Java의정석定石 [2-4] 다음중기본형(primitive type) 이아닌것은? a. int b. Byte c. double d. boolean [ 정답] b [ 해설] 기본형은 boolean, byte, short, char, int, long, float, double 모두 8 개이다. 그외의타입은모두참조형(reference type) 이다.

Java의정석定石 161 [2-5] 다음문장들의출력결과를적으세요. 오류가있는문장의경우, 괄호안에 오 류 라고적으시오. System.out.println( 1 + 2 ) (12 ) System.out.println(true + ) (true ) System.out.println( A' + 'B') (131 ) System.out.println('1' + 2) (51 ) System.out.println('1' + '2') (99 ) System.out.println('J' + ava ) (Java ) System.out.println(true + null) ( 오류 ) [ 해설] 문자열과덧셈연산을하면그결과는항상문자열이된다. 문자열 + any type 문자열 + any type 문자열 문자열 + 문자열 문자열 + 문자열 문자열 "" + 7 "" + "7" "7" // 빈문자열을더해서숫자를문자열로변환한다. 7 + "" "7" + "" "7" 7 + " " "7" + " " "7 " " " + 7 " " + "7" " 7" 7 + "7" "7" + "7" "77" 7 + 7 + "" 14 + "" "14" + "" "14" "" + 7 + 7 "7" + 7 "7" + "7" "77" true + "" "true" + "" "true" null + "" "null" + "" "null" 하지만문자와문자의덧셈연산의결과는 int 형정수값이된다. 왜냐하면 int형보다작은 타입(byte, char, short) 은 int 형으로변환된후에덧셈연산이진행되기때문이다. 'A'+'B' 의경우, char + char int + int int의과정을통해최종결과는 int형정수 값이된다. 'A'+'B' 65 + 66 131 'A' 와 'B' 의문자코드의값은각각 65와 66 이다. '1'+2 49 + 2 51 '1' 의문자코드의값은 49 이다. '1'+'2' 49 + 50 99

162 Java의정석定石 [2-6] 다음중키워드가아닌것은?( 모두고르시오) a. if b. True c. NULL d. Class e. System [ 정답] b, c, d, e [ 해설] Java에서는대소문자를구별하기때문에 true는키워드이지만 True는키워드가아 니다. 다음은 Java 에서사용하는키워드이다. abstract default if package this assert do goto private throw boolean double implements protected throws break else import public transient byte enum instanceof return true case extends int short try catch false interface static void char final long strictfp volatile class finally native super while const float new switch continue for null synchronized

Java의정석定石 163 [2-7] 다음중변수의이름으로사용할수있는것은? ( 모두고르시오) a. $ystem b. channel#5 - 허용하지않는특수문자'#' 를사용할수없다. c. 7eleven - 숫자로시작하면안된다. d. If e. 자바 f. new - 예약어라서사용할수없다. g. $MAX_NUM h. hello@com - 허용하지않는특수문자'@' 를사용할수없다. [ 정답] a, d, e, g [ 해설] 변수의이름(identifier) 은다음과같은규칙이있다. 1. 대소문자가구분되며길이에제한이없다. - True와 true 는서로다른것으로간주된다. 2. 예약어를사용해서는안된다. - true 는예약어라서사용할수없지만, True 는가능하다. 3. 숫자로시작해서는안된다. - top10 은허용하지만, 7up 는허용되지않는다. 4. 특수문자는 '_' 와 '$' 만을허용한다. - $harp 은허용되지만, S#arp 은허용되지않는다.

164 Java의정석定石 [2-8] 참조형변수(reference type) 와같은크기의기본형(primitive type) 은? ( 모두고 르시오 ) a. int(4 byte) b. long(8 byte) c. short(2 byte) d. float(4 byte) e. double(8 byte) [ 정답] a, d [ 해설] 모든참조형변수는 4 byte 이므로, 크기가 4 byte 인기본형타입을고르면된다.

Java의정석定石 165 [2-9] 다음중형변환을생략할수있는것은? ( 모두고르시오) byte b = 10; char ch = 'A'; int i = 100; long l = 1000L; a. b = (byte)i; // int(4byte) byte(1byte) 이므로반드시형변환필요 b. ch = (char)b; // byte(1byte) char(2byte) 이지만범위가달라서형변환필요 c. short s = (short)ch; // char,short은 2byte이지만범위가달라서형변환필요 d. float f = (float)l; // float(4byte) 의범위가 long(8byte) 보다커서생략가능 e. i = (int)ch; // char(2 byte) int(4byte) 이므로생략가능 [ 정답] d, e

166 Java의정석定石 [2-10] char 타입의변수에저장될수있는정수값의범위는? (10 진수로적으시오) [ 정답] 0~65535 [ 해설] char는 2 byte(2*8=16bit) 이므로 2의 16 제곱 개의값을표현할수있다. 2의 16제곱은 65536 개이며, 0을포함해야하므로 0~65535( 모두 65536 개) 가 char범위가된 다.

Java의정석定石 167 [2-11] 다음중변수를잘못초기화한것은? ( 모두고르시오) a. byte b = 256; // byte 의범위(-128~127) 를넘는값으로초기화할수없음. b. char c = ''; // char 는반드시한개의문자를지정해야함 c. char answer = 'no'; // char 에두개의문자를저장할수없음. d. float f = 3.14 // 3.14는 3.14d 의생략된형태. 접미사f를붙이거나형변환필요 e. double d = 1.4e3f; // double(8byte) 에 float 값(4byte) 을넣는것이므로 OK [ 정답] a,b,c,d [ 해설] 접미사가있는자료형은 long, float, double 모두세개의자료형이며, 접미사는 대소문자를구별하지않는다. double은접미사를생략할수있으므로 float리터럴에는반 드시접미사를붙여야한다.

168 Java의정석定石 [2-12] 다음중 main 메서드의선언부로알맞은것은? ( 모두고르시오) a. public static void main(string[] args) b. public static void main(string args[]) c. public static void main(string[] arv) // 매개변수 args의이름은달라도됨 d. public void static main(string[] args) // void는반드시 main 앞에와야한다. e. static public void main(string[] args) // public과 static은위치가바뀌어도됨 [ 정답] a,b,c,e [ 해설] 배열을의미하는기호인 [] 는타입뒤에붙여도되고변수명뒤에붙여도되 기때문에 'String[] args' 와 String args[]' 는같은뜻이다. 자세한내용은 5장배 열(Array) 에서자세히설명할것이다.

Java의정석定石 169 [2-13] 다음중타입과기본값이잘못연결된것은? ( 모두고르시오) a. boolean - false b. char - '\u0000' c. float - 0.0 // float는 0.0f 가기본값. 0.0은 0.0d에서접미사 d가생략된것 d. int - 0 e. long - 0 // long은 0L 이기본값. f. String - "" // String 은참조형타입. 모든참조형타입의기본값은 null [ 정답] c,e,f [ 해설] 리터럴의접미사는대소문자를구분하지않으므로, long 의경우 'L' 또는 'l'( 소문 자) 을사용할수있다. 'l' 은숫자 '1' 과혼동하기쉬우므로대문자를사용하는것이좋 다.

170 Java의정석定石 [ 연습문제 - 모범답안 ] [3-1] 다음연산의결과를적으시오. [ 연습문제]/ch3/Exercise3_1.java class Exercise3_1 { public static void main(string[] args) { int x = 2; int y = 5; char c = 'A'; // 'A' 의문자코드는 65 System.out.println(1 + x << 33); System.out.println(y >= 5 x < 0 && x > 2); System.out.println(y += 10 - x++); System.out.println(x+=2); System.out.println(!('A' <= c && c <='Z') ); System.out.println('C'-c); System.out.println('5'-'0'); System.out.println(c+1); System.out.println(++c); System.out.println(c++); System.out.println(c); [ 정답] 실행결과 [ ] 6 true 13 5 false 2 5 66 B B C [ 해설] System.out.println(1 + x << 33); '1 + x << 33' 는 x의값이 2 이므로 '1 + 2 << 33' 가된다. 덧셈연산자(+) 보다쉬프트연산 자(<<) 가우선순위가낮으므로 '3 << 33' 이된다. int는 32 bit이므로 33번쉬프트하지 않고 1 번만쉬프트한다. '3 << 1' 은 3 에 2의 1 제곱 인 2를곱하는것과같은결과를 얻으므로 '3 * 2' 가되어결국 6 을얻는다. System.out.println(y >= 5 x < 0 && x > 2); x의값이 2 이고, y의값이 5 이므로위의식은 'true false && false' 가된다. 논리연

Java의정석定石 171 산자 'and(&&)' 는 'or( )' 보다우선순위가높기때문에 'false && false' 가먼저연산되 어 'true false' 가되고최종결과는 true 가된다. System.out.println(y += 10 - x++); 'y += 10 - x++' 를풀어쓰면, 'y = y + (10 - x++)' 이된다. x++ 은후위형이기때문에 x 의값이증가되지않은상태에서 (10 - x) 는계산되고 x의값은 1 증가된다. 그래서 (10-2) 로계산이되고 x의값은 1증가하여 3 이된다. y의값은 5이므로식은 'y = 5 + (10-2)' 가되어 y에 13 이저장된다. System.out.println(x+=2); 'x+=2' 는 'x=x+2' 와같다. 이전의식에서 x의값이 1증가하였으므로이제 x의값은 3이 다. 3에 2를더했으므로결과는 5 가된다. System.out.println(!('A' <= c && c <='Z') );!('A' <= c && c <='Z') 는문자 c 가대문자가아닌지를확인하는조건식이다. 먼저괄호 안의 'A' <= c && c <='Z' 가먼저계산되고마지막에이계산결과가논리부정연산자(!) 에 의해반대(true false) 로바뀐다. c 가 'A' 이므로 'A' <= 'A' && 'A' <='Z' 가되고양 쪽의조건식이 true 이므로 'true && true' 의결과인 true 를얻게된다. 이결과에논리부 정연산(!) 을수행하니까 true가 false로바뀌어최종결과는 false 가된다. System.out.println('C'-c); 이항연산자는피연산자가 int 보다작은타입(byte, short, char) 인경우 int로변환한다 음에연산을수행한다. c 의값이 'A' 이므로 'C'-c 는 C'-'A' 가되고 'C' 와 'A' 는 int로 변환되어 '67-65' 가되고최종결과는 2 가된다. System.out.println('5'-'0'); '5'-'0' 도위와같은이유로 '53-48' 이되어 5 를결과로얻는다. System.out.println(c+1); c+1은 c 의값이 'A' 이므로 'A'+1 이되고, 이항연산자의성질(int보다작은타입은 int로 변환후연산) 때문에 'A' 는문자코드값인 65 로변환되어 '65 + 1' 을수행하여 66을결과 로얻는다. 단지변수 c에저장된값을읽어서수식을계산한것이므로변수 c의저장된 값에는아무런변화가없다.

172 Java의정석定石 System.out.println(++c); 단항연산자인'++' 은이항연산자와달리 int 보다작은타입도형변환을하지않는다.( 이항 연산자는연산을위해 피연산자스택(operand stack) 을사용하는데이과정에서형변 환이발생하는것이다. 반면에단항연산자인증가연산자'++' 은 피연산자스택 을사용 하지않으므로형변환도발생하지않는다.) 그래서 println은변수 c 를숫자(int) 로출력 하는것이아니라문자로출력한다. 변수 c 에저장된문자가 'A'( 실제로저장된것은 'A' 의문자코드인 65) 이므로문자코드의값이 1증가되어 66('B' 의문자코드) 이변수 c에저 장된다. 변수 c 에저장된것은문자코드, 즉정수값이다. println은이값을타입에따라어떻게 출력할지를결정한다. 만일문자타입이면저장된값( 문자코드) 에해당하는문자를출력하 고숫자라면숫자로출력한다. System.out.println(c++); 단항연산자'++' 이후위형인경우에는 println() 에의해서변수 c가출력된후에 c에저장 된값이증가하므로문자 'B' 가출력된후에변수 c의값이 1 증가해서문자 'C' 가저장된 다.

Java의정석定石 173 [3-2] 아래의코드는사과를담는데필요한바구니( 버켓) 의수를구하는코드이다. 만일 사과의수가 123개이고하나의바구니에는 10 개의사과를담을수있다면, 13개의바구니 가필요할것이다. (1) 에알맞은코드를넣으시오. [ 연습문제]/ch3/Exercise3_2.java class Exercise3_2 { public static void main(string[] args) { int numofapples = 123; // 사과의개수 int sizeofbucket = 10; // 바구니의크기( 바구니에담을수있는사과의개수) int numofbucket = numofapples/sizeofbucket + (numofapples%sizeofbucket > 0? 1 : 0) ; System.out.println(" 필요한바구니의수 :"+numofbucket); 실행결과 [ ] 13 [ 정답] numofapples/sizeofbucket + (numofapples%sizeofbucket > 0? 1 : 0) [ 해설] 사과의개수(numOfApples) 를바구니의크기(sizeOfBucket) 으로나눗셈연산(/) 을 하면사과를담는데필요한바구니의수(numOfBucket) 를구할수있다. 정수간의나눗셈 연산의특징은반올림을하지않고버림을한다는것이다. 예를들어 125/10의결과는 13 이아니라 12 가된다. 게다가 int와 int간의이항연산결과는 int 이기때문에, 12.5와같 은실수값결과가나오지않는다. 그리고사과의개수(numOfApples) 를바구니의크기(sizeOfBucket) 으로나눴을때나머지 가있으면하나의바구니가더필요하다. 그래서나머지연산자(%) 를이용해서나눗셈연 산에서나머지가발생하는지확인해서, 나머지가발생하면바구니의개수(numOfBucket) 에 1 을더해줘야한다.

174 Java의정석定石 [3-3] 아래는변수 num의값에따라 양수, 음수, 0 을출력하는코드이다. 삼항연산 자를이용해서 (1) 에알맞은코드를넣으시오. [Hint] 삼항연산자를두번사용하라. [ 연습문제]/ch3/Exercise3_3.java class Exercise3_3 { public static void main(string[] args) { int num = 10; System.out.println( num > 0? " 양수": (num < 0? " 음수" : "0")); 실행결과 [ ] 양수 [ 정답] num > 0? " 양수":(num < 0? " 음수" : "0") [ 설명] 삼항연산자를사용하면 2 가지경우의수를처리할수있다. 삼항연산자에삼항연 산자를포함시키면 3 가지경우의수를처리할수있다. num의값이 0 보다크면, ' 양수' 를 출력하고끝나지만, num의값이 0 보다작거나같으면괄호안의삼항연산자가수행된다. 여기서 num의값이 0 보다작으면 ' 음수' 가출력되고, 그렇지않으면(num의값이 0 이면) '0' 이출력된다.

Java의정석定石 175 [3-4] 아래는변수 num 의값중에서백의자리이하를버리는코드이다. 만일변수 num 의값이 456 이라면 400 이되고, 111 이라면 100 이된다. (1) 에알맞은코드를넣으 시오. [ 연습문제]/ch3/Exercise3_4.java class Exercise3_4 { public static void main(string[] args) { int num = 456; System.out.println(num/100*100); 실행결과 [ ] 400 [ 정답] num/100*100 [ 해설] 앞의문제에서도설명했듯이, 나눗셈연산자는반올림을하지않고버림을한다. 이성질을이용한문제이다.

176 Java의정석定石 [3-5] 아래는변수 num의값중에서일의자리를 1 로바꾸는코드이다. 만일변수 num의 값이 333이라면 331 이되고, 777이라면 771 이된다. (1) 에알맞은코드를넣으시오. [ 연습문제]/ch3/Exercise3_5.java class Exercise3_5 { public static void main(string[] args) { int num = 333; System.out.println(num/10*10+1); 실행결과 [ ] 331 [ 정답] num/10*10+1 [ 해설] 앞의문제를약간더응용한문제이다. 이미다설명한내용이므로자세한설명은 생략한다.

Java의정석定石 177 [3-6] 아래는변수 num의값보다크면서도가장가까운 10의배수에서변수 num의값을 뺀나머지를구하는코드이다. 예를들어, 24의크면서도가장가까운 10의배수는 30이 다. 19의경우 20 이고, 81의경우 90 이된다. 30에서 24를뺀나머지는 6이기때문에변 수 num의값이 24라면 6 을결과로얻어야한다. (1) 에알맞은코드를넣으시오. [Hint] 나머지연산자를사용하라. [ 연습문제]/ch3/Exercise3_6.java class Exercise3_6 { public static void main(string[] args) { int num = 24; System.out.println(10 - num%10); 실행결과 [ ] 6 [ 정답] 10 - num%10 [ 해설] 고민을좀해봐야하는문제인데답을보고나면너무간단해서허탈할지도모르겠 다. 이문제를풀기위해여러연산자를놓고고민을해보는것에의미가있다고생각해서 넣게되었다. 다른정답으로는 '(num/10+1)*10 - num' 이있다.

178 Java의정석定石 [3-7] 아래는화씨(Fahrenheit) 를섭씨(Celcius) 로변환하는코드이다. 변환공식이 'C = 5/9 (F - 32)' 라고할때, (1) 에알맞은코드를넣으시오. 단, 변환결과값은소수점 셋째자리에서반올림해야한다.(Math.round() 를사용하지않고처리할것) [ 연습문제]/ch3/Exercise3_7.java class Exercise3_7 { public static void main(string[] args) { int fahrenheit = 100; float celcius = (int)((5/9f * (fahrenheit - 32))*100 + 0.5) / 100f; System.out.println("Fahrenheit:"+fahrenheit); System.out.println("Celcius:"+celcius); 실행결과 [ ] Fahrenheit:100 Celcius:37.78 [ 정답] (int)((5/9f * (fahrenheit - 32))*100 + 0.5) / 100f [ 해설] 먼저화씨를섭씨로바꾸는공식은 '5/9f * (fahrenheit - 32)' 이다. 5/9의결과 는 0이기때문에두피연산자중어느한쪽을반드시 float나 double로해야만실수형태 의결과를얻을수있다. 그래서정수형리터럴인 9대신 float타입의리터럴인 9f를사용 하였다. 소수점셋째자리에서반올림을하려면다음의과정을거쳐야한다. 1. 값에 100 을곱한다. 37.77778 * 100 2. 1의결과에 0.5 를더한다. 3777.778 + 0.5 3778.278 3. 2의결과를 int 타입으로변환한다. (int)3778,278 3778 4. 3의결과를 100f 로나눈다.(100 으로나누면소수점아래의값을잃는다.) 3778 / 100f 37.78

Java의정석定石 179 [3-8] 아래코드의문제점을수정해서실행결과와같은결과를얻도록하시오. [ 연습문제]/ch3/Exercise3_8.java class Exercise3_8 { public static void main(string[] args) { byte a = 10; byte b = 20; byte c = (byte)(a + b); char ch = 'A'; ch = (char)(ch + 2); float f = 3 / 2f; long l = 3000 * 3000 * 3000L; float f2 = 0.1f; double d = 0.1; boolean result = (float)d==f2; System.out.println("c="+c); System.out.println("ch="+ch); System.out.println("f="+f); System.out.println("l="+l); System.out.println("result="+result); 실행결과 [ ] c=30 ch=c f=1.5 l=27000000000 result=true [ 정답] byte c = a + b; byte c = (byte)(a + b); ch = ch + 2; ch = (char)(ch + 2); float f = 3 / 2; float f = 3 / 2f; long l = 3000 * 3000 * 3000; long l = 3000 * 3000 * 3000L; boolean result = d==f2; boolean result = (float)d==f2; [ 해설] 이항연산은두피연산자의타입을일치시킨후연산을수행한다는것, 그리고 int보다작은타입은 int 로자동변환한다는것은반드시기억하고있어야하는중요한내용이다. byte c = a + b; byte c = (byte)(a + b); 변수 a와 b는모두 byte타입이므로이항연산인덧셈연산을하기전에 int타입으로자동형변환된다. int와 int의덧셈이므로연산결과는 int 가된다. int 타입의값(4 byte) 을 byte 타입의변수(1 byte) 에담아야하므로형변환을해주어야한다.

180 Java의정석定石 ch = ch + 2; ch = (char)(ch + 2); 이것도이전의경우와마찬가지이다. char타입이덧셈연산의과정을거치면서 int타입으로변환되므로 char타입의변수에저장하기위해서는 char타입으로형변환을해주어야한다. float f = 3 / 2; float f = 3 / 2f; int와 int의연산결과는 int이기때문에 3/2의결과는 1 이된다. 연산결과를실수로얻고싶으면, 적어도두피연산자중한쪽이실수타입(float와 double 중의하나) 이어야한다. long l = 3000 * 3000 * 3000; long l = 3000 * 3000 * 3000L; int*int*int의결과는 int이므로 int타입의최대값인약 2*10의 9제곱을넘는결과는오버플로우가발생하여예상한것과는다른값을얻는다. 그래서피연산자중적어도한값은 long타입이어야최종결과를 long타입의값으로얻기때문에 long 타입의접미사 'L' 을붙여서 long 타입의리터럴로만들어줘야한다. boolean result = d==f2; boolean result = (float)d==f2; 비교연산자도이항연산자이므로연산시에두피연산자의타입을맞추기위해형변환이발생한다. 그래서 double과 float의연산은 double과 double의연산으로자동형변환되는데, 실수는정수와달리근사값으로표현을하기때문에 float를 double로형변환했을때오차가발생할수있다. 그래서 float값을 double로형변환하기보다는 double값을유효자리수가적은 float 로형변환해서비교하는것이정확한결과를얻는다.

Java의정석定石 181 [3-9] 다음은문자형변수 ch 가영문자( 대문자또는소문자) 이거나숫자일때만변수 b 의값이 true 가되도록하는코드이다. (1) 에알맞은코드를넣으시오. [ 연습문제]/ch3/Exercise3_9.java class Exercise3_9 { public static void main(string[] args) { char ch = 'z'; boolean b = ('a' <= ch && ch <= 'z') ('A' <= ch && ch <= 'Z') ('0' <= ch && ch <= '9'); System.out.println(b); 실행결과 [ ] true [ 정답] ('a' <= ch && ch <= 'z') ('A' <= ch && ch <= 'Z') ('0' <= ch && ch <= '9') 괄호는생략해도된다.

182 Java의정석定石 [3-10] 다음은대문자를소문자로변경하는코드인데, 문자 ch에저장된문자가대문자 인경우에만소문자로변경한다. 문자코드는소문자가대문자보다 32 만큼더크다. 예를 들어 'A' 의코드는 65 이고 'a' 의코드는 97 이다. (1)~(2) 에알맞은코드를넣으시오. [ 연습문제]/ch3/Exercise3_10.java class Exercise3_10 { public static void main(string[] args) { char ch = 'A'; char lowercase = ('A' <= ch && ch <= 'Z')? (char)(ch+32): ch; System.out.println("ch:"+ch); System.out.println("ch to lowercase:"+lowercase); 실행결과 [ ] ch:a ch to lowercase:a [ 정답] ('A' <= ch && ch <= 'Z'), (char)(ch+32) [ 해설] 대문자인경우에만문자코드의값을 32 만큼증가시키면소문자가된다. 문자 ch가 대문자인지를확인하는조건식은 'A' <= ch && ch <= 'Z' 이고, 문자 ch의문자코드를 32 증가시키기위해서는덧셈연산을해야하는데, 이때덧셈연산의결과가 int이므로 char 타입으로의형변환이필요하다.

Java의정석定石 183 [ 연습문제 - 모범답안 ] [4-1] 다음의문장들을조건식으로표현하라. 1. int형변수 x가 10보다크고 20보다작을때 true인조건식 2. char형변수 ch가공백이나탭이아닐때 true인조건식 3. char형변수 ch 가 'x' 또는 'X' 일때 true인조건식 4. char형변수 ch 가숫자( 0 ~ 9 ) 일때 true인조건식 5. char형변수 ch 가영문자( 대문자또는소문자) 일때 true인조건식 6. int형변수 year가 400으로나눠떨어지거나또는 4로나눠떨어지고 100으로 나눠떨어지지않을때 true인조건식 7. boolean형변수 poweron가 false일때 true인조건식 8. 문자열참조변수 str 이 yes 일때 true인조건식 [ 정답 & 해설] 1. int형변수 x가 10보다크고 20보다작을때 true인조건식 10 < x && x < 20 2. char형변수 ch가공백이나탭이아닐때 true인조건식!(ch == ' ' ch =='\t') 또는 ch!=' ' && ch!='\t' 3. char형변수 ch 가 x' 또는 X' 일때 true인조건식 ch == 'x' ch == 'X' 4. char형변수 ch 가숫자( 0 ~ 9 ) 일때 true인조건식 '0' <= ch && ch <='9' 5. char형변수 ch 가영문자( 대문자또는소문자) 일때 true인조건식 ('a' <= ch && ch <= 'z') ('A' <= ch && ch <= 'Z') 6. int형변수 year가 400으로나눠떨어지거나또는 4로나눠떨어지고 100으로 나눠떨어지지않을때 true인조건식 year%400==0 year%4==0 && year%100!=0 7. boolean형변수 poweron가 false일때 true인조건식!poweron 또는 poweron==false 8. 문자열참조변수 str 이 yes 일때 true인조건식 str.equals("yes") 또는 "yes".equals(str)

184 Java의정석定石 [4-2] 1부터 20까지의정수중에서 2 또는 3 의배수가아닌수의총합을구하시오. [ 정답] 73 [ 해설] [ 연습문제]/ch4/Exercise4_2.java class Exercise4_2 { public static void main(string[] args) { int sum = 0; for(int i=1; i <=20; i++) { if(i%2!=0 && i%3!=0) //i가 2또는 3의배수가아닐때만 sum에 i 를더한다. sum +=i; System.out.println("sum="+sum); // main

Java의정석定石 185 [4-3] 1+(1+2)+(1+2+3)+(1+2+3+4)+...+(1+2+3+...+10) 의결과를계산하시오. [ 정답] 220 [ 해설] [ 연습문제]/ch4/Exercise4_3.java class Exercise4_3 { public static void main(string[] args) { int sum = 0; int totalsum = 0; for(int i=1; i <=10; i++) { sum += i; totalsum += sum; System.out.println("totalSum="+totalSum); // main i의값이 1부터 10까지 1 씩증가하며변하는동안, i의값을누적해서 sum에저장하면 sum의값은 1,3,6,10,15,21,28,36,45,55 의순서로변해간다. 즉, 1, 1+2, 1+2+3, 1+2+3+4, 1+2+3+4+5,...,1+2+3+4+5+6+7+8+9,1+2+3+4+5+6+7+8+9+10 의순서로변해간다. 따라서 1+(1+2)+(1+2+3)+(1+2+3+4)+...+(1+2+3+...+10) 의결과를계산하려면, sum의값 을계속더해나가면된다. 그래서 totalsum 이라는변수를두고, 이변수에 sum의값을계 속해서누적하여결과를얻었다. i sum totalsum 1 1 1 2 3 = 1+2 4 =1+3 = 1+(1+2) 3 6 = 1+2+3 10 =1+3+6 = 1+(1+2)+(1+2+3) 4 10= 1+2+3+4 20 =1+3+6+10 5 15 =1+2+3+4+5 35 =1+3+6+10+15 6 21 =1+2+3+4+5+6 56 =1+3+6+10+15+21 7 28 =1+2+3+4+5+6+7 84 =1+3+6+10+15+21+28 8 36 =1+2+3+4+5+6+7+8 120=1+3+6+10+15+21+28+36 9 45 =1+2+3+4+5+6+7+8+9 165=1+3+6+10+15+21+28+36+45 10 55 =1+2+3+4+5+6+7+8+9+10 220=1+3+6+10+15+21+28+36+45+55

186 Java의정석定石 [4-4] 1+(-2)+3+(-4)+... 과같은식으로계속더해나갔을때, 몇까지더해야총합이 100 이상이되는지구하시오. [ 정답] 199 [ 해설] [ 연습문제]/ch4/Exercise4_4.java class Exercise4_4 { public static void main(string[] args) { int sum = 0; // 총합을저장할변수 int s = 1; // 값의부호를바꿔주는데사용할변수 int num = 0; // 조건식의값이 true 이므로무한반복문이된다. for(int i=1;true; i++, s=-s) { // 매반복마다 s의값은 1, -1, 1, -1... num = s * i; // i 와부호(s) 를곱해서더할값을구한다. sum += num; if(sum >=100) // 총합이 100 보다같거나크면반복문을빠져나간다. break; System.out.println("num="+num); System.out.println("sum="+sum); // main for문대신 while 문을써도좋고, for 문을보다간략히하면다음과같이할수있다. for(int i=1; sum < 100; i++, s=-s) { num = i * s; sum += num;

Java의정석定石 187 [4-5] 다음의 for문을 while 문으로변경하시오. [ 연습문제]/ch4/Exercise4_5.java public class Exercise4_5 { public static void main(string[] args) { for(int i=0; i<=10; i++) { for(int j=0; j<=i; j++) System.out.print("*"); System.out.println(); // end of main // end of class [ 정답] 연습문제 [ ]/ch4/exercise4_5_2.java public class Exercise4_5_2 { public static void main(string[] args) { int i=0; while( i<=10) { int j=0; while(j<=i) { System.out.print("*"); j++; System.out.println(); i++; // end of main // end of class

188 Java의정석定石 [4-6] 두개의주사위를던졌을때, 눈의합이 6이되는모든경우의수를출력하는프 로그램을작성하시오. [ 정답] 1+5=6 2+4=6 3+3=6 4+2=6 5+1=6 [ 해설] [ 연습문제]/ch4/Exercise4_6.java class Exercise4_6 { public static void main(string[] args) { for(int i=1;i<=6;i++) for(int j=1;j<=6;j++) if(i+j==6) System.out.println(i+"+"+j+"="+(i+j)); // main 반복문을중첩해서 1부터 6까지를반복하면서두값의합이 6인경우를화면에출력하면 된다.

Java의정석定石 189 [4-7] Math.random() 을이용해서 1부터 6사이의임의의정수를변수 value에저장하는 코드를완성하라. (1) 에알맞은코드를넣으시오. [ 연습문제]/ch4/Exercise4_7.java class Exercise4_7 { public static void main(string[] args) { int value = (int)(math.random()*6)+1; System.out.println("value:"+value); [ 정답] (int)(math.random()*6)+1 [ 해설] 1. 각변에 6 을곱한다. 0.0 * 6 <= Math.random() * 6 < 1.0 * 6 0.0 <= Math.random() * 6 < 6.0 2. 각변을 int 형으로변환한다. (int)0.0 <= (int)(math.random() * 6) < (int)6.0 0 <= (int)(math.random() * 6) < 6 지금까지는 0과 6 사이의정수중하나를가질수있다. 0은포함되고 6은포함되지않는 다. 3. 각변에 1 을더한다. 0 + 1 <= (int)(math.random() * 6) + 1 < 6 + 1 1 <= (int)(math.random() * 6) + 1 < 7 자, 이제는 1과 7 사이의정수중하나를얻을수있다. 단, 1은범위에포함되고 7은포 함되지않는다.

190 Java의정석定石 [4-8] 방정식 2x+4y=10 의모든해를구하시오. 단, x와 y는정수이고각각의범위는 0<=x<=10, 0<=y<=10 이다. [ 실행결과] x=1, y=2 x=3, y=1 x=5, y=0 [ 정답] 연습문제 [ ]/ch4/exercise4_8.java class Exercise4_8 { public static void main(string[] args) { for(int x=0; x <=10;x++) { for(int y=0; y <=10;y++) { if(2*x+4*y==10) { System.out.println("x="+x+", y="+y); // main [ 해설] 문제4-6 과유사한문제이다. 반복문을중첩해서 0부터 10까지 1씩증가시켜가면서 돌린다. 반복과정에서방정식을만족시키는경우에만 x와 y 의값을출력하면된다.

Java의정석定石 191 [4-9] 숫자로이루어진문자열 str 이있을때, 각자리의합을더한결과를출력하는코 드를완성하라. 만일문자열이 "12345" 라면, 1+2+3+4+5 의결과인 15를출력이출력되 어야한다. (1) 에알맞은코드를넣으시오. [Hint] String클래스의 charat(int i) 을사용 [ 연습문제]/ch4/Exercise4_9.java class Exercise4_9 { public static void main(string[] args) { String str = "12345"; int sum = 0; for(int i=0; i < str.length(); i++) { sum += str.charat(i) - '0'; System.out.println("sum="+sum); 실행결과 [ ] 15 [ 정답] sum += str.charat(i) - '0'; [ 해설] charat(int i) 메서드는문자열에서 i 번째문자를반환한다.(i의값은 0부터시작 한다.) 예를들어, "Hello" 라는문자열이있을때 "Hello".charAt(4) 는문자 'o' 가된다. index 0 1 2 3 4 char H e l l o charat(int i) 을이용해서반복문으로각문자열의문자를하나씩읽어서숫자로변환한 다음 sum 에계속더하면된다. 문자'3' 을숫자 3 로바꾸는방법은문자'3' 에서문자'0' 을 빼주는것이다. 알파벳이나숫자는문자코드가연속적으로할당되었기때문에이런방법 이가능하다. 문자 문자코드...... 0 48 1 49 2 50 3 51...... 뺄셈과같은이항연산자는 int 타입보다작은타입은피연산자(byte, short, char) 은 int 로변환한다. 그래서 '3'-'0' 은 51-48으로변환되고그결과는숫자 3 이된다. '3'-'0' 51-48 3

192 Java의정석定石 [4-10] int타입의변수 num 이있을때, 각자리의합을더한결과를출력하는코드를 완성하라. 만일변수 num의값이 12345라면, 1+2+3+4+5 의결과인 15를출력하라. (1) 에알맞은코드를넣으시오. [ 주의] 문자열로변환하지말고숫자로만처리해야한다. [ 연습문제]/ch4/Exercise4_10.java class Exercise4_10 { public static void main(string[] args) { int num = 12345; int sum = 0; while(num > 0) { sum += num%10; num /= 10; System.out.println("sum="+sum); 실행결과 [ ] 15 [ 정답] while(num > 0) { sum += num%10; num /= 10; [ 해설] 문제4-9에서처럼문자열에서 charat(int i) 를이용해서문자를숫자로변환하는 것보다숫자에서각자리수의숫자를하나씩뽑아내는것은더어렵다. 하지만, 숫자의 마지막자리를어떻게뽑아내는지만알아내면나머지는쉽게해결된다. 방법은의외로간단하다아래와같이숫자를 10 으로반복해서나눠가면서, 10으로나머 지연산을하면일의자리를얻어낼수있다. num num%10 12345 5 1234 4 123 3 12 2 1 1 이값들을더하기만하면변수 있다. num에저장된숫자의각자리수를모두더한값을구할수

Java의정석定石 193 [4-11] 피보나치(Fibonnaci) 수열( 數列 ) 은앞을두수를더해서다음수를만들어나가 는수열이다. 예를들어앞의두수가 1과 1이라면그다음수는 2가되고그다음수는 1과 2를더해서 3이되어서 1,1,2,3,5,8,13,21,... 과같은식으로진행된다. 1과 1부터 시작하는피보나치수열의 10 번째수는무엇인지계산하는프로그램을완성하시오. [ 연습문제]/ch4/Exercise4_11.java public class Exercise4_11 { public static void main(string[] args) { // Fibonnaci 수열의시작의첫두숫자를 1, 1 로한다. int num1 = 1; int num2 = 1; int num3 = 0; // 세번째값 System.out.print(num1+","+num2); for (int i = 0 ; i < 8 ; i++ ) { num3 = num1 + num2; // 세번째값은첫번째와두번째값을더해서얻는다. System.out.print(","+num3); // 세번째수열출력 num1 = num2; // 두번째수열을첫번째값으로한다. num2 = num3; // 세번째수열을두번째값으로한다. // end of main // end of class 실행결과 [ ] 1,1,2,3,5,8,13,21,34,55 [ 정답] num3 = num1 + num2; // 세번째값은첫번째와두번째값을더해서얻는다. System.out.print(","+num3); // 세번째수열출력 num1 = num2; // 두번째수열을첫번째값으로한다. num2 = num3; // 세번째수열을두번째값으로한다. [ 해설] 워낙간단한문제이니정답을보는것만으로도다른설명이필요하지는않을것이 라생각한다. 혹시라도질문이있으면 http://cafe.naver.com/javachobostudy.cafe의게 시판에올려주길바란다.

194 Java의정석定石 [4-12] 구구단의일부분을다음과같이출력하시오. [ 실행결과] 2*1=2 3*1=3 4*1=4 2*2=4 3*2=6 4*2=8 2*3=6 3*3=9 4*3=12 5*1=5 6*1=6 7*1=7 5*2=10 6*2=12 7*2=14 5*3=15 6*3=18 7*3=21 8*1=8 9*1=9 8*2=16 9*2=18 8*3=24 9*3=27 [ 정답] [ 연습문제]/ch4/Exercise4_12.java public class Exercise4_12 { public static void main(string[] args) { for (int i = 1 ; i <= 9 ; i++) { for (int j = 1; j <= 3; j++) { int x = j+1+(i-1)/3*3; int y = i%3==0? 3 : i%3 ; if(x > 9) // 9 단까지만출력한다. 이코드가없으면 10 단까지출력된다. break; System.out.print(x+"*"+y+"="+x*y+"\t"); //println이아님에주의 System.out.println(); if(i%3==0) System.out.println(); // // end of main // end of class [ 해설] 이문제를푸는방법은여러가지가있겠지만, 반복문을 2번사용해서작성해보 았다. 가로로출력을했기때문에좀복잡하긴한데, 일단세로로출력해본다음에가로 로출력되도록변경하면문제풀기가수월해진다. 그래서실행결과와같은결과를얻기위 해서는먼저아래와같이출력할수있어야한다. 2*1=2 3*1=3 4*1=4 2*2=4 3*2=6 4*2=8 2*3=6 3*3=9 4*3=12 5*1=5

Java의정석定石 195 6*1=6 7*1=7 5*2=10 6*2=12 7*2=14 5*3=15 6*3=18 7*3=21 8*1=8 9*1=9 10*1=10 8*2=16 9*2=18 10*2=20 8*3=24 9*3=27 10*3=30 원래는 2단부터 9 단까지출력하는것이지만, 문제를쉽게하기위해서 10단까지출력하는 것이좋다. 구구단을곱하기 3까지만출력하므로전체반복회수는 3 * 9 = 27 번이된다. 3번반복하는반복문과 9번반복하는반복문을 2 중으로사용하면되는것이다. public class Exercise4_12 { public static void main(string[] args) { for (int i = 1 ; i <= 9 ; i++) { for (int j = 1; j <= 3; j++) { // 이블럭{ 안의코드가 9 * 3 = 27 번반복된다. // end of main // end of class 단을의미하는변수 x와곱하는숫자를의미하는변수 y를정의하고카운터 i와 j를이용 해서 x와 y 의값을적절히계산해주는것이이문제의핵심이다. public class Exercise4_12 { public static void main(string[] args) { for (int i = 1 ; i <= 9 ; i++) { for (int j = 1; j <= 3; j++) { int x = 0; // i와 j 값을이용해서적절히계산해야한다. int y = 0; // i와 j 값을이용해서적절히계산해야한다. System.out.println(x+"*"+y+"="+x*y); // end of main // end of class i와 j의값의변화와그에따른 x와 y 값의변화를표로적어보았다. 어떻게하면 i와 y의 값을이용해서 x와 y 의값을구해낼수있을까? 먼저 i의값과 y 의값을보면유사한점이많다. y의값은 i의값만잘이용하면어떻게 될것같다는생각이든다. i가 1~9까지 1씩증가하는데반해 y의값은 1,2,3이계속해서

196 Java의정석定石 반복된다. 그래서 i를 3 으로나머지연산을해봤더니, 우리가원하는 y의값과매우유사 해졌다. 다만 i%3의결과가 0 일때, 3 으로바꾸면된다. 그래서다음과같은식이만들 어지게된것이다. public class Exercise4_12 { public static void main(string[] args) { for (int i = 1 ; i <= 9 ; i++) { for (int j = 1; j <= 3; j++) { int x = 0; // i와 j 값을이용해서적절히계산해야한다. int y = i%3==0? 3 : i%3 ; System.out.println(x+"*"+y+"="+x*y); // end of main // end of class i j x y i%3 j+1 x-(j+1) 1 1 2 1 1 2 0 1 2 3 1 1 3 0 1 3 4 1 1 4 0 2 1 2 2 2 2 0 2 2 3 2 2 3 0 2 3 4 2 2 4 0 3 1 2 3 0 2 0 3 2 3 3 0 3 0 3 3 4 3 0 4 0 4 1 5 1 1 2 3 4 2 6 1 1 3 3 4 3 7 1 1 4 3 5 1 5 2 2 2 3 5 2 6 2 2 3 3 5 3 7 2 2 4 3 6 1 5 3 0 2 3 6 2 6 3 0 3 3 6 3 7 3 0 4 3 7 1 8 1 1 2 6 7 2 9 1 1 3 6 7 3 10 1 1 4 6 8 1 8 2 2 2 6 8 2 9 2 2 3 6 8 3 10 2 2 4 6 9 1 8 3 0 2 6 9 2 9 3 0 3 6 9 3 10 3 0 4 6 이제 x 의값만구하면되는데, x의값은 j 의값과좀유사하다. 다만 2단부터시작하기 때문에 x의값은 1이아닌 2 부터시작한다. 그래서 j의값에 1을더해서 j+1의값을적어 보니 x의값과 3 또는 6 의차이가있다. 이값의차이를보정해주기위해서는어떻게식 을만들어가야할까? i와 j중에서 i는증가하는성질의값이고 j는반복되는성질의값 이므로 j보다는 i 가적절할것같다. i의값을가지고어떻게하면원하는값을얻을수 있을까고민해보자.

Java의정석定石 197 public class Exercise4_12 { public static void main(string[] args) { for (int i = 1 ; i <= 9 ; i++) { for (int j = 1; j <= 3; j++) { int x = (j+1) + (???); // (???) 안에적절한수식이들어가야한다. int y = i%3==0? 3 : i%3 ; System.out.println(x+"*"+y+"="+x*y); // end of main // end of class i j x y j+1 i/3 (i-1)/3 (i-1)/3*3 j+1+(i-1)/3*3 1 1 2 1 2 0 0 0 2 1 2 3 1 3 0 0 0 3 1 3 4 1 4 0 0 0 4 2 1 2 2 2 0 0 0 2 2 2 3 2 3 0 0 0 3 2 3 4 2 4 0 0 0 4 3 1 2 3 2 1 0 0 2 3 2 3 3 3 1 0 0 3 3 3 4 3 4 1 0 0 4 4 1 5 1 2 1 1 3 5 4 2 6 1 3 1 1 3 6 4 3 7 1 4 1 1 3 7 5 1 5 2 2 1 1 3 5 5 2 6 2 3 1 1 3 6 5 3 7 2 4 1 1 3 7 6 1 5 3 2 2 1 3 5 6 2 6 3 3 2 1 3 6 6 3 7 3 4 2 1 3 7 7 1 8 1 2 2 2 6 8 7 2 9 1 3 2 2 6 9 7 3 10 1 4 2 2 6 10 8 1 8 2 2 2 2 6 8 8 2 9 2 3 2 2 6 9 8 3 10 2 4 2 2 6 10 9 1 8 3 2 3 2 6 8 9 2 9 3 3 3 2 6 9 9 3 10 3 4 3 2 6 10 위의표와같은과정을거쳐 i 의값을연산했더니우리가원했던값을얻을수있었다. 혼자서문제를풀때는어려웠는데별것아니었다고느끼는가? 아니면여전히어려운 가? 어렵다고느끼는이유는이러한문제풀이과정이익숙하지않기때문일뿐이다. 이러한문제들을통해여러분들이얻어야하는것은문제를풀어가는과정이라고생각한 다. 코드만이리저리주무르다가답을얻는것이아니라논리적인과정을하나하나거쳐 나가면서답을만들어가는것이여러분들이진정으로배워야하는것이다. 나머지과정은설명하지않아도이해할수있으리라생각하고생략하겠다. 정을거쳐구구단의일부가아닌전체를출력하는코드를작성해보자. 이와같은과

198 Java의정석定石 [4-13] 다음은주어진문자열(value) 이숫자인지를판별하는프로그램이다. (1) 에알맞 은코드를넣어서프로그램을완성하시오. [ 연습문제]/ch4/Exercise4_13.java class Exercise4_13 { public static void main(string[] args) { String value = "12o34"; char ch = ' '; boolean isnumber = true; // 반복문과 charat(int i) 를이용해서문자열의문자를 // 하나씩읽어서검사한다. for(int i=0; i < value.length() ;i++) { ch = value.charat(i); if(!('0'<=ch && ch<='9')) { isnumber = false; break; if (isnumber) { System.out.println(value+" 는숫자입니다."); else { System.out.println(value+" 는숫자가아닙니다."); // end of main // end of class [ 실행결과] 12o34 는숫자가아닙니다. [ 정답] ch = value.charat(i); if(!('0'<=ch && ch<='9')) { isnumber = false; break; [ 해설] charat(int i) 메서드는문자열에서 i 번째문자를반환한다.(i의값은 0부터시작 한다.) "12o34" 라는문자열이있을때 "12o34".charAt(2) 는문자 'o' 가된다. index 0 1 2 3 4 char 1 2 o 3 4 조건식 '0'<=ch && ch<='9' 는문자 ch 가숫자('0'~'9' 사이의문자) 이면참(true) 이된다. 이조건식전체에논리부정연산자! 를붙였으니, 문자 ch 가숫자가아니어야참(true) 인 조건식이된다. 이조건식을만족하는경우( 문자열중의어느한문자라도숫자가아닌 경우) 에만 isnumber의값을 false로바꾸고 break 문을수행해서반복문을빠져나온다.

Java의정석定石 199 [4-14] 다음은숫자맞추기게임을작성한것이다. 1과 100사이의값을반복적으로입력 해서컴퓨터가생각한값을맞추면게임이끝난다. 사용자가값을입력하면, 컴퓨터는자 신이생각한값과비교해서결과를알려준다. 사용자가컴퓨터가생각한숫자를맞추면 게임이끝나고몇번만에숫자를맞췄는지알려준다. (1)~(2) 에알맞은코드를넣어프 로그램을완성하시오. [ 연습문제]/ch4/Exercise4_14.java class Exercise4_14 { public static void main(string[] args) { // 1~100사이의임의의값을얻어서 answer 에저장한다. int answer = (int)(math.random() * 100) + 1; int input = 0; // 사용자입력을저장할공간 int count = 0; // 시도횟수를세기위한변수 // 화면으로부터사용자입력을받기위해서 Scanner클래스사용 java.util.scanner s = new java.util.scanner(system.in); do { count++; System.out.print("1과 100 사이의값을입력하세요 :"); input = s.nextint(); // 입력받은값을변수 input 에저장한다. if(answer > input) { System.out.println(" 더큰수를입력하세요."); else if(answer < input) { System.out.println(" 더작은수를입력하세요."); else { System.out.println(" 맞췄습니다."); System.out.println(" 시도횟수는 "+count+" 번입니다."); break; // do-while문을벗어난다 while(true); // 무한반복문 // end of main // end of class HighLow [ 실행결과] 1과 100 사이의값을입력하세요 :50 더큰수를입력하세요. 1과 100 사이의값을입력하세요 :75 더큰수를입력하세요. 1과 100 사이의값을입력하세요 :87 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :80 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :77 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :76 맞췄습니다. 시도횟수는 6 번입니다. [ 정답] (1) (int)(math.random() * 100) + 1;

200 Java의정석定石 (2) if(answer > input) { System.out.println(" 더큰수를입력하세요."); else if(answer < input) { System.out.println(" 더작은수를입력하세요."); else { System.out.println(" 맞췄습니다."); System.out.println(" 시도횟수는 "+count+" 번입니다."); break; // do-while 문을벗어난다 [ 해설] (1) 에는 1과 100사이의임의의정수를구하는코드가들어가야하며다음과같은 과정을통해만들어낼수있다. 1. 각변에 100 을곱한다. 0.0 * 100 <= Math.random() * 100 < 1.0 * 100 0.0 <= Math.random() * 100 < 100.0 2. 각변을 int 형으로변환한다. (int)0.0 <= (int)(math.random() * 100) < (int)100.0 0 <= (int)(math.random() * 100) < 100 지금까지는 0과 100 사이의정수중하나를가질수있다. 0은포함되고 100은포함되지 않는다. 3. 각변에 1 을더한다. 0 + 1 <= (int)(math.random() * 100) + 1 < 100 + 1 1 <= (int)(math.random() * 100) + 1 < 101 자, 이제는 1과 101 사이의정수중하나를얻을수있다. 1은포함되고 101은포함되지 않는다. (2) 에들어갈코드는입력받은값(input) 이컴퓨터가생각한값(answer) 과큰지, 작은 지, 같은지모두세가지경우에대해처리해야하므로 if-else if 문을사용했다. 변수 input 의값과 answer 의값이같은경우(else 블럭) 에는 break문을만나 do-while문을빠져나오 게된다.

Java의정석定石 201 [4-15] 다음은회문수를구하는프로그램이다. 회문수(palindrome) 란, 숫자를거꾸로읽 어도앞으로읽는것과같은수를말한다. 예를들면 12321 이나 13531 같은수를말한 다. (1) 에알맞은코드를넣어서프로그램을완성하시오. [Hint] 나머지연산자를이용하시오. [ 연습문제]/ch4/Exercise4_15.java class Exercise4_15 { public static void main(string[] args) { int number = 12321; int tmp = number; int result =0; // 변수 number를거꾸로변환해서담을변수 while(tmp!=0) { result = result*10 + tmp % 10; // 기존결과에 10 을곱해서더한다. tmp /= 10; if(number == result) System.out.println( number + " 는회문수입니다."); else System.out.println( number + " 는회문수가아닙니다."); // main [ 실행결과] 12321 는회문수입니다. [ 정답] result = result*10 + tmp % 10; tmp /= 10; [ 해설] 숫자를역순으로바꾼후원래의숫자와비교해서같으면회문수이다. 예를들어 원래의숫자(number) 의값이 12345 라면, 역순으로바꾸면 54321 이될것이다. 어떻게하 면 12345를 54321 로바꿀수있을까? 각자리수의값을더하는문제4-10 과같은방식, 10 으로나눠가면서 10 으로나머지연산을하는방식으로각자리수를얻을수있다. 다만 그냥더하는게아니라 10 을곱해가면서더하면숫자를역순으로바꿀수있다. result result*10 tmp tmp%10 0 0 12345 5 5 50 1234 4 54 540 123 3 543 5430 12 2 5432 54320 1 1 54321-0 -

202 Java의정석定石 Chapter 배열 Array

Java의정석定石 203 [ 연습문제 - 모범답안 ] [5-1] 다음은배열을선언하거나초기화한것이다. 잘못된것을고르고그이유를설명 하시오. a. int[] arr[]; b. int[] arr = {1,2,3,; // 마지막의쉼표, 는있어도상관없음. c. int[] arr = new int[5]; d. int[] arr = new int[5]{1,2,3,4,5; // 두번째대괄호[] 에숫자넣으면안됨. e. int arr[5]; // 배열을선언할때는배열의크기를지정할수없음. f. int[] arr[] = new int[3][]; [ 정답] d, e [ 해설] d. int[] arr = new int[]{1,2,3,4,5 에서는대괄호[] 안에배열의크기를지정할 수없다. 괄호{ 안의데이터의개수에따라자동적으로결정되기때문이다.

204 Java의정석定石 [5-2] 다음과같은배열이있을때, arr[3].length 의값은얼마인가? int[][] arr = { { 5, 5, 5, 5, 5, { 10, 10, 10, { 20, 20, 20, 20, { 30, 30 ; [ 정답] 2 [ 해설] 위와같은코드가실행되면다음과같은그림의배열이생성된다. arr 0x100 0x200 arr[0][0] arr[0][1] arr[0][2] arr[0][3] arr[0][4] 0x100 arr[0] 0x200 0x300 5 5 5 5 5 arr[1][0] arr[1][1] arr[1][2] arr[1] 0x300 10 10 10 0x400 arr[2][0] arr[2][1] arr[2][2] arr[2][3] arr[2] 0x400 20 20 20 20 0x500 arr[3][0] arr[3][1] arr[3] 0x500 30 30 arr[3].length는 arr[3] 이가리키는배열의크기를의미한다. 위의그림에서 arr[3] 이가 리키는배열은 0x500번지에있는배열이며크기는 2 이다. 그래서 arr[3].length의값은 2 가된다. 참고로 arr.length의값은 4 이고, arr[0].length의값은 5, arr[1].length의값 은 3, arr[2].length의값은 4 이다.

Java의정석定石 205 [5-3] 배열 arr 에담긴모든값을더하는프로그램을완성하시오. [ 연습문제]/ch5/Exercise5_3.java class Exercise5_3 { public static void main(string[] args) { int[] arr = {10, 20, 30, 40, 50; int sum = 0; for(int i=0;i<arr.length;i++) { sum += arr[i]; System.out.println("sum="+sum); 실행결과 [ ] sum=150 [ 정답] for(int i=0;i<arr.length;i++) { sum += arr[i]; [ 해설] 간단한문제라서별도의설명은생략함.

206 Java의정석定石 [5-4] 2차원배열 arr 에담긴모든값의총합과평균을구하는프로그램을완성하시오. [ 연습문제]/ch5/Exercise5_4.java class Exercise5_4 { public static void main(string[] args) { int[][] arr = { { 5, 5, 5, 5, 5, {10,10,10,10,10, {20,20,20,20,20, {30,30,30,30,30 ; int total = 0; float average = 0; for(int i=0; i < arr.length;i++) { for(int j=0; j < arr[i].length;j++) { total += arr[i][j]; average = total /(float)(arr.length * arr[0].length); System.out.println("total="+total); System.out.println("average="+average); // end of main // end of class 실행결과 [ ] total=325 average=16.25 [ 해설] 이번에도배열과반복문을이용하는문제인데, 2차원배열이라 2중 for문을사용 해야한다는것을제외하고는이전문제와다르지않다. 평균을구할때는배열의모든요소의총합을개수로나누면되는데, int로나누면 int 나누기 int이기때문에결과를 int 로얻으므로소수점이하의값을얻을수없다. 그래서 나누는값을 float 로형변환해주었다. 만일 float로형변환을해주지않으면 avaerage는 16.25가아닌 16.0 이될것이다.(average의타입이 float이므로 16을저장하면 16.0이된 다.) 1. int 형(4 byte) 보다크기가작은자료형은 int 형으로형변환후에연산을수행한다. byte / short int / int int 2. 두개의피연산자중자료형의표현범위가큰쪽에맞춰서형변환된후연산을수행한다. int / float float / float float 3. 정수형간의나눗셈에서 0 으로나누는것은금지되어있다.

Java의정석定石 207 [5-5] 다음은 1과 9사이의중복되지않은숫자로이루어진 3자리숫자를만들어내는프 로그램이다. (1)~(2) 에알맞은코드를넣어서프로그램을완성하시오. [ 참고] Math.random() 을사용했기때문에실행결과와다를수있다. [ 연습문제]/ch5/Exercise5_5.java class Exercise5_5 { public static void main(string[] args) { int[] ballarr = {1,2,3,4,5,6,7,8,9; int[] ball3 = new int[3]; // 배열 ballarr 의임의의요소를골라서위치를바꾼다. for(int i=0; i< ballarr.length;i++) { int j = (int)(math.random() * ballarr.length); int tmp = 0; tmp = ballarr[i]; ballarr[i] = ballarr[j]; ballarr[j] = tmp; // 배열 ballarr의앞에서 3개의수를배열 ball3 로복사한다. System.arraycopy(ballArr,0, ball3,0,3); for(int i=0;i<ball3.length;i++) { System.out.print(ball3[i]); System.out.println(); // end of main // end of class 실행결과 [ ] 486 [ 정답] (1) (2) tmp = ballarr[i]; ballarr[i] = ballarr[j]; ballarr[j] = tmp; System.arraycopy(ballArr,0, ball3,0,3); [ 해설] 1~9 의숫자를배열에순서대로담고, 반복해서위치를서로바꿈으로써숫자를섞 는다. 그다음에배열의세요소를차례대로가져오면중복되지않은세개의정수를얻 을수있다. 그다음엔배열 ballarr에서세개의값을배열 ball3 으로복사한다. 편의상 맨앞의세값을 ball3 로복사하기로하자. System.arraycopy(ballArr, 0, ball3, 0, 3); ballarr[0] 에서 ball3[0] 으로 3개의데이터를복사

208 Java의정석定石 ballarr ballarr[0] ballarr[1] ballarr[2] ballarr[3] ballarr[4] ballarr[5] ballarr[6] ballarr[7] ballarr[8] 0x100 4 8 6 1 7 5 3 9 2 0x100 ball3 ball3[0] ball3[1] ball3[2] 0x200 4 8 6 0x200

Java의정석定石 209 [5-6] 다음은거스름돈을몇개의동전으로지불할수있는지를계산하는문제이다. 변 수 money의금액을동전으로바꾸었을때각각몇개의동전이필요한지계산해서출력하 라. 단, 가능한한적은수의동전으로거슬러주어야한다. (1) 에알맞은코드를넣어서 프로그램을완성하시오. [Hint] 나눗셈연산자와나머지연산자를사용해야한다. [ 연습문제]/ch5/Exercise5_6.java class Exercise5_6 { public static void main(string args[]) { // 큰금액의동전을우선적으로거슬러줘야한다. int[] coinunit = {500, 100, 50, 10; int money = 2680; System.out.println("money="+money); for(int i=0;i<coinunit.length;i++) { System.out.println(coinUnit[i]+" 원: "+money/coinunit[i]); money = money%coinunit[i]; // main [ 실행결과] money=2680 500 원: 5 100 원: 1 50 원: 1 10 원: 3 [ 정답] System.out.println(coinUnit[i]+" 원: "+money/coinunit[i]); money = money%coinunit[i]; [ 해설] 동전의단위를내림차순으로배열에초기화한다. 금액이큰동전을우선적으로지 불해야가장적은동전의개수로거스름돈을줄수있기때문이다. 그렇지않으면, 모든 거스름돈을 10 원짜리로만주게될수도있다. 변수 money를 coinunit[i] 로나누면지불할동전의개수가되고, 나머지연산을하면 coinunit[i] 로지불하고남은금액이된다. 동전단위(coinUnit 배열) 의개수만큼이과정 을반복하면된다. money coinunit[i] money/coinunit[i] money%coinunit[i] 2680 500 5 180 180 100 1 80 80 50 1 30 30 10 3 0

210 Java의정석定石 [5-7] 문제 5-6 에동전의개수를추가한프로그램이다. 커맨드라인으로부터거슬러줄 금액을입력받아계산한다. 보유한동전의개수로거스름돈을지불할수없으면, 거스름 돈이부족합니다. 라고출력하고종료한다. 지불할돈이충분히있으면, 거스름돈을지불 한만큼가진돈에서빼고남은동전의개수를화면에출력한다. (1) 에알맞은코드를넣 어서프로그램을완성하시오. [ 연습문제]/ch5/Exercise5_7.java class Exercise5_7 { public static void main(string args[]) { if(args.length!=1) { System.out.println("USAGE: java Exercise5_7 3120"); System.exit(0); // 문자열을숫자로변환한다. 입력한값이숫자가아닐경우예외가발생한다. int money = Integer.parseInt(args[0]); System.out.println("money="+money); int[] coinunit = {500, 100, 50, 10 ; // int[] coin = {5, 5, 5, 5; // 동전의단위단위별동전의개수 for(int i=0;i<coinunit.length;i++) { int coinnum = 0; // 1. 금액(money) 을동전단위로나눠서필요한동전의개수(coinNum) 를구한다. coinnum = money/coinunit[i]; // 2. 배열 coin에서 coinnum 만큼의동전을뺀다. // ( 만일충분한동전이없다면배열 coin 에있는만큼만뺀다.) if(coin[i] >= coinnum) { coin[i] -= coinnum; else { coinnum = coin[i]; coin[i] = 0; // 3. 금액에서동전의개수(coinNum) 와동전단위를곱한값을뺀다. money -= coinnum*coinunit[i]; System.out.println(coinUnit[i]+" 원: "+coinnum); if(money > 0) { System.out.println(" 거스름돈이부족합니다."); System.exit(0); // 프로그램을종료한다. System.out.println("= 남은동전의개수 ="); for(int i=0;i<coinunit.length;i++) {

Java의정석定石 211 System.out.println(coinUnit[i]+" 원:"+coin[i]); // main [ 실행결과] C:\jdk1.8\work\ch5>java Exercise5_7 USAGE: java Exercise5_7 3120 C:\jdk1.8\work\ch5>java Exercise5_7 3170 money=3170 500 원: 5 100 원: 5 50 원: 3 10 원: 2 = 남은동전의개수 = 500 원:0 100 원:0 50 원:2 10 원:3 C:\jdk1.8\work\ch5>java Exercise5_7 3510 money=3510 500 원: 5 100 원: 5 50 원: 5 10 원: 5 거스름돈이부족합니다. [ 정답] // 1. 금액(money) 을동전단위로나눠서필요한동전의개수(coinNum) 를구한다. coinnum = money/coinunit[i]; // 2. 배열 coin에서 coinnum 만큼의동전을뺀다. // ( 만일충분한동전이없다면배열 coin 에있는만큼만뺀다.) if(coin[i] >= coinnum) { coin[i] -= coinnum; else { coinnum = coin[i]; coin[i] = 0; // 3. 금액에서동전의개수(coinNum) 와동전단위를곱한값을뺀다. money -= coinnum*coinunit[i]; [ 해설] 주어진로직대로만작성하면별어려움없이풀수있었을것이라생각한다. 문제 5-6 을이해했다면이문제도쉽게이해될것이므로자세한설명은생략한다. 이예제를발전시켜자판기프로그램을작성해보면좋은공부가될것이다.

212 Java의정석定石 [5-8] 다음은배열 answer 에담긴데이터를읽고각숫자의개수를세어서개수만큼 * 을찍어서그래프를그리는프로그램이다. (1)~(2) 에알맞은코드를넣어서완성하시오. [ 연습문제]/ch5/Exercise5_8.java class Exercise5_8 { public static void main(string[] args) { int[] answer = { 1,4,4,3,1,4,4,2,1,3,2 ; int[] counter = new int[4]; for(int i=0; i < answer.length;i++) { counter[answer[i]-1]++; for(int i=0; i < counter.length;i++) { System.out.print(counter[i]); for(int j=0; j < counter[i];j++) { System.out.print("*"); // counter[i] 의값만큼 * 을찍는다. System.out.println(); // end of main // end of class 실행결과 [ ] 3*** 2** 2** 4**** [ 정답] (1) counter[answer[i]-1]++; (2) System.out.print(counter[i]); for(int j=0; j < counter[i];j++) { System.out.print("*"); [ 해설] 배열을이용해서데이터의개수를세는문제이다. 1~4범위의데이터를집계할것 이기때문에크기가 4 인배열(counter) 을생성하였다. 크기가 4이지만배열의 index는 0~3이기때문에 answer[i] 에서 1 을빼주어야한다. counter[answer[i]-1]++; Java의정석 3판의예제5-11 과거의동일하므로자세한설명은생략한다. 다만, Java의 정석소스압축파일에있는플래시동영상'/flash/Array.swf' 을보면단계별로자세히설 명되어있으니참고하기바란다. Java의정석소스압축파일은 http://cafe.naver.com/javachobostudy 에서얻을수있다.

Java의정석定石 213 [5-9] 주어진배열을시계방향으로 90 도회전시켜서출력하는프로그램을완성하시오. [ 연습문제]/ch5/Exercise5_9.java class Exercise5_9 { public static void main(string[] args) { char[][] star = { {'*','*',' ',' ',' ', {'*','*',' ',' ',' ', {'*','*','*','*','*', {'*','*','*','*','*' ; char[][] result = new char[star[0].length][star.length]; for(int i=0; i < star.length;i++) { for(int j=0; j < star[i].length;j++) { System.out.print(star[i][j]); System.out.println(); System.out.println(); for(int i=0; i < star.length;i++) { for(int j=0; j < star[i].length;j++) { int x = j; int y = star.length-1-i; result[x][y]=star[i][j]; for(int i=0; i < result.length;i++) { for(int j=0; j < result[i].length;j++) { System.out.print(result[i][j]); System.out.println(); // end of main // end of class [ 실행결과] ** ** ***** ***** **** **** ** ** ** [ 정답] int x = j; int y = star.length-1-i; result[x][y]=star[i][j];

214 Java의정석定石 [ 해설] 테트리스의도형을회전시키듯이배열을회전시키는문제이다. 배열 star가 4 5 의 2차원배열이므로이배열을 90도회전시키면 5 4 의 2 차원배열이되어야한다. char[][] result = new char[star[0].length][star.length]; 배열 star를시계방향으로회전시켜서만든배열 result를그림으로그려보면다음과같 다. 배열 star 배열 result star.length * * * * * * * * * 시계방향 90 회전 * * * * * * * * * * * * * * * * * star[0].length * * result 배열을생성했으니, 이제배열 star의요소들을배열 result의적절한위치로옮기 면된다. 원래의위치를 (i,j), 옮길위치를 (x, y) 라고할때 i와 j의값을이용해서 x 와 y 의값을어떻게계산해낼것인지를고민해보자. for(int i=0; i < star.length;i++) { for(int j=0; j < star[i].length;j++) { int x =???; int y =???; result[x][y]=star[i][j]; // (i,j) (x,y) 배열 star 배열 result 0,0 0,1 0,2 0,3 0,4 0,0 0,1 0,2 0,3 star.length 1,0 1,1 1,2 1,3 1,4 시계방향 90 회전 1,0 1,1 1,2 1,3 2.0 2,1 2,2 2,3 2,4 2,0 2,1 2,2 2,3 3,0 3,1 3,2 3,3 3,4 3,0 3,1 3,2 3,3 star[0].length 4,0 4,1 4,2 4,3 위그림은배열의인덱스를표시한것인데, star[0][0] 은 result[0][3] 으로, star[0][1] 은 result[1][3] 으로이동해야함을알수있다. 이것을표로정리하면다음과같다.

Java의정석定石 215 i j 0 0 0 1 0 2 0 3 1 0 1 1...... 3 2 3 3 3 4 x y 0 3 1 3 2 3 3 3 0 2 1 2...... 2 0 3 0 4 0 위의표를보면, x의값은 j 의값과정확히일치함을알수있다. 그래서 x의값은 j의 값을그대로가져다쓰면된다. y 의값을보면, i와 y 의합이일정함을알수있다. i와 y의합은항상 3 이다. 3은 star.length-1 과동일한값이다. 'i+y = star.length-1' 이니까, 'y = star.length-1-i' 라고할수있다. for(int i=0; i < star.length;i++) { for(int j=0; j < star[i].length;j++) { int x = j; int y = star.length-1-i; result[x][y]=star[i][j]; // (i,j) (x,y) 익숙하지않겠지만이렇게그림을그리고표를그리면쉽게해결된다. 코딩을하기전에종이에그림을그리고로직을정리하는것은모니터를보는시간을줄여서눈의피로를적게하고, 논리적오류를줄여줄수있다는장점이있다.

216 Java의정석定石 [5-10] 다음은알파벳과숫자를아래에주어진암호표로암호화하는프로그램이다. (1) 에알맞은코드를넣어서완성하시오. a b c d e f g h i j k l m n o p q r s t ` ~! @ # $ % ^ & * ( ) - _ + = [ ] { u v w x y z ; :,. / 0 1 2 3 4 5 6 7 8 9 q w e r t y u i o p [ 연습문제]/ch5/Exercise5_10.java class Exercise5_10 { public static void main(string[] args) { char[] abccode = { '`','~','!','@','#','$','%','^','&','*', '(',')','-','_','+','=',' ','[',']','{', '',';',':',',','.','/'; // 0 1 2 3 4 5 6 7 8 9 char[] numcode = {'q','w','e','r','t','y','u','i','o','p'; String src = "abc123"; String result = ""; // 문자열 src의문자를 charat() 으로하나씩읽어서변환후 result에저장 for(int i=0; i < src.length();i++) { char ch = src.charat(i); if('a' <= ch && ch <='z') { result += abccode[ch-'a']; else if('0' <= ch && ch <='9') { result += numcode[ch-'0']; System.out.println("src:"+src); System.out.println("result:"+result); // end of main // end of class 실행결과 [ ] src:abc123 result:`~!wer [ 정답] if('a' <= ch && ch <='z') { result += abccode[ch-'a']; else if('0' <= ch && ch <='9') { result += numcode[ch-'0'];

Java의정석定石 217 [ 해설] 문자열을반복문과 chatat(int i) 을이용해서, 한문자씩배열에있는암호코드로 변경해서암호화하는문제이다. 암호코드는영어소문자와숫자로나뉘어져있는데, 영어소문자인경우배열 abccode에서 해당암호코드를얻고, 숫자인경우에는배열 numcode 에서암호코드를얻도록되어있다. 그래서조건문으로문자가영어소문자인경우와숫자인경우를나누어서처리했다. if('a' <= ch && ch <='z') { result += abccode[ch-'a']; else if('0' <= ch && ch <='9') { result += numcode[ch-'0']; 암호코드배열 abccode 에는문자 'a' 시작해서문자 'z' 까지의암호코드가순서대로저장되 어있기때문에문자 'a' 의암호코드는 abccode[0] 이고, 문자 'c' 의암호코드는 abccode[2] 이다. 즉, 영어소문자 ch의암호코드는 abccode[ch-'a'] 로표현할수있는것 이다. 만일문자 ch 가 'c' 였다면, 조건식 'a' <= ch && ch <='z' 가 true가되어 result+= abcc ode[ch-'a']; 가수행된다. 이문장은아래와같은순서로연산이진행된다. result+= abccode[ch-'a']; result+= abccode['c'-'a']; result+= abccode[2]; result+= '!'; 알파벳이나숫자는문자코드가연속적으로할당되어있기때문에, 'c' 에서 'a' 를빼면 2 를결과로얻는다. 'c'-'a' 99-97 2 뺄셈과같은이항연산자는 int 타입보다작은타입은피연산자(byte, short, char) 은 int 로변환한다. 그래서 'c'-'a' 은 99-97로변환되고그결과는숫자 2 가된다. 참고로문 자 'a' 와 'c' 의코드는아래와같다. 문자 문자코드...... a 97 b 98 c 99 d 100......

218 Java의정석定石 [5-11] 주어진 2차원배열의데이터보다가로와세로로 1이더큰배열을생성해서배열 의행과열의마지막요소에각열과행의총합을저장하고출력하는프로그램이다. (1) 에알맞은코드를넣어서완성하시오. [ 연습문제]/ch5/Exercise5_11.java class Exercise5_11 { public static void main(string[] args) { int[][] score = { {100, 100, 100, {20, 20, 20, {30, 30, 30, {40, 40, 40, {50, 50, 50 ; int[][] result = new int[score.length+1][score[0].length+1]; for(int i=0; i < score.length;i++) { for(int j=0; j < score[i].length;j++) { result[i][j] = score[i][j]; result[i][score[0].length] += result[i][j]; result[score.length][j] += result[i][j]; result[score.length][score[0].length] += result[i][j]; for(int i=0; i < result.length;i++) { for(int j=0; j < result[i].length;j++) { System.out.printf("%4d",result[i][j]); System.out.println(); // main [ 실행결과] 100 100 100 300 20 20 20 60 30 30 30 90 40 40 40 120 50 50 50 150 240 240 240 720 [ 정답] result[i][j] = score[i][j]; result[i][score[0].length] += result[i][j]; result[score.length][j] += result[i][j]; result[score.length][score[0].length] += result[i][j]; [ 해설] 2 차원배열의복사를조금응용한문제이다. 2차원배열 score에담긴값들을 2차 원배열 result에복사하되배열 result 의맨오른쪽열에는각행의총합이, 그리고맨

Java의정석定石 219 마지막행에는각열의총합이, 마지막으로맨오른쪽행의마지막열에는전체총합이 저장되어야한다. 언뜻복잡해보이지만그림을그려보면간단명료해진다. 먼저 score[i][j] 를 result[i][j] 에저장하고, result[i][j] 는아래그림에표시한세 곳에누적해서더해주면된다. 배열 score 100 100 100 20 20 20 30 30 30 40 40 40 50 50 50 result[i][j] 배열 result 100 +100 result[i][result[0].length-1] +100 +100 result[result.length-1][j] result[result.length-1][result[0].length-1] result.length-1과 result[0].length-1은 score.length와 score[0].length와각각동일 하므로보다식을간단히하기위해대체해서사용했는데, 반드시그렇게해야하는것은 아니다. result.length-1 score.length result[0].length-1 score[0].length score[i][j] 의값을 result[i][j] 에저장하기때문에, result[i][j] 대신 score[i][j] 를 사용해도같은결과를얻는다. result[i][score[0].length] += score[i][j]; result[score.length][j] += score[i][j]; result[score.length][score[0].length] += score[i][j];

220 Java의정석定石 [5-12] 예제5-23 을변경하여, 아래와같은결과가나오도록하시오. [ 실행결과] Q1. chair 의뜻은? dmlwk 틀렸습니다. 정답은의자입니다 Q2. computer 의뜻은? 컴퓨터정답입니다. Q3. integer 의뜻은? 정수정답입니다. 전체 3문제중 2 문제맞추셨습니다. [ 정답] [ 연습문제]/ch5/Exercise5_12.java import java.util.*; class Exercise5_12 { public static void main(string[] args) { String[][] words = { {"chair"," 의자", // words[0][0], words[0][1] {"computer"," 컴퓨터", // words[1][0], words[1][1] {"integer"," 정수" // words[2][0], words[2][1] ; int score = 0; // 맞춘문제의수를저장하기위한변수 Scanner scanner = new Scanner(System.in); for(int i=0;i<words.length;i++) { System.out.printf("Q%d. %s 의뜻은?", i+1, words[i][0]); String tmp = scanner.nextline(); if(tmp.equals(words[i][1])) { System.out.printf(" 정답입니다.%n%n"); score++; else { System.out.printf(" 틀렸습니다. 정답은 %s 입니다.%n%n",words[i][1]); // for System.out.printf(" 전체 %d 문제중 %d 문제맞추셨습니다.%n", words.length, score); // main의끝 [ 해설] 맞춘문제의수를저장하기위한변수하나를추가하고, 정답을맞추면이변수의 값을증가시키기만하면된다.

Java의정석定石 221 [5-13] 단어의글자위치를섞어서보여주고원래의단어를맞추는예제이다. 실행결과와 같이동작하도록예제의빈곳을채우시오. [ 연습문제5-13]/ch5/Excercise5_13.java import java.util.scanner; class Exercise5_13 { public static void main(string args[]) { String[] words = { "television", "computer", "mouse", "phone" ; Scanner scanner = new Scanner(System.in); for(int i=0;i<words.length;i++) { char[] question = words[i].tochararray(); // String을 char[] 로변환 for(int j=0;j<question.length;j++) { int idx = (int)(math.random() * question.length); char tmp = question[i]; question[i] = question[idx]; question[idx] = tmp; System.out.printf("Q%d. %s 의정답을입력하세요.>", i+1, new String(question)); String answer = scanner.nextline(); // trim() 으로 answer 의좌우공백을제거한후, equals로 word[i] 와비교 if(words[i].equals(answer.trim())) System.out.printf(" 맞았습니다.%n%n"); else System.out.printf(" 틀렸습니다.%n%n"); // main의끝 [ 실행결과] Q1. lvtsieeoin 의정답을입력하세요.>television 맞았습니다. Q2. otepcumr 의정답을입력하세요.>computer 맞았습니다. Q3. usemo 의정답을입력하세요.>asdf 틀렸습니다. Q4. ohpne 의정답을입력하세요.>phone 맞았습니다. [ 정답] for(int j=0;j<question.length;j++) { int idx = (int)(math.random() * question.length);

222 Java의정석定石 char tmp = question[i]; question[i] = question[idx]; question[idx] = tmp; [ 해설] 예제5-8 을응용한문제이다. 간단한문제이므로설명은생략한다.

Java의정석定石 223 [ 연습문제 - 모범답안 ] [6-1] 다음과같은멤버변수를갖는 SutdaCard 클래스를정의하시오. 타입변수명설명 int num 카드의숫자.(1~10 사이의정수) boolean iskwang 광( 光 ) 이면 true, 아니면 false [ 정답] class SutdaCard { int num; boolean iskwang;

224 Java의정석定石 [6-2] 문제6-1에서정의한 SutdaCard클래스에두개의생성자와 info() 를추가해서실행 결과와같은결과를얻도록하시오. [ 연습문제]/ch6/Exercise6_2.java class Exercise6_2 { public static void main(string args[]) { SutdaCard card1 = new SutdaCard(3, false); SutdaCard card2 = new SutdaCard(); System.out.println(card1.info()); // 3 이출력된다. System.out.println(card2.info()); // 1K 가출력된다. class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); // SutdaCard(1, true) 를호출한다. SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; String info() { // 숫자를문자열로반환한다. 광( 光 ) 인경우 K 를덧붙인다. return num + ( iskwang? "K" : ""); 실행결과 [ ] 3 1K [ 해설] 객체를생성할때두개의생성자를사용했으므로두개의생성자를정의해야한 다. SutdaCard card1 = new SutdaCard(3, false); // 3 SutdaCard card2 = new SutdaCard(); // 1K 일단매개변수가있는생성자를살펴보면, 카드의 num과 iskwang의값을매개변수로받는 것을알수있다. 그리고매개변수가없는기본생성자는실행결과에서 "1K" 가출력된것 으로봐서 num과 iskwang의값을각각 1과 true 로하였다는것을알수있다.

Java의정석定石 225 SutdaCard() { this.num = 1; this.iskwang = true; SutdaCard(int num, boolean iskwan g) { this.num = num; this.iskwang = iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwan g) { this.num = num; this.iskwang = iskwang; 매개변수가없는기본생성자를정의할때, 왼쪽의코드와같이할수도있지만오른쪽 코드와같이기존의코드를호출하는것이더좋은코드이다. 재사용성이더높고나중에 코드를수정할때도유리하다. info() 메서드는 card 인스턴스의정보를문자열로반환하기위한것이다. card인스턴스의 멤버변수 num와 iskwang 의값을문자열로만들어서반환하면된다. iskwang의값이 true 인경우에는숫자뒤에 "K" 를붙이도록삼항연산자를사용했다. String info() { // 숫자를문자열로반환한다. 광( 光 ) 인경우 K 를덧붙인다. return num + ( iskwang? "K" : ""); 변수 num은타입이 int이지만문자열과덧셈연산을하기때문에최종적으로는문자열을 반환하게된다.

226 Java의정석定石 [6-3] 다음과같은멤버변수를갖는 Student 클래스를정의하시오. 타입 변수명 설명 String name 학생이름 int ban 반 int no 번호 int kor 국어점수 int eng 영어점수 int math 수학점수 [ 정답] class Student { String name; int ban; int no; int kor; int eng; int math;

Java의정석定石 227 [6-4] 문제6-3에서정의한 Student클래스에다음과같이정의된두개의메서드 gettotal() 과 getaverage() 를추가하시오. 1. 메서드명 : gettotal 기능 : 국어(kor), 영어(eng), 수학(math) 의점수를모두더해서반환한다. 반환타입 : int 매개변수 : 없음 2. 메서드명 : getaverage 기 능 : 총점( 국어점수+ 영어점수+ 수학점수) 을과목수로나눈평균을구한다. 소수점둘째자리에서반올림할것. 반환타입 : float 매개변수 : 없음 [ 연습문제]/ch6/Exercise6_4.java class Exercise6_4 { public static void main(string args[]) { Student s = new Student(); s.name = " 홍길동"; s.ban = 1; s.no = 1; s.kor = 100; s.eng = 60; s.math = 76; System.out.println(" 이름:"+s.name); System.out.println(" 총점:"+s.getTotal()); System.out.println(" 평균:"+s.getAverage()); class Student { String name; int ban; int no; int kor; int eng; int math; int gettotal() { return kor + eng + math; float getaverage() { return (int)(gettotal() / 3f * 10 + 0.5f) / 10f; [ 실행결과] 이름: 홍길동총점 :236 평균 :78.7 [ 정답] class Student {

228 Java의정석定石 String name; int ban; int no; int kor; int eng; int math; int gettotal() { return kor + eng + math; float getaverage() { return (int)(gettotal() / 3f * 10 + 0.5f) / 10f; [ 해설] 총점과평균을구하는문제인데, 평균을구할때소수점둘째자리에서반올림을 하는부분에서생각을좀해야할것이다. 총점의타입이 int이기때문에 3으로나누면 int와 int간의연산이므로결과를 int로얻 는다. 즉, 소수점이하의값은버려지게된다. 그래서 float타입의리터럴인 3f로나누어 야소수점이하의값들을얻을수있다. 그리고, 소수점둘째자리에서반올림하려면 10 을곱하고 0.5를더한다음다시 10f 로나누면된다. 236 / 3 78 236 / 3f 78.666664 236 / 3f * 10 786.66664 236 / 3f * 10 + 0.5 787.16664 (int)(236 / 3f * 10 + 0.5) (int)787.16664 787 (int)(236 / 3f * 10 + 0.5) / 10 78 (int)(236 / 3f * 10 + 0.5) / 10f 78.7

Java의정석定石 229 [6-5] 다음과같은실행결과를얻도록 Student클래스에생성자와 info() 를추가하시오. [ 연습문제]/ch6/Exercise6_5.java class Exercise6_5 { public static void main(string args[]) { Student s = new Student(" 홍길동",1,1,100,60,76); System.out.println(s.info()); class Student { String name; int ban; int no; int kor; int eng; int math; Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; int gettotal() { return kor+eng+math; float getaverage() { return (int)(gettotal() / 3f * 10 + 0.5f) / 10f; public String info() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage() ; 실행결과 [ ] 홍길동,1,1,100,60,76,236,78.7 [ 해설] 학생의이름, 반, 번호, 과목별성적을매개변수로받는생성자를추가하고, 학생 의정보를출력하는 info() 메서드를정의하는문제이다. 답을보는것만으로도충분히이 해할수있는문제이므로설명은생략한다.

230 Java의정석定石 [6-6] 두점의거리를계산하는 getdistance() 를완성하시오. [Hint] 제곱근계산은 Math.sqrt(double a) 를사용하면된다. [ 연습문제]/ch6/Exercise6_6.java class Exercise6_6 { // 두점 (x,y) 와 (x1,y1) 간의거리를구한다. static double getdistance(int x, int y, int x1, int y1) { return Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1)); // x, y는지역변수 public static void main(string args[]) { System.out.println(getDistance(1,1,2,2)); 실행결과 [ ] 1.4142135623730951 [ 정답] return Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1)); [ 해설] 두점 (x, y) 와 (x1, y1) 의거리를구하는공식은 이다. 제곱근계산은 Math클래스의 sqrt(double a) 를사용하면된다. 제곱도 Math.pow(double a, double b) 를사용하면되지만, 2 제곱이므로그냥곱셈연산자를사용했다. 어느쪽을 사용해도괜찮지만, 메서드를호출하는것은곱셈연산보다비용이많이드는작업이라는 것은기억해두자. 그렇다고해서보다빠른코드를만들겠다고코드를복잡하게하는것 은좋지않다. 참고로 Math.pow(double a, double b) 를사용한코드는다음과같다. static double getdistance(int x, int y, int x1, int y1) { return Math.sqrt(Math.pow(x-x1,2) + Math.pow(y-y1,2));

Java의정석定石 231 [6-7] 문제6-6에서작성한클래스메서드 getdistance() 를 MyPoint클래스의인스턴스메서 드로정의하시오. [ 연습문제]/ch6/Exercise6_7.java class MyPoint { int x; // 인스턴스변수 int y; // 인스턴스변수 MyPoint(int x, int y) { this.x = x; this.y = y; double getdistance(int x1, int y1) { return Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1)); // x, y는인스턴스변수 class Exercise6_7 { public static void main(string args[]) { MyPoint p = new MyPoint(1,1); // p 와 (2,2) 의거리를구한다. System.out.println(p.getDistance(2,2)); 실행결과 [ ] 1.4142135623730951 [ 정답] double getdistance(int x1, int y1) { return Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1)); [ 해설] 이전문제의 static 메서드를인스턴스메서드로변경하는문제인데, static메서드 와인스턴스메서드의차이를이해하는것은매우중요하다. static 메서드인경우에는메서드내에서인스턴스변수를사용하지않았다. 대신매개변 수( 지역변수) 로작업에필요한값을제공받아야했다. 그래서, 인스턴스와관계가없으므 로( 인스턴스변수를사용안했으니까) static 메서드로선언할수있는것이다. static double getdistance(int x, int y, int x1, int y1) { return Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1)); // x, y는지역변수 그러나, 인스턴스메서드는인스턴스변수 x, y를사용해서작업하므로매개변수로 x1과 y1 만을제공받으면된다. 인스턴스와관계가있으므로( 인스턴스변수를사용했으니까) static 을붙일수없다. double getdistance(int x1, int y1) { return Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1));// x, y는인스턴스변수

232 Java의정석定石 아래의코드는인스턴스메서드를사용할때와 주기위한것이다. 어떤차이가있는지잘살펴보자. static메서드를사용할때의차이를보여 1. static 메서드의사용 System.out.println(Exercise6_6.getDistance(1,1,2,2)); 2. 인스턴스메서드의사용 MyPoint p = new MyPoint(1,1); System.out.println(p.getDistance(2,2)); MyPoint클래스에두점간의거리를계산하는메서드 getdistance() 를넣는다면, static메 서드보다는인스턴스메서드로정의하는것이더적합하다.

Java의정석定石 233 [6-8] 다음의코드에정의된변수들을종류별로구분해서적으시오. class PlayingCard { int kind; int num; static int width; static int height; PlayingCard(int k, int n) { kind = k; num = n; public static void main(string args[]) { PlayingCard card = new PlayingCard(1,1); - 클래스변수(static 변수) : width, height - 인스턴스변수 : kind, num - 지역변수 : k, n, card, args [ 해설] 변수가선언된위치를보면변수의종류를알수있다. 클래스블럭{ 내에선언된 변수는인스턴스변수이고, static이붙은것은 static 변수( 클래스변수) 이다. 그리고나 머지는모두지역변수이다. class Variables { int iv; // 인스턴스변수 static int cv; // 클래스변수(static 변수, 공유변수) 클래스영역 void method() { int lv = 0; // 지역변수 메서드영역 변수의종류선언위치생성시기 클래스변수 (class variable) 인스턴스변수 (instance variable) 지역변수 (local variable) 클래스영역 클래스영역이외의영역 ( 메서드, 생성자, 초기화블럭내부) 클래스가메모리에올라갈때 인스턴스가생성되었을때 변수선언문이수행되었을때

234 Java의정석定石 [6-9] 다음은컴퓨터게임의병사(marine) 를클래스로정의한것이다. 이클래스의멤버 중에 static 을붙여야하는것은어떤것들이고그이유는무엇인가? ( 단, 모든병사의공격력과방어력은같아야한다.) class Marine { int x=0, y=0; // Marine 의위치좌표(x,y) int hp = 60; // 현재체력 static int weapon = 6; // 공격력 static int armor = 0; // 방어력 static void weaponup() { weapon++; static void armorup() { armor++; void move(int x, int y) { this.x = x; // this.x 는인스턴스변수, x는지역변수 this.y = y; // this.y 는인스턴스변수, y는지역변수 [ 정답] weapon, armor - 모든 Marine 인스턴스에대해동일한값이어야하므로. weaponup(), armorup() - static 변수에대한작업을하는메서드이므로 [ 해설] 인스턴스마다개별적인값을가져야하는변수는인스턴스변수로, 모든인스턴스가 공통적인값을가져야하는변수는클래스변수(static 변수) 로선언해야한다. 그래서위의코드에서어떤변수들이모든인스턴스에서공통적인적인값을가져야하는 지알아내야한다. 병사(marin) 의위치는모든병사가서로다른위치에있어야하므로개별적인값이어야 하고, 병사들마다부상의정도가다를것이므로병사들의체력(hp) 역시개별적인값이어 야한다. 그러나모든병사들의공격력과방어력은같아야한다.( 게임이니까) 그래서공격력을의미하는변수 weapon과방어력을의미하는변수 armor에 static을붙 어야한다. 그다음은메서드인데, 어떤메서드에 static을붙이고어떤메서드에는 static을붙이 지않아야하는것일까? 메서드는어떠한작업을하는것인데, 이작업을할때인스턴스변수를사용하면인스턴 스메서드로하고, 그렇지않으면 static 메서드로하면된다. 보통인스턴스메서드는인 스턴스변수와관련된작업을하고, static메서드는 static변수와관련된작업을하기때 문이다. 메서드 weaponup() 과 armorup() 은각각 static변수 weapon과 armor를가지고작업을하 기때문에 static 을붙이는것이맞다. 반면에메서드 move(int x, int y) 는인스턴스변 수 x와 y를가지고작업하기때문에 static 을붙여서는안된다.

Java의정석定石 235 [6-10] 다음중생성자에대한설명으로옳지않은것은? ( 모두고르시오) a. 모든생성자의이름은클래스의이름과동일해야한다. b. 생성자는객체를생성하기위한것이다. c. 클래스에는생성자가반드시하나이상있어야한다. d. 생성자가없는클래스는컴파일러가기본생성자를추가한다. e. 생성자는오버로딩할수없다. [ 정답] b, e [ 해설] b. 생성자는객체를생성하기위한것이다. 생성자가객체를생성할때사용되기는하지만, 객체를초기화할목적으로사용되는 것이다. 객체를생성하는것은 new 연산자이다. e. 생성자는오버로딩할수없다. 생성자도오버로딩이가능해서하나의클래스에여러개의생성자를정의할수있 다.

236 Java의정석定石 [6-11] 다음중 this 에대한설명으로맞지않은것은? ( 모두고르시오) a. 객체자신을가리키는참조변수이다. b. 클래스내에서라면어디서든사용할수있다. 인스턴스메서드에서만사용가능 c. 지역변수와인스턴스변수를구별할때사용한다. d. 클래스메서드내에서는사용할수없다. [ 정답] b [ 해설] b. 클래스내에서라면어디서든사용할수있다. 클래스멤버(static 이붙은변수나메서드) 에는사용할수없다. this 는인스턴스자신의주소를저장하고있으며, 모든인스턴스메서드에숨겨진채로존재하는지역변수이다. 그래서인스턴스메서드내에서만사용할수있다.

Java의정석定石 237 [6-12] 다음중오버로딩이성립하기위한조건이아닌것은? ( 모두고르시오) a. 메서드의이름이같아야한다. b. 매개변수의개수나타입이달라야한다. c. 리턴타입이달라야한다. d. 매개변수의이름이달라야한다. [ 정답] c, d [ 해설] c. 리턴타입이달라야한다. 리턴타입은오버로딩에영향을주지못한다. d. 매개변수의이름이달라야한다. 리턴타입은오버로딩에영향을주지못한다. << 오버로딩의조건 >> 1. 메서드이름이같아야한다. 2. 매개변수의개수또는타입이달라야한다. 3. 매개변수는같고리턴타입이다른경우는오버로딩이성립되지않는다. ( 리턴타입은오버로딩을구현하는데아무런영향을주지못한다.)

238 Java의정석定石 [6-13] 다음중아래의 add 메서드를올바르게오버로딩한것은? ( 모두고르시오) long add(int a, int b) { return a+b; a. long add(int x, int y) { return x+y; b. long add(long a, long b) { return a+b; c. int add(byte a, byte b) { return a+b; d. int add(long a, int b) { return (int)(a+b); [ 정답] b, c, d [ 해설] b, c, d는모두메서드의이름이 add이고매개변수의타입이다르므로오버로딩이 성립한다. 오버로딩이성립하기위한조건은다음과같다. << 오버로딩의조건 >> 1. 메서드이름이같아야한다. 2. 매개변수의개수또는타입이달라야한다. 3. 매개변수는같고리턴타입이다른경우는오버로딩이성립되지않는다. ( 리턴타입은오버로딩을구현하는데아무런영향을주지못한다.)

Java의정석定石 239 [6-14] 다음중초기화에대한설명으로옳지않은것은? ( 모두고르시오) a. 멤버변수는자동초기화되므로초기화하지않고도값을참조할수있다. b. 지역변수는사용하기전에반드시초기화해야한다. c. 초기화블럭보다생성자가먼저수행된다. 초기화블럭이먼저수행된다. d. 명시적초기화를제일우선적으로고려해야한다. e. 클래스변수보다인스턴스변수가먼저초기화된다. 클래스변수가먼저초기화됨 [ 정답] c, e [ 해설] 클래스변수는클래스가처음메모리에로딩될때, 자동초기화되므로인스턴스변 수보다먼저초기화된다. 그리고생성자는초기화블럭이수행된다음에수행된다.

240 Java의정석定石 [6-15] 다음중인스턴스변수의초기화순서가올바른것은? a. 기본값-명시적초기화-초기화블럭-생성자 b. 기본값-명시적초기화-생성자-초기화블럭 c. 기본값-초기화블럭-명시적초기화-생성자 d. 기본값-초기화블럭-생성자-명시적초기화 [ 정답] a [ 해설] 변수의초기화순서는다음과같다. 클래스변수의초기화시점 인스턴스변수의초기화시점 : 클래스가처음로딩될때단한번초기화된다. : 인스턴스가생성될때마다각인스턴스별로초기화가이루어진다. 클래스변수의초기화순서 : 기본값 명시적초기화 클래스초기화블럭 인스턴스변수의초기화순서 : 기본값 명시적초기화 인스턴스초기화블럭 생성자

Java의정석定石 241 [6-16] 다음중지역변수에대한설명으로옳지않은것은? ( 모두고르시오) a. 자동초기화되므로별도의초기화가필요없다. b. 지역변수가선언된메서드가종료되면지역변수도함께소멸된다. c. 매서드의매개변수로선언된변수도지역변수이다. d. 클래스변수나인스턴스변수보다메모리부담이적다. e. 힙(heap) 영역에생성되며가비지컬렉터에의해소멸된다. [ 정답] a, e [ 해설] 지역변수는자동초기화되지않기때문에사용하기전에반드시적절한값으로 초기화를해주어야한다. 지역변수는자신이선언된블럭이나메서드가종료되면소멸되므 로메모리부담이적다. 힙(heap) 영역에는인스턴스( 인스턴스변수) 가생성되는영역이며, 지역변수는호출스택(call stack) 에생성된다.

242 Java의정석定石 [6-17] 호출스택이다음과같은상황일때옳지않은설명은? ( 모두고르시오) println method1 method2 main a. 제일먼저호출스택에저장된것은 main 메서드이다. b. println 메서드를제외한나머지메서드들은모두종료된상태이다. c. method2메서드를호출한것은 main 메서드이다. d. println메서드가종료되면 method1 메서드가수행을재개한다. e. main-method2-method1-println 의순서로호출되었다. f. 현재실행중인메서드는 println 뿐이다. [ 정답] b [ 해설] 호출스택의제일위에있는메서드가현재수행중인메서드이며, 호출스택안의 나머지메서드들은대기상태이다.

Java의정석定石 243 [6-18] 다음의코드를컴파일하면에러가발생한다. 컴파일에러가발생하는라인과그 이유를설명하시오. class MemberCall { int iv = 10; static int cv = 20; int iv2 = cv; static int cv2 = iv; // 라인 A - 컴파일에러 static void staticmethod1() { System.out.println(cv); System.out.println(iv); // 라인 B - 컴파일에러 void instancemethod1() { System.out.println(cv); System.out.println(iv); // 라인 C static void staticmethod2() { staticmethod1(); instancemethod1(); // 라인 D - 컴파일에러 void instancemethod2() { staticmethod1(); instancemethod1(); // 라인 E [ 정답] 라인 A, 라인 B, 라인 D [ 해설] 라인 A - static 변수의초기화에인스턴스변수를사용할수없다. 라인 라인 꼭사용해야한다면, 객체를생성해야한다. B - static 메서드에서는인스턴스변수를사용할수없다. D - static 메서드에서는인스턴스메서드를사용할수없다.

244 Java의정석定石 [6-19] 다음코드의실행결과를예측하여적으시오. [ 연습문제]/ch6/Exercise6_19.java class Exercise6_19 { public static void change(string str) { str += "456"; public static void main(string[] args) { String str = "ABC123"; System.out.println(str); change(str); System.out.println("After change:"+str); [ 정답] [ 실행결과] ABC123 After change:abc123 [ 해설] change 메서드의매개변수가참조형인데도왜? main메서드의문자열 str에변경한 내용이반영되지않은것일까? 많은사람들이매개변수가참조형이라는것만보고 main메 서드의문자열 str 이변경될것이라고쉽게생각한다. 누구라도실수하기쉬운부분이므 로주의하길바라는마음에서이문제를만들었다. 그림과함께단계별로설명하면어렵지않게이해할수있을것이다. 처음에문자열을참조변수 str 에저장하면아래와같은그림이된다. String str = "ABC123"; main str 0x100 "ABC123" 0x100 그다음에메서드 change를호출하면서참조변수 str 을넘겨주면, 메서드 change의지역 변수 str에주소값 0x100 이저장된다. 이제메서드 change의지역변수 str도문자열 "ABC123" 을참조하게된다. 이두참조변수는이름은같지만분명히다른변수이다. 서 로다른영역에존재하기때문에이름이같아도상관없는것이다.

Java의정석定石 245 change(str); // change를호출하면서문자열 str 을넘겨준다. change str 0x100 main str 0x100 "ABC123" 0x100 메서드 change 에서는넘겨받은문자열의뒤에 "456" 을붙인다. 문자열은내용을변경할 수없기때문에덧셈연산을하면새로운문자열이생성되고새로운문자열의주소가변수 str 에저장된다. public static void change(string str) { str += "456"; // 기존의문자열에 "456" 을붙인다. change str 0x200 "ABC123456" main str 0x100 0x200 "ABC123" 0x100 이제 change 메서드는종료되고, 작업에사용하던메모리를반환하므로 change메서드의지 역변수인 str 역시메모리에서제거된다. 다시 main메서드로돌아와서문자열 str의값을 출력하면처음의값과변함없는값이출력된다. 문자열 "ABC123456" 은참조하는변수가 하나도없으므로적절한시기에가비지컬렉터(garbage collector) 에의해제거된다. System.out.println("After change:"+str); "ABC123456" main str 0x100 0x200 "ABC123" 0x100

246 Java의정석定石 [6-20] 다음과같이정의된메서드를작성하고테스트하시오. [ 주의] Math.random() 을사용하는경우실행결과와다를수있음. 메서드명 : shuffle 기 능 : 주어진배열에담긴값의위치를바꾸는작업을반복하여뒤섞이게한다. 처리한배열을반환한다. 반환타입 : int[] 매개변수 : int[] arr - 정수값이담긴배열 [ 연습문제]/ch6/Exercise6_20.java class Exercise6_20 { public static int[] shuffle(int[] arr) { if(arr==null arr.length==0) return arr; for(int i=0; i< arr.length;i++) { int j = (int)(math.random()*arr.length); // arr[i] 와 arr[j] 의값을서로바꾼다. int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; return arr; public static void main(string[] args) { int[] original = {1,2,3,4,5,6,7,8,9; System.out.println(java.util.Arrays.toString(original)); int[] result = shuffle(original); System.out.println(java.util.Arrays.toString(result)); 실행결과 [ ] [1, 2, 3, 4, 5, 6, 7, 8, 9] [4, 6, 8, 3, 2, 9, 7, 1, 5] [ 정답] public static int[] shuffle(int[] arr) { if(arr==null arr.length==0) return arr; for(int i=0; i< arr.length;i++) { int j = (int)(math.random()*arr.length); // arr[i] 와 arr[j] 의값을서로바꾼다. int tmp = arr[i]; arr[i] = arr[j];

Java의정석定石 247 arr[j] = tmp; return arr; [ 해설] int배열을매개변수로받아서배열에저장된각요소들의위치를여러번바꿔서 섞은다음반환하는메서드이다. 매개변수로어떤값이넘어올지모르기때문에작업을시작하기전에값의유효성체크는 반드시해야한다. 아래의코드는넘겨받은배열이 null이거나크기가 0이면그대로반환 한다. if(arr==null arr.length==0) return arr; 반복문을이용해서반복적으로배열의임의의두요소의값을바꾼다. for(int i=0; i< arr.length;i++) { int j = (int)(math.random()*arr.length); // arr[i] 와 arr[j] 의값을서로바꾼다. int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; Math.random() 을사용하는방법이나두변수의값을바꾸는것에대한설명은이전문제 들에서했으므로생략하겠다.

248 Java의정석定石 [6-21] Tv 클래스를주어진로직대로완성하시오. 완성한후에실행해서주어진실행결과 와일치하는지확인하라. [ 참고] 코드를단순히하기위해서유효성검사는로직에서제외했다. [ 연습문제]/ch6/Exercise6_21.java class MyTv { boolean ispoweron; int channel; int volume; final int MAX_VOLUME = 100; final int MIN_VOLUME = 0; final int MAX_CHANNEL = 100; final int MIN_CHANNEL = 1; void turnonoff() { // (1) ispoweron의값이 true면 false 로, false면 true 로바꾼다. ispoweron =!ispoweron; void volumeup() { // (2) volume의값이 MAX_VOLUME보다작을때만값을 1 증가시킨다. if(volume < MAX_VOLUME) volume++; void volumedown() { // (3) volume의값이 MIN_VOLUME보다클때만값을 1 감소시킨다. if(volume > MIN_VOLUME) volume--; void channelup() { // (4) channel의값을 1 증가시킨다. // 만일 channel이 MAX_CHANNEL 이면, channel의값을 MIN_CHANNEL 로바꾼다. if(channel==max_channel) { channel = MIN_CHANNEL; else { channel++; void channeldown() { // (5) channel의값을 1 감소시킨다. // 만일 channel이 MIN_CHANNEL 이면, channel의값을 MAX_CHANNEL 로바꾼다. if(channel==min_channel) { channel = MAX_CHANNEL; else { channel--; // class MyTv class Exercise6_21 { public static void main(string args[]) { MyTv t = new MyTv();

Java의정석定石 249 t.channel = 100; t.volume = 0; System.out.println("CH:"+t.channel+", VOL:"+ t.volume); t.channeldown(); t.volumedown(); System.out.println("CH:"+t.channel+", VOL:"+ t.volume); t.volume = 100; t.channelup(); t.volumeup(); System.out.println("CH:"+t.channel+", VOL:"+ t.volume); 실행결과 [ ] CH:100, VOL:0 CH:99, VOL:0 CH:100, VOL:100 [ 해설] 답을보는것만으로도별도의설명이필요없을것이라생각한다. 혹시라도질문이 있으면 http://cafe.naver.com/javachobostudy.cafe 의게시판에올려주길바란다.

250 Java의정석定石 [6-22] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : isnumber 기능 : 주어진문자열이모두숫자로만이루어져있는지확인한다. 모두숫자로만이루어져있으면 true 를반환하고, 그렇지않으면 false 를반환한다. 만일주어진문자열이 null 이거나빈문자열 이라면 false 를반환한다. 반환타입 : boolean 매개변수 : String str - 검사할문자열 [Hint] String클래스의 charat(int i) 메서드를사용하면문자열의 i 번째위치한문자를얻을수있다. [ 연습문제]/ch6/Exercise6_22.java class Exercise6_22 { public static boolean isnumber(string str) { if(str==null str.equals("")) return false; for(int i=0; i< str.length();i++) { char ch = str.charat(i); if(ch < '0' ch > '9') { return false; // for return true; public static void main(string[] args) { String str = "123"; System.out.println(str+" 는숫자입니까? "+isnumber(str)); str = "1234o"; System.out.println(str+" 는숫자입니까? "+isnumber(str)); [ 실행결과] 123 는숫자입니까? true 1234o 는숫자입니까? false [ 해설] 매개변수로어떤값이넘어올지모르기때문에값의작업을시작하기전에유효성 체크는반드시해야한다. 아래의코드는넘겨받은문자열(str) 이 null이거나빈문자열 ("") 이면 false 를반환한다. if(str==null str.equals("")) return false;

Java의정석定石 251 반복문과 charat(int i) 을이용해서문자열에서한문자씩차례대로읽어와 char타입의 변수 ch 에저장한다. for(int i=0; i< str.length();i++) { char ch = str.charat(i); 읽어온문자(ch) 가숫자가아니면 false 를반환한다. 와같다 if(ch < '0' ch > '9') { // if(!('0'<=ch && ch<='9')). return false;

252 Java의정석定石 [6-23] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : max 기능 : 주어진 int 형배열의값중에서제일큰값을반환한다. 반환타입 : int 만일주어진배열이 null이거나크기가 0 인경우, -999999 를반환한다. 매개변수 : int[] arr - 최대값을구할배열 [ 연습문제]/ch6/Exercise6_23.java class Exercise6_23{ public static int max(int[] arr) { if(arr==null arr.length==0) return -999999; int max = arr[0]; // 배열의첫번째값으로최대값을초기화한다. for(int i=1; i< arr.length;i++) { // 배열의두번째값부터비교한다. if(arr[i] > max) max = arr[i]; return max; public static void main(string[] args) { int[] data = {3,2,9,4,7; System.out.println(java.util.Arrays.toString(data)); System.out.println(" 최대값:"+max(data)); System.out.println(" 최대값:"+max(null)); System.out.println(" 최대값:"+max(new int[]{)); // 크기가 0인배열 실행결과 [ ] [3, 2, 9, 4, 7] 최대값 :9 최대값 :-999999 최대값 :-999999 [ 해설] 매개변수로넘겨받은배열 arr이 null이거나크기가 0이면 -999999 을반환한다. if(arr==null arr.length==0) return -999999; 배열의첫번째요소(arr[0]) 로최대값(max) 을초기화한다. int max = arr[0]; // 배열의첫번째값으로최대값을초기화한다.

Java의정석定石 253 최대값 max 를배열의첫번째값으로초기화했으므로첫번째값은비교할필요가없다. 그래서두번째값(arr[1]) 부터비교한다. 비교해서최대값보다크면그값을변수 max에 저장한다. for(int i=1; i< arr.length;i++) { // 배열의두번째값부터비교한다. if(arr[i] > max) // 배열의 i번째요소가 max보다크면 max = arr[i]; 반복문을다돌고나면, max 에는배열의요소중가장큰값이저장되어있을것이다. 이 값을반환한다. return max;

254 Java의정석定石 [6-24] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : abs 기능 : 주어진값의절대값을반환한다. 반환타입 : int 매개변수 : int value [ 연습문제]/ch6/Exercise6_24.java class Exercise6_24 { public static int abs(int value) { return value >=0? value : -value; public static void main(string[] args) { int value = 5; System.out.println(value+" 의절대값:"+abs(value)); value = -10; System.out.println(value+" 의절대값:"+abs(value)); [ 실행결과] 5 의절대값:5-10 의절대값:10 [ 해설] value 의값이양수이면그대로반환하고, 음수이면부호를바꿔서반환하면된다. if 문을사용해도되지만삼항연산자를이용하면보다간결한코드를얻을수있다. 참고 로 if 문을사용한코드는다음과같다. public static int abs(int value) { if(value >=0) { return value; else { return -value; // value 가음수인경우, 부호를변경한다.

Java의정석定石 255 [ 연습문제 - 모범답안 ] [7-1] 섯다카드 20 장을포함하는섯다카드한벌(SutdaDeck 클래스) 을정의한것이다. 섯 다카드 20장을담는 SutdaCard 배열을초기화하시오. 단, 섯다카드는 1부터 10까지의숫자 가적힌카드가한쌍씩있고, 숫자가 1, 3, 8 인경우에는둘중의한장은광(Kwang) 이 어야한다. 즉, SutdaCard의인스턴스변수 iskwang의값이 true 이어야한다. [ 연습문제]/ch7/Exercise7_1.java class SutdaDeck { final int CARD_NUM = 20; SutdaCard[] cards = new SutdaCard[CARD_NUM]; SutdaDeck() { for(int i=0;i < cards.length;i++) { int num = i%10+1; boolean iskwang = (i < 10)&&(num==1 num==3 num==8); cards[i] = new SutdaCard(num,isKwang); class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; // info() 대신 Object클래스의 tostring() 을오버라이딩했다. public String tostring() { return num + ( iskwang? "K":""); class Exercise7_1 { public static void main(string args[]) { SutdaDeck deck = new SutdaDeck(); for(int i=0; i < deck.cards.length;i++) System.out.print(deck.cards[i]+","); 실행결과 [ ] 1K,2,3K,4,5,6,7,8K,9,10,1,2,3,4,5,6,7,8,9,10,

256 Java의정석定石 [ 해설] SutdaDeck클래스에 cards라는 SutdaCard 배열이정의되어있다. 이배열을생성했 다고해서 SutdarCard 인스턴스가생성된것은아니다. 그저 SutdaCard인스턴스를저장하 기위한공간을생성한것일뿐이다. 객체배열을생성할때, 배열만생성해놓고객체를 생성하지않는실수를하지않도록주의하자. SutdaCard[] cards = new SutdaCard[CARD_NUM]; 생성자를통해객체배열 SutdaCard에 SutdaCard 인스턴스를생성해서저장할차례다. 아래 와같이반복문을이용해서배열의크기만큼 SutdaCard 인스턴스를생성하면되는데, 이때 num의값과 iskwang 의값을어떻게계산해낼것인지를고민해야한다. SutdaDeck() { for(int i=0;i < cards.length;i++) { int num =???; boolean iskwang =???; cards[i] = new SutdaCard(num,isKwang); 아래의표에서볼수있는것처럼, i의값이 0~19까지변하는동안우리가원하는 num의 값을얻기위해서는 i%10+1 과같은계산식을사용하면된다. i i%10 i%10+1 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 8 8 9 9 9 10 10 0 1 11 1 2 12 2 3 13 3 4 14 4 5 15 5 6 16 6 7 17 7 8 18 8 9 19 9 10 그리고 num의값이 1,3,8 일때, 한쌍의카드중에서하나는광(kwang) 이어야하므로아래 와같은조건식이필요하다. AND(&&) 가 OR( ) 보다우선순위가높기때문에괄호를꼭사 용해야한다. boolean iskwang = (i < 10)&&(num==1 num==3 num==8);

Java의정석定石 257 만일 i의값이 2이고 num의값이 3이라면위의조건식은다음과같은계산과정을거쳐서 iskwang에는 true 가저장된다. boolean iskwang = (2 < 10)&&(3==1 3==3 3==8); boolean iskwang = (true)&&(false true false); boolean iskwang = (true)&&(true false); boolean iskwang = (true)&&(true); boolean iskwang = true;

258 Java의정석定石 [7-2] 문제7-1의 SutdaDeck클래스에다음에정의된새로운메서드를추가하고테스트하 시오. [ 주의] Math.random() 을사용하는경우실행결과와다를수있음. 1. 메서드명 : shuffle 기능 : 배열 cards 에담긴카드의위치를뒤섞는다.(Math.random() 사용) 반환타입 : 없음 매개변수 : 없음 2. 메서드명 : pick 기능 : 배열 cards에서지정된위치의 SutdaCard 를반환한다. 반환타입 : SutdaCard 매개변수 : int index - 위치 3. 메서드명 : pick 기능 : 배열 cards에서임의의위치의 SutdaCard 를반환한다.(Math.random() 사용) 반환타입 : SutdaCard 매개변수 : 없음 [ 연습문제]/ch7/Exercise7_2.java class SutdaDeck { final int CARD_NUM = 20; SutdaCard[] cards = new SutdaCard[CARD_NUM]; SutdaDeck() { for(int i=0;i < cards.length;i++) { int num = i%10+1; boolean iskwang = (i < 10)&&(num==1 num==3 num==8); cards[i] = new SutdaCard(num,isKwang); void shuffle() { for(int i=0; i<cards.length;i++) { int j = (int)(math.random()*cards.length); // cards[i] 와 cards[j] 의값을서로바꾼다. SutdaCard tmp = cards[i]; cards[i] = cards[j]; cards[j] = tmp; SutdaCard pick(int index) { if(index < 0 index >= CARD_NUM) // index 의유효성을검사한다. return null; return cards[index];

Java의정석定石 259 SutdaCard pick() { int index = (int)(math.random()*cards.length); return pick(index); // pick(int index) 를호출한다. // SutdaDeck class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public String tostring() { return num + ( iskwang? "K":""); class Exercise7_2 { public static void main(string args[]) { SutdaDeck deck = new SutdaDeck(); System.out.println(deck.pick(0)); System.out.println(deck.pick()); deck.shuffle(); for(int i=0; i < deck.cards.length;i++) System.out.print(deck.cards[i]+","); System.out.println(); System.out.println(deck.pick(0)); 실행결과 [ ] 1K 7 2,6,10,1K,7,3,10,5,7,8,5,1,2,9,6,9,4,8K,4,3K, 2 [ 해설] shuffle메서드에대한것은이미문제6-20에서이미설명했으므로설명을생략하 겠다. pick(int index) 메서드는매개변수 index 에대한유효성검사가필요하다. 그렇지 않으면배열의 index범위를넘어서서 ArrayIndexOutOfBounndsException이발생할수있 다. 매개변수가있는메서드는반드시작업전에유효성검사를해야한다는것을기억하 자.

260 Java의정석定石 SutdaCard pick(int index) { if(index < 0 index >= CARD_NUM) return null; return cards[index]; // index 의유효성을검사한다. SutdaCard pick() { int index = (int)(math.random()*cards.length); return pick(index); // pick(int index) 를호출한다. pick() 메서드의경우, cards배열에있는임의의카드를꺼내야하므로 Math.random() 을이 용해서유효한 index범위내의한값을얻어서다시 pick(int index) 메서드를호출한다. 다소비효율적이지만코드의중복을제거하고재사용성을높이기위해이처럼하는것이 다. 그러나너무객체지향적인측면에얽매여서코드를짤필요는없다고생각한다. 상황 에맞는적절한코드를작성하면그것으로좋지않을까. SutdaCard pick() { int index = (int)(math.random()*cards.length); return cards[index];

Java의정석定石 261 [7-3] 오버라이딩의정의와필요성에대해서설명하시오. [ 정답] 오버라이딩(overriding) 이란, 조상클래스로부터상속받은메서드를자손클래 스에맞게재정의하는것 을말한다. 조상클래스로부터상속받은메서드를자손클래스에서그대로사용할수없는경우가 많기때문에오버라이딩이필요하다.

262 Java의정석定石 [7-4] 다음중오버라이딩의조건으로옳지않은것은? ( 모두고르시오) a. 조상의메서드와이름이같아야한다. b. 매개변수의수와타입이모두같아야한다. c. 접근제어자는조상의메서드보다좁은범위로만변경할수있다. d. 조상의메서드보다더많은수의예외를선언할수있다. [ 정답] c, d [ 해설] 자손클래스에서오버라이딩하는메서드는조상클래스의메서드와 - 이름이같아야한다. - 매개변수가같아야한다. - 리턴타입이같아야한다. [ 참고] JDK1.5 부터 공변반환타입(covariant return type) 이추가되어, 반환타입을자손클래스의타입으로변경 하는것은가능하도록조건이완화되었다. p.457 조상클래스의메서드를자손클래스에서오버라이딩할때 1. 접근제어자를조상클래스의메서드보다좁은범위로변경할수없다. 2. 예외는조상클래스의메서드보다많이선언할수없다. 3. 인스턴스메서드를 static 메서드로또는그반대로변경할수없다.

Java의정석定石 263 [7-5] 다음의코드는컴파일하면에러가발생한다. 그이유를설명하고에러를수정하기 위해서는코드를어떻게바꾸어야하는가? [ 연습문제]/ch7/Exercise7_5.java class Product { int price; // 제품의가격 int bonuspoint; // 제품구매시제공하는보너스점수 Product() { Product(int price) { this.price = price; bonuspoint =(int)(price/10.0); class Tv extends Product { Tv() { public String tostring() { return "Tv"; class Exercise7_5 { public static void main(string[] args) { Tv t = new Tv(); [ 정답] Product클래스에기본생성자 Product() 가없기때문에에러가발생한다. Product 클래스에기본생성자 Product() { 를추가해줘야한다. [ 해설] Tv 클래스의인스턴스를생성할때, 생성자 Tv() 가호출되고 Tv() 는조상생성자 super() 를호출한다. 실제코드에서는 super() 를호출하는곳이없지만컴파일러가자동 적으로추가해준다. 그래서컴파일을하고나면아래의오른쪽코드와같이변경된다. Tv() { Tv() { super(); //Product() 를호출 추가된 super() 는조상클래스인 Product의기본생성자 Product() 를호출하는것인데, Product클래스에는기본생성자 Product() 가정의되어있지않다. 정의되어있지않은생 성자를호출하니까에러가발생하는것이다. Product클래스에는이미 Product(int price) 라는생성자가정의되어있기때문에컴파일러가자동적으로추가해주지도않으므로직 접 Product클래스에 Product(){ 를넣어주면문제가해결된다.

264 Java의정석定石 [7-6] 자손클래스의생성자에서조상클래스의생성자를호출해야하는이유는무엇인 가? [ 정답] 조상에정의된인스턴스변수들이초기화되도록하기위해서. [ 해설] 자손클래스의인스턴스를생성하면조상으로부터상속받은인스턴스변수들도생성 되는데, 이상속받은인스턴스변수들역시적절히초기되어야한다. 상속받은조상의인 스턴스변수들을자손의생성자에서직접초기화하기보다는조상의생성자를호출함으로써 초기화되도록하는것이바람직하다. 각클래스의생성자는해당클래스에선언된인스턴스변수의초기화만을담당하고, 조상 클래스로부터상속받은인스턴스변수의초기화는조상클래스의생성자가처리하도록해야 하는것이다.

Java의정석定石 265 [7-7] 다음코드의실행했을때호출되는생성자의순서와실행결과를적으시오. [ 연습문제]/ch7/Exercise7_7.java class Parent { int x=100; Parent() { this(200); // Parent(int x) 를호출 Parent(int x) { this.x = x; int getx() { return x; class Child extends Parent { int x = 3000; Child() { this(1000); // Child(int x) 를호출 Child(int x) { this.x = x; class Exercise7_7 { public static void main(string[] args) { Child c = new Child(); System.out.println("x="+c.getX()); [ 정답] Child() Child(int x) Parent() Parent(int x) Object() 의 순서로호출된다. 실행결과 [ ] x=200 [ 해설] 컴파일러는생성자의첫줄에다른생성자를호출하지않으면조상의기본생성자 를호출하는코드'super();' 를넣는다. 그래서왼쪽의코드는컴파일후오른쪽과같은 코드로바뀐다. Child클래스의조상은 Parent이므로 super() 는 Parent() 를의미한다. Child(int x) { this.x = x; Child(int x) { super(); // Parent() 를호출 this.x = x;

266 Java의정석定石 마찬가지로 Parent(int x) 역시컴파일러가 Parent의조상인 Object클래스의기본생성자 를호출하는코드'super();' 를넣는다. Parent(int x) { this.x = x; Parent(int x) { super(); // Object() 를호출 this.x = x; Child() Child(int x) Parent() Parent(int x) Object() 의순서로 호출되니까, Child클래스의인스턴스변수 x는 1000 이되고, Parent클래스의인스턴스 변수 x는 200 이된다. getx() 는조상인 Parent 클래스에정의된것이라서, getx() 에 서 x는 Parent클래스의인스턴스변수 x 를의미한다. 그래서 x=200 이출력된다.

Java의정석定石 267 [7-8] 다음중접근제어자를접근범위가넓은것에서좁은것의순으로바르게나열한것은? a. public-protected-(default)-private b. public-(default)-protected-private c. (default)-public-protected-private d. private-protected-(default)-public [ 정답] a [ 해설] 접근제어자가사용될수있는곳 - 클래스, 멤버변수, 메서드, 생성자 private - 같은클래스내에서만접근이가능하다. default - 같은패키지내에서만접근이가능하다. protected - 같은패키지내에서, 그리고다른패키지의자손클래스에서 public 접근이가능하다. - 접근제한이전혀없다. 접근범위가넓은쪽에서좁은쪽의순으로왼쪽부터나열하면다음과같다. public > protected > default > private 제어자 같은클래스 같은패키지 자손클래스 전체 public protected default private

268 Java의정석定石 [7-9] 다음중제어자 final 을붙일수있는대상과붙였을때그의미를적은것이다. 옳지않은것은? ( 모두고르시오) a. 지역변수 - 값을변경할수없다. b. 클래스 - 상속을통해클래스에새로운멤버를추가할수없다. c. 메서드 - 오버로딩을할수없다. 오버라이딩(overriding) 을할수없다. d. 멤버변수 - 값을변경할수없다. [ 정답] c [ 해설] 제어자 final 은 ' 마지막의' 또는 ' 변경될수없는' 의의미를가지고있으며거의 모든대상에사용될수있다. 제어자대상의미 final 클래스 메서드 변경될수없는클래스, 확장될수없는클래스가된다. 그래서 final 로지정된클래스는다른클래스의조상이될수없다. 변경될수없는메서드, final로지정된메서드는오버라이딩을통해재정의될수없다. 멤버변수변수앞에이붙으면값을변경할수없는상수가된다 final,. 지역변수

Java의정석定石 269 [7-10] MyTv2클래스의멤버변수 ispoweron, channel, volume을클래스외부에서접근할 수없도록제어자를붙이고대신이멤버변수들의값을어디서나읽고변경할수있도록 getter와 setter 메서드를추가하라. [ 연습문제]/ch7/Exercise7_10.java class MyTv2 { private boolean ispoweron; private int channel; private int volume; final int MAX_VOLUME = 100; final int MIN_VOLUME = 0; final int MAX_CHANNEL = 100; final int MIN_CHANNEL = 1; public void setvolume(int volume){ if(volume > MAX_VOLUME volume < MIN_VOLUME) return; this.volume = volume; public int getvolume(){ return volume; public void setchannel(int channel){ if(channel > MAX_CHANNEL channel < MIN_CHANNEL) return; this.channel = channel; public int getchannel(){ return channel; class Exercise7_10 { public static void main(string args[]) { MyTv2 t = new MyTv2(); t.setchannel(10); System.out.println("CH:"+t.getChannel()); t.setvolume(20); System.out.println("VOL:"+t.getVolume()); 실행결과 [ ] CH:10 VOL:20 [ 해설] 별로어렵지않은문제라별도의설명이필요없을것이다. 다만매개변수가있는 메서드는반드시작업전에넘겨받은값의유효성검사를해야한다는것을잊지말자.

270 Java의정석定石 [7-11] 문제7-10에서작성한 MyTv2 클래스에이전채널(previous channel) 로이동하는 기능의메서드를추가해서실행결과와같은결과를얻도록하시오. [Hint] 이전채널의값을저장할멤버변수를정의하라. 메서드명 : gotoprevchannel 기능 : 현재채널을이전채널로변경한다. 반환타입 : 없음 매개변수 : 없음 [ 연습문제]/ch7/Exercise7_11.java class MyTv2 { private boolean ispoweron; private int channel; private int volume; private int prevchannel; // 이전채널(previous channel) final int MAX_VOLUME = 100; final int MIN_VOLUME = 0; final int MAX_CHANNEL = 100; final int MIN_CHANNEL = 1; public void setvolume(int volume){ if(volume > MAX_VOLUME volume < MIN_VOLUME) return; this.volume = volume; public int getvolume(){ return volume; public void setchannel(int channel){ if(channel > MAX_CHANNEL channel < MIN_CHANNEL) return; prevchannel = this.channel; // 현재채널을이전채널에저장한다. this.channel = channel; public int getchannel(){ return channel; public void gotoprevchannel() { setchannel(prevchannel); // 현재체널을이전채널로변경한다. class Exercise7_11 { public static void main(string args[]) { MyTv2 t = new MyTv2();

Java의정석定石 271 t.setchannel(10); System.out.println("CH:"+t.getChannel()); t.setchannel(20); System.out.println("CH:"+t.getChannel()); t.gotoprevchannel(); System.out.println("CH:"+t.getChannel()); t.gotoprevchannel(); System.out.println("CH:"+t.getChannel()); 실행결과 [ ] CH:10 CH:20 CH:10 CH:20 [ 해설] 먼저이전채널을저장할변수(prevChannel) 를하나추가해야한다. 그리고채널 이바뀔때마다이변수에바뀌기전의채널을저장해야한다. 문제7-10의코드에아래의 붉은색코드를추가했다. public void setchannel(int channel){ if(channel > MAX_CHANNEL channel < MIN_CHANNEL) return; prevchannel = this.channel; // 현재채널을이전채널에저장한다. this.channel = channel; 이제 gotoprevchannel() 에서는 setchannel() 을호출해주기만하면된다. public void gotoprevchannel() { setchannel(prevchannel); // 현재체널을이전채널로변경한다.

272 Java의정석定石 [7-12] 다음중접근제어자에대한설명으로옳지않은것은? ( 모두고르시오) a. public 은접근제한이전혀없는접근제어자이다. b. (default) 가붙으면, 같은패키지내에서만접근이가능하다. c. 지역변수에도접근제어자를사용할수있다. d. protected 가붙으면, 같은패키지내에서도접근이가능하다. e. protected 가붙으면, 다른패키지의자손클래스에서접근이가능하다. [ 정답] c [ 해설] 접근제어자가사용될수있는곳 - 클래스, 멤버변수, 메서드, 생성자 private - 같은클래스내에서만접근이가능하다. default - 같은패키지내에서만접근이가능하다. protected - 같은패키지내에서, 그리고다른패키지의자손클래스에서 public 접근이가능하다. - 접근제한이전혀없다. 제어자 같은클래스 같은패키지 자손클래스 전체 public protected default private

Java의정석定石 273 [7-13] Math클래스의생성자는접근제어자가 private 이다. 그이유는무엇인가? [ 정답] Math클래스의모든메서드가 static메서드이고인스턴스변수가존재하지않기때 문에객체를생성할필요가없기때문 [ 해설] Math클래스는몇개의상수와 static메서드만으로구성되어있기때문에인스턴스 를생성할필요가없다. 그래서외부로부터의불필요한접근을막기위해다음과같이생 성자의접근제어자를 private 으로지정하였다. public final class Math { private Math() { //...

274 Java의정석定石 [7-14] 문제7-1 에나오는섯다카드의숫자와종류(isKwang) 는사실한번값이지정되면 변경되어서는안되는값이다. 카드의숫자가한번잘못바뀌면똑같은카드가두장이 될수도있기때문이다. 이러한문제점이발생하지않도록아래의 SutdaCard를수정하시 오. [ 연습문제]/ch7/Exercise7_14.java class SutdaCard { final int NUM; final boolean IS_KWANG; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.is_kwang = iskwang; public String tostring() { return NUM + ( IS_KWANG? "K":""); class Exercise7_14 { public static void main(string args[]) { SutdaCard card = new SutdaCard(1, true); [ 해설] 원래변수앞에 final 을붙일때는선언과초기화를동시에해야한다. final int MAX_VOLUME = 100; 그러나인스턴스변수의경우, 선언시에초기화하지않고생성자에서초기화할수있다. 생성할때지정된값이변하지않도록할수있는것이다. 상수이므로한번초기화한이 후로는값을바꿀수없다. final int NUM; final boolean IS_KWANG; SutdaCard(int num, boolean iskwang) { this.num = num; // 생성자에서단한번의초기화만가능 this.is_kwang = iskwang; // 생성자에서단한번의초기화만가능 카드게임에서카드의숫자와무늬가게임도중에변경되는것이가능하다면, 실수로같은카드가두장이되는일이일어날수있기때문에이를방지하기위해서숫자와무늬는한번지정되면변경할수없도록하는것이바람직하다.

Java의정석定石 275 [7-15] 클래스가다음과같이정의되어있을때, 형변환을올바르게하지않은것은? ( 모두고르시오.) class Unit { class AirUnit extends Unit { class GroundUnit extends Unit { class Tank extends GroundUnit { class AirCraft extends AirUnit { Unit u = new GroundUnit(); Tank t = new Tank(); AirCraft ac = new AirCraft(); a. u = (Unit)ac; b. u = ac; c. GroundUnit gu = (GroundUnit)u; d. AirUnit au = ac; e. t = (Tank)u; 조상타입의인스턴스를자손타입으로형변환할수없다. f. GroundUnit gu = t; [ 정답] e [ 해설] 클래스간의상속관계를그림으로그려보면쉽게알수있다. Unit AirUnit GroundUnit AirCraft Tank Unit 클래스는나머지네개클래스의조상이므로형변환이가능하며, 도있다. 심지어는생략할수 AirCraft ac = new AirCraft(); u = (Unit)ac; // u는 AirCraft의조상인 Unit 타입이므로형변환이가능하다. u = ac; // 업캐스팅( 자손 조상) 이므로형변환을생략할수있다. 조상타입의참조변수로자손타입의인스턴스를참조하는것이가능하기때문에아래의코 드는모두가능하다. Unit u = new GroundUnit(); GroundUnit gu = (GroundUnit)u; // u가참조하는객체가 GroundUnit이므로 OK GroundUnit gu = (GroundUnit)new GroundUnit(); // 위의두줄을한줄로합침 AirCraft ac = new AirCraft(); AirUnit au = ac; // AirCraft가 AirUnit 의자손이므로가능. 형변환생략됨 AirUnit au = new AirCraft(); // 위의두줄을한줄로합치면이렇게쓸수있음 Tank t = new Tank(); GroundUnit gu = t; // 조상타입의참조변수로자손타입의인스턴스를참조. OK GroundUnit gu = new Tank(); // 위의두줄을한줄로합치면이렇게쓸수있음

276 Java의정석定石 그러나조상인스턴스를자손타입으로형변환하는것은허용하지않는다. 참조변수 u는실 제로 GroundUnit 인스턴스를참조하고있다. (Tank)u는 GroundUnit인스턴스를자손타입인 Tank 로형변환하는것인데, 자손타입으로형변환은허용되지않으므로실행시에러가발 생한다. [ 참고] 컴파일시에는타입만을체크하기때문에에러가발생하지않을수도있지만, 실행시에에러가발생한다. Unit u = new GroundUnit(); Tank t = new Tank(); t = (Tank)u; // 조상인스턴스(GroundUnit) 를자손(Tank) 으로형변환할수없다. Tank t = (Tank)new GroundUnit; // 허용되지않음

Java의정석定石 277 [7-16] 다음중연산결과가 true 가아닌것은? ( 모두고르시오) class Car { class FireEngine extends Car implements Movable { class Ambulance extends Car { FireEngine fe = new FireEngine(); a. fe instanceof FireEngine b. fe instanceof Movable c. fe instanceof Object d. fe instanceof Car e. fe instanceof Ambulance [ 정답] e [ 해설] instanceof연산자는실제인스턴스의모든조상이나구현한인터페이스에대해 true 를반환한다. 그래서, 아래그림에서알수있듯이 FireEngine인스턴스는 Object, Car, Movable, FireEngine타입에대해 instanceof연산을하면결과로 true 를얻는다. 어 떤타입에대해 instanceof연산결과가 true라는것은그타입으로형변환이가능하다는 것을뜻한다. 참조변수의형변환을하기에앞서 instanceof연산자로형변환이가능한지 미리확인해보는것이좋다. Object Car Movable Ambulance FireEngine

278 Java의정석定石 [7-17] 아래세개의클래스로부터공통부분을뽑아서 Unit 이라는클래스를만들고, 이 클래스를상속받도록코드를변경하시오. class Marine { // 보병 int x, y; // 현재위치 void move(int x, int y) { /* 지정된위치로이동 */ void stop() { /* 현재위치에정지 */ void stimpack() { /* 스팀팩을사용한다.*/ class Tank { // 탱크 int x, y; // 현재위치 void move(int x, int y) { /* 지정된위치로이동 */ void stop() { /* 현재위치에정지 */ void changemode() { /* 공격모드를변환한다. */ class Dropship { // 수송선 int x, y; // 현재위치 void move(int x, int y) { /* 지정된위치로이동 */ void stop() { /* 현재위치에정지 */ void load() { /* 선택된대상을태운다.*/ void unload() { /* 선택된대상을내린다.*/ [ 정답] 각클래스의공통부분을뽑아서 Unit 클래스를생성하면된다. 클래스마다이동하 는방법이다르므로 move 메서드는추상메서드로정의하였다. 책에도같은내용이있기때 문에자세한설명은생략하겠다. abstract class Unit { int x, y; abstract void move(int x, int y); // 추상클래스 void stop() { /* 현재위치에정지 */ class Marine extends Unit { // 보병 void move(int x, int y) { /* 지정된위치로이동 */ void stimpack() { /* 스팀팩을사용한다.*/ class Tank extends Unit { void move(int x, int y) void changemode() class Dropship extends Unit void move(int x, int y) void load() void unload() // 탱크 { /* 지정된위치로이동 */ { /* 공격모드를변환한다. */ { // 수송선 { /* 지정된위치로이동 */ { /* 선택된대상을태운다.*/ { /* 선택된대상을내린다.*/

Java의정석定石 279 [7-18] 다음과같은실행결과를얻도록코드를완성하시오. [Hint] instanceof 연산자를사용해서형변환한다. 메서드명 : action 기능 : 주어진객체의메서드를호출한다. 반환타입 : 없음 DanceRobot 인경우, dance() 를호출하고, SingRobot 인경우, sing() 을호출하고, DrawRobot 인경우, draw() 를호출한다. 매개변수 : Robot r - Robot인스턴스또는 Robot의자손인스턴스 [ 연습문제]/ch7/Exercise7_18.java class Exercise7_18 { public static void action(robot r) { if(r instanceof DanceRobot) { DanceRobot dr = (DanceRobot)r; dr.dance(); else if(r instanceof SingRobot) { SingRobot sr = (SingRobot)r; sr.sing(); else if(r instanceof DrawRobot) { DrawRobot dr = (DrawRobot)r; dr.draw(); public static void main(string[] args) { Robot[] arr = { new DanceRobot(), new SingRobot(), new DrawRobot(); for(int i=0; i< arr.length;i++) action(arr[i]); // main class Robot { class DanceRobot extends Robot { void dance() { System.out.println(" 춤을춥니다."); class SingRobot extends Robot { void sing() { System.out.println(" 노래를합니다."); class DrawRobot extends Robot { void draw() { System.out.println(" 그림을그립니다.");

280 Java의정석定石 실행결과 [ ] 춤을춥니다. 노래를합니다. 그림을그립니다. [ 해설] action메서드의매개변수가 Robot타입이므로 Robot클래스의자손클래스인 DanceRobot, SingRobot, DrawRobot 의인스턴스는모두매개변수로가능하다. Robot[] arr = { new DanceRobot(), new SingRobot(), new DrawRobot(); for(int i=0; i< arr.length;i++) action(arr[i]); action 메서드내에서는실제로받아온인스턴스가어떤것인지알수없다. 단지 Robot클 래스또는그자손클래스의인스턴스일것이라는것만알수있다. 그래서 instanceof연 산자를이용해야만실제인스턴스의타입을확인할수있다. public static void action(robot r) { if(r instanceof DanceRobot) { DanceRobot dr = (DanceRobot)r; dr.dance(); else if(r instanceof SingRobot) { SingRobot sr = (SingRobot)r; sr.sing(); else if(r instanceof DrawRobot) { DrawRobot dr = (DrawRobot)r; dr.draw();

Java의정석定石 281 [7-19] 다음은물건을구입하는사람을정의한 Buyer 클래스이다. 이클래스는멤버변수 로돈(money) 과장바구니(cart) 를가지고있다. 제품을구입하는기능의 buy메서드와장 바구니에구입한물건을추가하는 add 메서드, 구입한물건의목록과사용금액, 그리고남 은금액을출력하는 summary 메서드를완성하시오. 1. 메서드명 : buy 기능 : 지정된물건을구입한다. 가진돈(money) 에서물건의가격을빼고, 반환타입 : 없음 장바구니(cart) 에담는다. 만일가진돈이물건의가격보다적다면바로종료한다. 매개변수 : Product p - 구입할물건 2. 메서드명 : add 기능 : 지정된물건을장바구니에담는다. 반환타입 : 없음 만일장바구니에담을공간이없으면, 장바구니의크기를 2 배로늘린다음에담는다. 매개변수 : Product p - 구입할물건 3. 메서드명 : summary 기능 : 구입한물건의목록과사용금액, 남은금액을출력한다. 반환타입 : 없음 매개변수 : 없음 [ 연습문제]/ch7/Exercise7_19.java class Exercise7_19 { public static void main(string args[]) { Buyer b = new Buyer(); b.buy(new Tv()); b.buy(new Computer()); b.buy(new Tv()); b.buy(new Audio()); b.buy(new Computer()); b.buy(new Computer()); b.buy(new Computer()); b.summary(); class Buyer { int money = 1000; Product[] cart = new Product[3]; // 구입한제품을저장하기위한배열 int i = 0; // Product배열 cart에사용될 index void buy(product p) { // 1.1 가진돈과물건의가격을비교해서가진돈이적으면메서드를종료한다. if(money < p.price) { System.out.println(" 잔액이부족하여 "+ p +" 을/ 를살수없습니다."); return;

282 Java의정석定石 // 1.2 가진돈이충분하면, 제품의가격을가진돈에서빼고 money -= p.price; // 1.3 장바구니에구입한물건을담는다.(add 메서드호출) add(p); void add(product p) { // 1.1 i의값이장바구니의크기보다같거나크면 if(i >= cart.length) { // 1.1.1 기존의장바구니보다 2 배큰새로운배열을생성한다. Product[] tmp = new Product[cart.length*2]; // 1.1.2 기존의장바구니의내용을새로운배열에복사한다. System.arraycopy(cart,0,tmp,0,cart.length); // 1.1.3 새로운장바구니와기존의장바구니를바꾼다. cart = tmp; // 1.2 물건을장바구니(cart) 에저장한다. 그리고 i의값을 1 증가시킨다. cart[i++]=p; // add(product p) void summary() { String itemlist = ""; int sum = 0; for(int i=0; i < cart.length;i++) { if(cart[i]==null) break; // 1.1 장바구니에담긴물건들의목록을만들어출력한다. itemlist += cart[i] + ","; // 1.2 장바구니에담긴물건들의가격을모두더해서출력한다. sum += cart[i].price; // 1.3 물건을사고남은금액(money) 를출력한다. System.out.println(" 구입한물건:"+itemList); System.out.println(" 사용한금액:"+sum); System.out.println(" 남은금액:"+money); // summary() class Product { int price; // 제품의가격 Product(int price) { this.price = price; class Tv extends Product { Tv() { super(100); public String tostring() { return "Tv"; class Computer extends Product { Computer() { super(200);

Java의정석定石 283 public String tostring() { return "Computer"; class Audio extends Product { Audio() { super(50); public String tostring() { return "Audio"; [ 실행결과] 잔액이부족하여 Computer 을/ 를살수없습니다. 구입한물건 :Tv,Computer,Tv,Audio,Computer,Computer, 사용한금액 :850 남은금액 :150 [ 해설] 자신이스스로로직을작성할수있으면가장좋겠지만, 적어도주어진로직대로 코드를구현할수있는능력은갖추어야한다. 그런능력을향상시키기위한문제이다. 이문제가쉽게느껴지는사람은로직( 주석) 을안보고코드를다시작성해보기바란다. 책에있는내용을복습하는문제이기때문에자세한설명은생략하겠다. 책을참고하길 바란다.

284 Java의정석定石 [7-20] 다음의코드를실행한결과를적으시오. [ 연습문제]/ch7/Exercise7_20.java class Exercise7_20 { public static void main(string[] args) { Parent p = new Child(); Child c = new Child(); System.out.println("p.x = " + p.x); p.method(); System.out.println("c.x = " + c.x); c.method(); class Parent { int x = 100; void method() { System.out.println("Parent Method"); class Child extends Parent { int x = 200; void method() { System.out.println("Child Method"); [ 정답] 실행결과 [ ] p.x = 100 Child Method c.x = 200 Child Method [ 해설] 조상클래스에선언된멤버변수와같은이름의인스턴스변수를자손클래스에중 복으로정의했을때, 조상타입의참조변수로자손인스턴스를참조하는경우와자손타입 의참조변수로자손인스턴스를참조하는경우는서로다른결과를얻는다. 메서드의경우조상클래스의메서드를자손의클래스에서오버라이딩한경우에도참조변 수의타입에관계없이항상실제인스턴스의메서드( 오버라이딩된메서드) 가호출되지만, 멤버변수의경우참조변수의타입에따라달라진다. 타입은다르지만, 참조변수 p, c모두 Child 인스턴스를참조하고있다. Parent p = new Child(); Child c = new Child();

Java의정석定石 285 그리고, Parent클래스와 Child 클래스는서로같은멤버들을정의하고있다. class Parent { int x = 100;... class Child extends Parent { int x = 200;... 이때조상타입의참조변수 p로 Child인스턴스의멤버들을사용하는것과자손타입의참 조변수 c로 Child 인스턴스의멤버들을사용하는것의차이를알수있다. 메서드인 method() 의경우참조변수의타입에관계없이항상실제인스턴스의타입인 Child 클래스에정의된메서드가호출되지만, 인스턴스변수인 x는참조변수의타입에따라 서달라진다.

286 Java의정석定石 [7-21] 다음과같이 attack 메서드가정의되어있을때, 이메서드의매개변수로가능한 것두가지를적으시오. interface Movable { void move(int x, int y); void attack(movable f) { /* 내용생략 */ [ 정답] null, Movable인터페이스를구현한클래스또는그자손의인스턴스 [ 해설] 매개변수의다형성을잘이해하고있는지를확인하는문제이다. 매개변수의타입 이인터페이스라는것은어떤의미일지이해하지못하는경우가많은데, 이것을이해하는 것은매우중요하다. 언제라도누가 Movable 인터페이스타입의매개변수로가능한것이무엇이냐? 고물었 을때, 주저없이얘기할수있도록완전히외우고있어야한다.

Java의정석定石 287 [7-22] 아래는도형을정의한 Shape 클래스이다. 이클래스를조상으로하는 Circle클래 스와 Rectangle 클래스를작성하시오. 이때, 생성자도각클래스에맞게적절히추가해야 한다. (1) 클래스명 : Circle 조상클래스 : Shape 멤버변수 : double r - 반지름 (2) 클래스명 : Rectangle 조상클래스 : Shape 멤버변수 메서드 : : double width - 폭 double height - 높이 1. 메서드명 : issquare 기능 : 정사각형인지아닌지를알려준다. 반환타입 : boolean 매개변수 : 없음 [ 연습문제]/ch7/Exercise7_22.java abstract class Shape { Point p; Shape() { this(new Point(0,0)); Shape(Point p) { this.p = p; abstract double calcarea(); // 도형의면적을계산해서반환하는메서드 Point getposition() { return p; void setposition(point p) { this.p = p; class Rect extends Shape { double width; double height; Rect(double width, double height) { this(new Point(0,0), width, height); Rect(Point p, double width, double height) { super(p); // 조상의멤버는조상의생성자가초기화하도록한다. this.width = width;

288 Java의정석定石 this.height = height; boolean issquare() { // width나 height가 0이아니고 width와 height가같으면 true 를반환한다. return width*height!=0 && width==height; double calcarea() { return width * height; class Circle extends Shape { double r; // 반지름 Circle(double r) { this(new Point(0,0),r); // Circle(Point p, double r) 를호출 Circle(Point p, double r) { super(p); // 조상의멤버는조상의생성자가초기화하도록한다. this.r = r; double calcarea() { return Math.PI * r * r; class Point { int x; int y; Point() { this(0,0); Point(int x, int y) { this.x=x; this.y=y; public String tostring() { return "["+x+","+y+"]";

Java의정석定石 289 [7-23] 문제7-22에서정의한클래스들의면적을구하는메서드를작성하고테스트하시 오. 1. 메서드명 : sumarea 기능 : 주어진배열에담긴도형들의넓이를모두더해서반환한다. 반환타입 : double 매개변수 : Shape[] arr [ 연습문제]/ch7/Exercise7_23.java class Exercise7_23 { static double sumarea(shape[] arr) { double sum = 0; for(int i=0; i < arr.length;i++) sum+= arr[i].calcarea(); return sum; public static void main(string[] args) { Shape[] arr = {new Circle(5.0), new Rectangle(3,4), new Circle(1); System.out.println(" 면적의합:"+sumArea(arr)); 실행결과 [ ] 면적의합 :93.68140899333463 [ 해설] 반복문으로넘겨받은객체배열(arr) 의객체들에대해 calcarea() 를호출하여면적 을구하고누적해서반환하도록작성하면된다. Shape타입의배열에는 Shape 의자손인스턴스가들어있기때문에, Shape클래스의추상메 서드 calcarea() 를호출해도실제로는각인스턴스에완전히구현된 calcarea() 가호출된 다.

290 Java의정석定石 [7-24] 다음중인터페이스의장점이아닌것은? a. 표준화를가능하게해준다. b. 서로관계없는클래스들에게관계를맺어줄수있다. c. 독립적인프로그래밍이가능하다. d. 다중상속을가능하게해준다. e. 패키지간의연결을도와준다. [ 정답] e [ 해설] 인터페이스를사용하는이유와그장점을정리해보면다음과같다. 1. 개발시간을단축시킬수있다. 일단인터페이스가작성되면, 이를사용해서프로그램을작성하는것이가능하다. 메서드를호출하 는쪽에서는메서드의내용에관계없이선언부만알면되기때문이다. 그리고동시에다른한쪽에서는인터페이스를구현하는클래스를작성하도록하여, 인터페이스를 구현하는클래스가작성될때까지기다리지않고도양쪽에서동시에개발을진행할수있다. 2. 표준화가가능하다. 프로젝트에사용되는기본틀을인터페이스로작성한다음, 개발자들에게인터페이스를구현하여프 로그램을작성하도록함으로써보다일관되고정형화된프로그램의개발이가능하다. 3. 서로관계없는클래스들에게관계를맺어줄수있다. 서로상속관계에있지도않고, 같은조상클래스를가지고있지않은서로아무런관계도없는클래 스들에게하나의인터페이스를공통적으로구현하도록함으로써관계를맺어줄수있다. 4. 독립적인프로그래밍이가능하다. 인터페이스를이용하면클래스의선언과구현을분리시킬수있기때문에실제구현에독립적인프로 그램을작성하는것이가능하다. 클래스와클래스간의직접적인관계를인터페이스를이용해서간접 적인관계로변경하면, 한클래스의변경이관련된다른클래스에영향을미치지않는독립적인프 로그래밍이가능하다.

Java의정석定石 291 [7-25] Outer클래스의내부클래스 Inner의멤버변수 iv 의값을출력하시오. [ 연습문제]/ch10/Exercise7_25.java class Outer { // 외부클래스 class Inner { // 내부클래스( 인스턴스클래스) int iv=100; class Exercise7_25 { public static void main(string[] args) { Outer o = new Outer(); Outer.Inner ii = o.new Inner(); System.out.println(ii.iv); 실행결과 [ ] 100 [ 해설] 내부클래스( 인스턴스클래스) 의인스턴스를생성하기위해서는먼저외부클래스 의인스턴스를생성해야한다. 왜냐하면 ' 인스턴스클래스' 는외부클래스의 ' 인스턴스변 수' 처럼외부클래스의인스턴스가생성되어야쓸수있기때문이다.

292 Java의정석定石 [7-26] Outer클래스의내부클래스 Inner의멤버변수 iv 의값을출력하시오. [ 연습문제]/ch10/Exercise7_26.java class Outer { // 외부클래스 static class Inner { // 내부클래스(static 클래스) int iv=200; class Exercise7_26 { public static void main(string[] args) { Outer.Inner ii = new Outer.Inner(); System.out.println(ii.iv); 실행결과 [ ] 200 [ 해설] 스태틱클래스(static inner class) 는 인스턴스클래스와달리외부클래스의인 스턴스를생성하지않고도사용할수있다. 마치 static멤버를인스턴스생성없이사용할 수있는것처럼.

Java의정석定石 293 [7-27] 다음과같은실행결과를얻도록 (1)~(4) 의코드를완성하시오. [ 연습문제]/ch10/Exercise7_27.java class Outer { int value=10; // Outer.this.value class Inner { // 인스턴스클래스(instance inner class) int value=20; // this.value void method1() { int value=30; // value System.out.println( value); System.out.println( this.value); System.out.println(Outer.this.value); // Inner클래스의끝 // Outer클래스의끝 class Exercise7_27 { public static void main(string args[]) { Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); inner.method1(); 실행결과 [ ] 30 20 10 [ 해설] 외부클래스와내부클래스에같은이름의인스턴스변수(value) 가선언되었을때 어떻게구별하는가에대한문제이다. 외부클래스의인스턴스변수는내부클래스에서 외부클래스이름.this. 변수이름 로접근할수있다. 내부클래스의종류가인스턴스클래스이기때문에외부클래스의인스턴스를생성한다 음에야내부클래스의인스턴스를생성할수있다.

294 Java의정석定石 [7-28] 아래의 EventHandler 를익명클래스(anonymous class) 로변경하시오. [ 연습문제]/ch7/Exercise7_28.java import java.awt.*; import java.awt.event.*; class Exercise7_28 { public static void main(string[] args) { Frame f = new Frame(); f.addwindowlistener(new EventHandler()); class EventHandler extends WindowAdapter { public void windowclosing(windowevent e) { e.getwindow().setvisible(false); e.getwindow().dispose(); System.exit(0); [ 정답] [ 연습문제]/ch10/Exercise7_28_2.java import java.awt.*; import java.awt.event.*; class Exercise7_28_2 { public static void main(string[] args) { Frame f = new Frame(); f.addwindowlistener(new WindowAdapter() { public void windowclosing(windowevent e) { e.getwindow().setvisible(false); e.getwindow().dispose(); System.exit(0); ); // main

Java의정석定石 295 [7-29] 지역클래스에서외부클래스의인스턴스멤버와 static멤버에모두접근할수있 지만, 지역변수는 final 이붙은상수만접근할수있는이유무엇인가? [ 정답] 메서드가수행을마쳐서지역변수가소멸된시점에도, 지역클래스의인스턴스가 소멸된지역변수를참조하려는경우가발생할수있기때문이다. [ 해설] 아직쓰레드를배우지않았지만, 쓰레드를사용해서상황을만들어보았다. [ 연습문제]/ch10/Exercise7_29.java import java.awt.*; import java.awt.event.*; class Exercise7_29 { public static void main(string[] args) { final int VALUE = 10; // 외부클래스의지역변수 Thread t = new Thread( new Runnable() { // 익명클래스( 내부클래스) public void run() { for(int i=0; i < 10;i++) { // 10 번반복한다. try { Thread.sleep(1*1000); // 1 초간멈춘다. catch(interruptedexception e) { System.out.println(VALUE); // 외부클래스의지역변수를사용 // run() ); t.start(); // 쓰레드를시작한다. System.out.println("main() - 종료."); // main [ 실행결과] main() - 종료. 10 10 10 10 10 10 10 10 10 10 실행결과를보면 main메서드가종료된후에도지역변수 VALUE의값을사용하고있다는것 을알수있다. 지역변수는메서드가종료되면함께사라지지만, 상수의경우이미컨스 턴트풀(constant pool, 상수를따로모아서저장해놓는곳) 에저장되어있기때문에사 용할수있는것이다.

296 Java의정석定石 [ 연습문제 - 모범답안 ] [8-1] 예외처리의정의와목적에대해서설명하시오. [ 정답] 정의 - 프로그램실행시발생할수있는예외의발생에대비한코드를작성하는것 목적 - 프로그램의비정상종료를막고, 정상적인실행상태를유지하는것 [ 해설] 프로그램의실행도중에발생하는에러는어쩔수없지만, 예외는프로그래머가이 에대한처리를미리해주어야한다. 에러(error) - 프로그램코드에의해서수습될수없는심각한오류예외(exception) - 프로그램코드에의해서수습될수있는다소미약한오류 예외처리(exception handling) 란, 프로그램실행시발생할수있는예기치못한예외의 발생에대비한코드를작성하는것이며, 예외처리의목적은예외의발생으로인한실행 중인프로그램의갑작스런비정상종료를막고, 정상적인실행상태를유지할수있도록 하는것이다. 예외처리(exception handling) 의 정의 - 프로그램실행시발생할수있는예외의발생에대비한코드를작성하는것 목적 - 프로그램의비정상종료를막고, 정상적인실행상태를유지하는것

Java의정석定石 297 [8-2] 다음은실행도중예외가발생하여화면에출력된내용이다. 이에대한설명중옳 지않은것은? java.lang.arithmeticexception : / by zero at ExceptionEx18.method2(ExceptionEx18.java:12) at ExceptionEx18.method1(ExceptionEx18.java:8) at ExceptionEx18.main(ExceptionEx18.java:4) a. 위의내용으로예외가발생했을당시호출스택에존재했던메서드를알수있다. b. 예외가발생한위치는 method2 메서드이며, ExceptionEx18.java파일의 12 번째줄이다. c. 발생한예외는 ArithmeticException 이며, 0 으로나누어서예외가발생했다. d. method2메서드가 method1메서드를호출하였고그위치는 ExceptionEx18.java파일의 8 번째줄이다. [ 정답] d [ 해설] 예외의종류는 ArithmeticException이고 0 으로나눠서발생하였다. 예외가발생한 곳은 method2이고 ExceptionEx18.java의 12 번째줄이다. 예외가발생했을당시의호출스 택을보면아래의그림과같다. 호출스택은맨위에있는메서드가현재실행중인메서 드이고아래있는메서드가바로위의메서드를호출한것이다. 그래서 main method1 method2 의순서로호출되었음을알수있다. method2 method1 main 괄호안의내용은예외가발생한소스와라인인데, method1() 의경우예외가발생한곳이 method2() 호출한라인이고 main의경우 method1() 을호출한라인이다. method1() 에서봤을때는 method2() 를호출한곳에서예외가발생한것이기때문이다. main 메서드역시마찬가지.

298 Java의정석定石 [8-3] 다음중오버라이딩이잘못된것은? ( 모두고르시오) void add(int a, int b) throws InvalidNumberException, NotANumberException { class NumberException extends Exception { class InvalidNumberException extends NumberException { class NotANumberException extends NumberException { a. void add(int a, int b) throws InvalidNumberException, NotANumberException { b. void add(int a, int b) throws InvalidNumberException { c. void add(int a, int b) throws NotANumberException { d. void add(int a, int b) throws Exception { e. void add(int a, int b) throws NumberException { [ 정답] d, e [ 해설] 오버라이딩(overriding) 을할때, 조상클래스의메서드보다많은수의예외를선 언할수없다. - 아래의코드를보면 Child클래스의 parentmethod() 에선언된예외의개수가조상인 Parent클래 스의 parentmethod() 에선언된예외의개수보다적으므로바르게오버라이딩되었다. Class Parent { void parentmethod() throws IOException, SQLException { //.. Class Child extends Parent { void parentmethod() throws IOException { //.. //.. 여기서주의해야할점은단순히선언된예외의개수의문제가아니라는것이다. Class Child extends Parent { void parentmethod() throws Exception { //.. //.. 만일위와같이오버라이딩을하였다면, 분명히조상클래스에정의된메서드보다적은개 수의예외를선언한것처럼보이지만 Exception은모든예외의최고조상이므로가장많

Java의정석定石 299 은개수의예외를던질수있도록선언한것이다. 그래서예외의개수는적거나같아야한다는조건을만족시키지못하는잘못된오버라이 딩인것이다. 아래의코드로이문제를직접테스트할수있다. class NumberException extends Exception { class InvalidNumberException extends NumberException { class NotANumberException extends NumberException { class Parent { int a; int b; Parent() { this(0,0); Parent(int a, int b) { this.a = a; this.b = b; void add(int a, int b) throws InvalidNumberException, NotANumberException { class Child extends Parent { Child() { Child(int a, int b) { super(a,b); void add(int a, int b) throws InvalidNumberException, NotANumberException {

300 Java의정석定石 [8-4] 다음과같은메서드가있을때, 예외를잘못처리한것은? ( 모두고르시오) void method() throws InvalidNumberException, NotANumberException { class NumberException extends RuntimeException { class InvalidNumberException extends NumberException { class NotANumberException extends NumberException { a. try {method(); catch(exception e) { b. try {method(); catch(numberexception e) { catch(exception e) { c. try {method(); catch(exception e) { catch(numberexception e) { d. try {method(); catch(invalidnumberexception e) { catch(notanumberexception e) { e. try {method(); catch(numberexception e) { f. try {method(); catch(runtimeexception e) { [ 정답] c [ 해설] try 블럭내에서예외가발생하면, catch블럭중에서예외를처리할수있는것을 을차례대로찾아내려간다. 발생한예외의종류와일치하는 catch블럭이있으면그블럭 의문장들을수행하고 try-catch 문을빠져나간다. 일치하는 catch블럭이없으면예외는 처리되지않는다. 발생한예외의종류와일치하는 catch 블럭을찾을때, instanceof로검사를하기때문에 모든예외의최고조상인 Exception이선언된 catch블럭은모든예외를다처리할수있 다. 한가지주의할점은 Exception을처리하는 catch블럭은모든 catch블럭중제일마 지막에있어야한다는것이다. try { method(); catch(exception e) { // 컴파일에러발생!!! catch(numberexception e) { 위의코드에서는 Exception을선언한 catch블럭이마지막 catch블럭이아니기때문에컴 파일에러가발생한다.

Java의정석定石 301 [8-5] 아래의코드가수행되었을때의실행결과를적으시오. [ 연습문제]/ch8/Exercise8_5.java class Exercise8_5 { static void method(boolean b) { try { System.out.println(1); if(b) throw new ArithmeticException(); System.out.println(2); // 예외가발생하면실행되지않는문장 catch(runtimeexception r) { System.out.println(3); return; // 메서드를빠져나간다.(finally 블럭을수행한후에) catch(exception e) { System.out.println(4); return; finally { System.out.println(5); // 예외발생여부에관계없이항상실행되는문장 System.out.println(6); public static void main(string[] args) { method(true); method(false); // main [ 정답] 실행결과 [ ] 1 3 5 1 2 5 6 [ 해설] 예외가발생하면 1,3,5 가출력되고예외가발생하지않으면, 1,2,5,6 이출력된다. ArithmeticException은 RuntimeException의자손이므로 RuntimeException이정의된 catch 블럭에서처리된다. 이 catch블럭에 return문이있으므로메서드를종료하고빠져나 가게되는데, 이때도 finally 블럭이수행된다.

302 Java의정석定石 [8-6] 아래의코드가수행되었을때의실행결과를적으시오. [ 연습문제]/ch8/Exercise8_6.java class Exercise8_6 { public static void main(string[] args) { try { method1(); catch(exception e) { System.out.println(5); static void method1() { try { method2(); System.out.println(1); catch(arithmeticexception e) { System.out.println(2); finally { System.out.println(3); System.out.println(4); // method1() static void method2() { throw new NullPointerException(); [ 정답] 실행결과 [ ] 3 5 [ 해설] main메서드가 method1() 을호출하고, method1() 은 method2() 를호출한다. method2() 에서 NullPointerException 이발생했는데, 이예외를처리해줄 try-catch블럭 이없으므로 method2() 는종료되고, 이를호출한 method1() 으로되돌아갔는데여기에는 try-catch블럭이있긴하지만 NullPointerException을처리해줄 catch블럭이없으므로 method1() 도종료되고, 이를호출한 main 메서드로돌아간다. 이때 finally블럭이수행되 어 '3' 이출력된다. main메서드에서는모든예외를처리할수있는 Exception이선언된 catch블럭이있으므 로예외가처리되고 '5' 가출력된다.

Java의정석定石 303 [8-7] 아래의코드가수행되었을때의실행결과를적으시오. [ 연습문제]/ch8/Exercise8_7.java class Exercise8_7 { static void method(boolean b) { try { System.out.println(1); if(b) System.exit(0); System.out.println(2); catch(runtimeexception r) { System.out.println(3); return; catch(exception e) { System.out.println(4); return; finally { System.out.println(5); System.out.println(6); public static void main(string[] args) { method(true); method(false); // main [ 정답] 실행결과 [ ] 1 [ 해설] 변수 b의값이 true이므로 System.exit(0); 이수행되어프로그램이즉시종료된 다. 이럴때는 finally 블럭이수행되지않는다.

304 Java의정석定石 [8-8] 다음은 1~100사이의숫자를맞추는게임을실행하던도중에숫자가아닌영문자를 넣어서발생한예외이다. 예외처리를해서숫자가아닌값을입력했을때는다시입력을 받도록보완하라. 1과 100 사이의값을입력하세요 :50 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :asdf Exception in thread "main" java.util.inputmismatchexception at java.util.scanner.throwfor(scanner.java:819) at java.util.scanner.next(scanner.java:1431) at java.util.scanner.nextint(scanner.java:2040) at java.util.scanner.nextint(scanner.java:2000) at Exercise8_8.main(Exercise8_8.java:16) [ 연습문제]/ch8/Exercise8_8.java import java.util.*; class Exercise8_8 { public static void main(string[] args) { // 1~100사이의임의의값을얻어서 answer 에저장한다. int answer = (int)(math.random() * 100) + 1; int input = 0; // 사용자입력을저장할공간 int count = 0; // 시도횟수를세기위한변수 do { count++; System.out.print("1과 100 사이의값을입력하세요 :"); // input = new Scanner(System.in).nextInt(); try { input = new Scanner(System.in).nextInt(); catch(exception e) { System.out.println(" 유효하지않은값입니다. " +" 다시값을입력해주세요."); continue; if(answer > input) { System.out.println(" 더큰수를입력하세요."); else if(answer < input) { System.out.println(" 더작은수를입력하세요."); else { System.out.println(" 맞췄습니다."); System.out.println(" 시도횟수는 "+count+" 번입니다."); break; // do-while문을벗어난다 while(true); // 무한반복문 // end of main // end of class HighLow

Java의정석定石 305 [ 실행결과] 1과 100 사이의값을입력하세요 :50 더작은수를입력하세요. 1과 100 사이의값을입력하세요 :asdf 유효하지않은값입니다. 다시값을입력해주세요. 1과 100 사이의값을입력하세요 :25 더큰수를입력하세요. 1과 100 사이의값을입력하세요 :38 더큰수를입력하세요. 1과 100 사이의값을입력하세요 :44 맞췄습니다. 시도횟수는 5 번입니다. [ 해설] 사용자로부터값을입력받는경우에는유효성검사를철저하게해야한다. 사용자 가어떤값을입력할지모르기때문이다. 여기서는간단하게화면으로부터값을입력받는부분에 try-catch구문으로예외처리를 해주기만하면된다. 값을입력받을때예외가발생하면, 값을다시입력하라는메세지를 보여주고다시입력받으면된다. input = new Scanner(System.in).nextInt(); try { input = new Scanner(System.in).nextInt(); catch(exception e) { System.out.println(" 유효하지않은값입니다. 다시값을입력해주세요."); continue;

306 Java의정석定石 [8-9] 다음과같은조건의예외클래스를작성하고테스트하시오. [ 참고] 생성자는실행결과를보고알맞게작성해야한다. * 클래스명 : UnsupportedFuctionException * 조상클래스명 : RuntimeException * 멤버변수 : 이 름 : ERR_CODE 저장값 : 에러코드 타 입 : int 기본값 : 100 제어자 : final private * 메서드 : 1. 메서드명 : geterrorcode 기능 : 에러코드(ERR_CODE) 를반환한다. 반환타입 : int 매개변수 : 없음 제어자 : public 2. 메서드명 : getmessage 기능 : 메세지의내용을반환한다.(Exception클래스의 getmessage() 를오버라이딩) 반환타입 : String 매개변수 : 없음 제어자 : public [ 연습문제]/ch8/Exercise8_9.java class UnsupportedFuctionException extends RuntimeException { private final int ERR_CODE; UnsupportedFuctionException(String msg, int errcode) { // super(msg); ERR_CODE = errcode; 생성자 UnsupportedFuctionException(String msg) { // 생성자 this(msg, 100); // ERR_CODE를 100( 기본값) 으로초기화한다. public int geterrcode() { // 에러코드를얻을수있는메서드도추가했다. return ERR_CODE; // 이메서드는주로 getmessage() 와함께사용될것이다. public String getmessage() { // Exception의 getmeesage() 를오버라이딩한다. return "["+geterrcode()+"]" + super.getmessage(); class Exercise8_9 { public static void main(string[] args) throws Exception { throw new UnsupportedFuctionException(" 지원하지않는기능입니다.",100);

Java의정석定石 307 실행결과 [ ] Exception in thread "main" UnsupportedFuctionException: [100] 지원하지않는기능입니다. at Exercise8_9.main(Exercise8_9.java:5) [ 해설] 에러메시지를저장하는인스턴스변수 msg는상속받은것이므로조상의생성자를 호출해서초기화되도록해야한다. ERR_CODE는한번값이지정되면바뀌는값이아니라 서 final 을붙여서상수로했다. 그리고생성자를통해초기화하였다. UnsupportedFuctionException(String msg, int errcode) { // 생성자 super(msg); // 조상의생성자 RuntimeException(String msg) 를호출 ERR_CODE = errcode; getmessage() 역시조상으로부터상속받은것이며, ERR_CODE도같이출력되도록하기위 해오버라이딩했다. 조상의메서드를오버라이딩할때는, 가능하다면조상의메서드를재 활용하는것이좋다. public String getmessage() { // Exception의 getmeesage() 를오버라이딩한다. return "["+geterrcode()+"]" + super.getmessage();

308 Java의정석定石 [8-10] 아래의코드가수행되었을때의실행결과를적으시오. [ 연습문제]/ch8/Exercise8_10.java class Exercise8_10 { public static void main(string[] args) { try { method1(); // 예외발생!!! System.out.println(6); // 예외가발생해서실행되지않는다. catch(exception e) { System.out.println(7); static void method1() throws Exception { try { method2(); System.out.println(1); catch(nullpointerexception e) { System.out.println(2); throw e; // 예외를다시발생시킨다. 예외되던지기(re-throwing) catch(exception e) { System.out.println(3); finally { System.out.println(4); System.out.println(5); // method1() static void method2() { throw new NullPointerException(); // NullPointerException 을발생시킨다. [ 정답] 실행결과 [ ] 2 4 7 [ 해설] method2() 에서발생한예외를 method1() 의 try-catch문에서처리했다가다시발생 시킨다. catch(nullpointerexception e) { System.out.println(2); throw e; // 예외를다시발생시킨다. 예외되던지기(re-throwing) catch(exception e) { 예외가발생한 catch 블럭내에이예외(NullPointerException) 를처리할 try-catch블럭이 없기때문에 method1() 이종료되면서 main 메서드에예외가전달된다. 이때예외가처리 되진않았지만, finally블럭의문장이수행되어 4 가출력된다.

Java의정석定石 309 main메서드의 try-catch블럭은 method1() 으로부터전달된예외를처리할 catch블럭이있 으므로해당 catch블럭이수행되어 7을출력하고 try-catch 블럭을벗어난다. 그리고더 이상수행할코드가없으므로프로그램이종료된다. try { method1(); // NullPointerException 발생!!! System.out.println(6); // 예외가발생해서실행되지않는다. catch(exception e) { // 모든종류의예외를처리할수있다. System.out.println(7);

310 Java의정석定石 Chapter java.lang 패키지 java.lang package

Java의정석定石 311 [ 연습문제 - 모범답안 ] [9-1] 다음과같은실행결과를얻도록 SutdaCard클래스의 equals() 를멤버변수인 num, iskwang 의값을비교하도록오버라이딩하고테스트하시오. [ 연습문제]/ch9/Exercise9_1.java class Exercise9_1 { public static void main(string[] args) { SutdaCard c1 = new SutdaCard(3,true); SutdaCard c2 = new SutdaCard(3,true); System.out.println("c1="+c1); System.out.println("c2="+c2); System.out.println("c1.equals(c2):"+c1.equals(c2)); class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public boolean equals(object obj) { if(obj instanceof SutdaCard) { SutdaCard c = (SutdaCard)obj; return num==c.num && iskwang==c.iskwang; return false; public String tostring() { return num + ( iskwang? "K":""); 실행결과 [ ] c1=3k c2=3k c1.equals(c2):true

312 Java의정석定石 [ 해설] 매개변수가 Object 타입이므로어떤타입의인스턴스도매개변수로가능하다. 그래서반드시 instanceof로확인한후에형변환해서멤버변수 num과 iskwang의값을비 교해야한다. 만일 instanceof의결과가 false라면멤버변수의값을비교할필요도없이 그냥 false 만반환하면된다. public boolean equals(object obj) { if(obj instanceof SutdaCard) { SutdaCard c = (SutdaCard)obj; return num==c.num && iskwang==c.iskwang; return false;

Java의정석定石 313 [9-2] 다음과같은실행결과를얻도록 Point3D클래스의 equals() 를멤버변수인 x, y, z 의값을비교하도록오버라이딩하고, tostring() 은실행결과를참고해서적절히오버라이 딩하시오. [ 연습문제]/ch9/Exercise9_2.java class Exercise9_2 { public static void main(string[] args) { Point3D p1 = new Point3D(1,2,3); Point3D p2 = new Point3D(1,2,3); System.out.println(p1); System.out.println(p2); System.out.println("p1==p2?"+(p1==p2)); System.out.println("p1.equals(p2)?"+(p1.equals(p2))); class Point3D { int x,y,z; Point3D(int x, int y, int z) { this.x=x; this.y=y; this.z=z; Point3D() { this(0,0,0); public boolean equals(object obj) { if(obj instanceof Point3D) { Point3D p =(Point3D)obj; return x==p.x && y==p.y && z==p.z; return false; public String tostring() { return "["+x+","+y+","+z+"]"; 실행결과 [ ] [1,2,3] [1,2,3] p1==p2?false p1.equals(p2)?true [ 해설] 문제9-1 과유사한문제이므로설명을생략하겠다.

314 Java의정석定石 [9-3] 다음과같은실행결과가나오도록코드를완성하시오. [ 연습문제]/ch9/Exercise9_3.java class Exercise9_3 { public static void main(string[] args) { String fullpath = "c:\\jdk1.8\\work\\pathseparatetest.java"; String path = ""; String filename = ""; int pos = fullpath.lastindexof("\\"); if(pos!=-1) { path = fullpath.substring(0, pos); filename = fullpath.substring(pos+1); System.out.println("fullPath:"+fullPath); System.out.println("path:"+path); System.out.println("fileName:"+fileName); 실행결과 [ ] fullpath:c:\jdk1.8\work\pathseparatetest.java path:c:\jdk1.8\work filename:pathseparatetest.java [ 해설] lastindexof() 와 substring() 을사용해서문자열을나누는문제다. 마지막경로구 분자를찾아야하기때문에, indexof() 보다는 lastindexof() 가적합하다. lastindexof() 는찾는문자열이없으면 -1을반환하기때문에조건문을사용해서결과가 -1인경우에는 substring() 을호출하지않아야한다.(pos 의값이음수이면, substring() 에서예외가발생한다.) 그래서 if 문으로처리를해주었는데, try-catch 로처리해도좋다.(if문없이문제를풀 었어도충분히좋은답안이다.) [ 참고] 아래의두문장은서로같은의미이다. filename = fullpath.substring(pos+1); // 지정된위치부터끝까지잘라낸다. filename = fullpath.substring(pos+1, fullpath.length()); // 위문장과동일

Java의정석定石 315 [9-4] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : printgraph 기능 : 주어진배열에담긴값만큼주어진문자를가로로출력한후, 값을출력한다. 반환타입 : 없음 매개변수 : int[] dataarr - 출력할그래프의데이터 char ch - 그래프로출력할문자. [ 연습문제]/ch9/Exercise9_4.java class Exercise9_4 { static void printgraph(int[] dataarr, char ch) { for(int i=0; i < dataarr.length;i++) { for(int j=0; j < dataarr[i];j++) { System.out.print(ch); System.out.println(dataArr[i]); public static void main(string[] args) { printgraph(new int[]{3,7,1,4,'*'); 실행결과 [ ] ***3 *******7 *1 ****4 [ 해설] 반복문으로배열의저장된숫자를읽어서, 그숫자만큼별을출력하면된다.

316 Java의정석定石 [9-5] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : count 기능 : 주어진문자열(src) 에찾으려는문자열(target) 이몇번나오는지세어서반환한다. 반환타입 : int 매개변수 : String src String target [Hint] String클래스의 indexof(string str, int fromindex) 를사용할것 [ 연습문제]/ch9/Exercise9_5.java class Exercise9_5 { public static int count(string src, String target) { int count = 0; // 찾은횟수 int pos = 0; // 찾기시작할위치 // (1) 반복문을사용해서아래의과정을반복한다. while(true) { // 1. src에서 target을 pos 의위치부터찾는다. pos = src.indexof(target,pos); // 2. 찾으면 count의값을 1 증가시키고, // pos의값을 target.length 만큼증가시킨다. if(pos!=-1) { count++; pos += target.length(); // pos 를찾은단어이후로옮긴다. else { // 3. indexof의결과가 -1이면반복문을빠져나가서 count 를반환한다. break; return count; public static void main(string[] args) { System.out.println(count("12345AB12AB345AB","AB")); System.out.println(count("12345","AB")); 실행결과 [ ] 3 0 [ 해설] indexof() 는지정된문자열을찾아서그위치를알려준다. 만일찾지못한다면 -1 을반환한다. 문자열 "12345AB12AB345AB" 에서문자열 "AB" 를 indexof() 로찾으면그첫 번째위치는아래의표에서알수있듯이 5 이다. 두번째는 9, 세번째는 14 이다. index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 char 1 2 3 4 5 A B 1 2 A B 3 4 5 A B

Java의정석定石 317 지정된문자열을찾으면변수 count를 1 증가시키고, 찾기시작할위치를찾은문자열의 이후로변경해주어야그다음에나오는일치하는문자열을찾을수있다. 그래서찾은위치(pos) 에찾은문자열의길이(target.length()) 를더해주는것이다. 여 기서는 target.length() 의값이 2 이므로찾은위치에서두글자뒤부터찾기시작한다. // 2. 찾으면 count의값을 1 증가시키고, pos의값을 target.length 만큼증가시킨다. if(pos!=-1) { count++; pos += target.length(); // pos 를찾은단어이후로옮긴다. else {... pos pos+target.length() index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 char 1 2 3 4 5 A B 1 2 A B 3 4 5 A B 참고로반복문을좀더간결히하면아래와같이할수있다. while((pos = src.indexof(target,pos))!=-1) { count++; pos += target.length();

318 Java의정석定石 [9-6] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : fillzero 기능 : 주어진문자열( 숫자) 로주어진길이의문자열로만들고, 왼쪽빈공간은 '0' 으로 채운다. 만일주어진문자열이 null이거나문자열의길이가 length의값과같으면그대로 반환한다. 반환타입 : String 만일주어진 length의값이 0 보다같거나작은값이면, 빈문자열("") 을반환한다. 매개변수 : String src - 변환할문자열 int length - 변환한문자열의길이 [ 연습문제]/ch9/Exercise9_6.java class Exercise9_6 { public static String fillzero(string src, int length) { // 1. src가널이거나 src.length() 가 length와같으면 src 를그대로반환한다. if(src==null src.length()==length) { return src; // 2. length의값이 0 보다같거나작으면빈문자열("") 을반환한다. else if(length <=0) { return ""; // 3. src의길이가 length의값보다크면 src를 length 만큼잘라서반환한다. else if(src.length() > length) { return src.substring(0,length); // 4. 길이가 length인 char 배열을생성한다. char[] charr = new char[length]; // 5. 4에서생성한 char 배열을 '0' 으로채운다. for(int i=0;i<charr.length;i++) charr[i] = '0'; // 6. src에서문자배열을뽑아내서 4 에서생성한배열에복사한다. System.arraycopy(src.toCharArray(),0,chArr,length-src.length(), src.length()); // 7. 4에서생성한배열로 String 을생성해서반환한다. return new String(chArr); public static void main(string[] args) { String src = "12345"; System.out.println(fillZero(src,10)); System.out.println(fillZero(src,-1)); System.out.println(fillZero(src,3)); [ 실행결과] 0000012345 123

Java의정석定石 319 [9-7] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : contains 기능 : 첫번째문자열(src) 에두번째문자열(target) 이포함되어있는지확인한다. 반환타입 : boolean 매개변수 : String src 포함되어있으면 true, 그렇지않으면 false 를반환한다. String target [Hint] String클래스의 indexof() 를사용할것 [ 연습문제]/ch9/Exercise9_7.java class Exercise9_7 { public static boolean contains(string src, String target) { return src.indexof(target)!=-1; public static void main(string[] args) { System.out.println(contains("12345","23")); System.out.println(contains("12345","67")); 실행결과 [ ] true false [ 해설] indexof() 는지정된문자열(src) 에서특정문자열(target) 을찾아서그위치를알 려준다. 만일찾지못한다면 -1을반환하므로 indexof() 의결과가 -1인지만확인해서그 결과를돌려주면된다. 예를들어 'src.indexof(target)' 의결과가 -1 이라면아래와같은연산과정을거친다. return src.indexof(target)!=-1; return -1!=-1; return false;

320 Java의정석定石 [9-8] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : round 기능 : 주어진값을반올림하여, 소수점이하 n 자리의값을반환한다. 반환타입 : double 예를들어 n의값이 3 이면, 소수점 4째자리에서반올림하여소수점이하 3자리의 수를반환한다. 매개변수 : double d - 변환할값 int n - 반올림한결과의소수점자리 [Hint] Math.round() 와 Math.pow() 를이용하라. [ 연습문제]/ch9/Exercise9_8.java class Exercise9_8 { public static double round(double d, int n) { return Math.round(d * Math.pow(10, n)) / Math.pow(10,n); public static void main(string[] args) { System.out.println(round(3.1415,1)); System.out.println(round(3.1415,2)); System.out.println(round(3.1415,3)); System.out.println(round(3.1415,4)); System.out.println(round(3.1415,5)); 실행결과 [ ] 3.1 3.14 3.142 3.1415 3.1415 [ 해설] Math.round() 는소수점첫째자리에서반올림해서 long타입의정수로반환하고 Math.pow(double a, double b) 는 a의 b 제곱을반환한다. 10의 3제곱은 Math.pow(10,3) 으 로구할수있다. Math.round() 가소수점첫째자리에서반올림하기때문에, 소수점 n+1째자리에서반올 림해서소수점 n째자리로만들려면 10의 n제곱을곱한다음에반올림하고다시 10의 n제 곱으로나눠줘야한다. 이두메서드는 Math 클래스에선언되어있으며, 선언부는아래와같다. public static long round(double a) public static double pow(double a, double b)

Java의정석定石 321 [9-9] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : delchar 기능 : 주어진문자열에서금지된문자들을제거하여반환한다. 반환타입 : String 매개변수 : String src - 변환할문자열 String delch - 제거할문자들로구성된문자열 [ 힌트] StringBuffer와 String클래스의 charat(int i) 과 indexof(int ch) 를사용하라. [ 연습문제]/ch9/Exercise9_9.java class Exercise9_9 { public static String delchar(string src, String delch) { StringBuffer sb = new StringBuffer(src.length()); for(int i=0; i < src.length();i++) { char ch = src.charat(i); // ch가 delch 에포함되있지않으면(indexOf() 로못찾으면) sb에추가 if(delch.indexof(ch)==-1) // indexof(int ch) 를호출 sb.append(ch); return sb.tostring(); // StringBuffer에저장된내용을 String으로반환 public static void main(string[] args) { System.out.println("(1!2@3^4~5)"+" -> " + delchar("(1!2@3^4~5)","~!@#$%^&*()")); System.out.println("(1 2 3 4\t5)"+" -> " + delchar("(1 2 3 4\t5)"," \t")); 실행결과 [ ] (1!2@3^4~5) -> 12345 (1 2 3 4 5) -> (12345) [ 해설] 반복문을이용해서주어진문자열(src) 의문자를순서대로가져와서, 삭제할문자 열(delCh) 에포함되었는지확인한다. 포함되어있지않을때만(indexOf() 의결과가 -1일 때만), StringBuffer 에추가한다. int indexof(int ch) // 문자열에서특정문자(ch) 를찾을때사용 // 매개변수타입이 int지만 char 값을넣으면된다. int indexof(string str) // 문자열에서특정문자열(str) 을찾을때사용

322 Java의정석定石 [9-10] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : format 기능 : 주어진문자열을지정된크기의문자열로변환한다. 나머지공간은공백으로채운다. 반환타입 : String 매개변수 : String str - 변환할문자열 int length - 변환된문자열의길이 int alignment - 변환된문자열의정렬조건 (0: 왼쪽정렬, 1: 가운데정렬, 2: 오른쪽정렬) [ 연습문제]/ch9/Exercise9_10.java class Exercise9_10 { static String format(string str, int length, int alignment) { // 1. length의값이 str의길이보다작으면 length 만큼만잘라서반환한다. int diff = length - str.length(); if(diff < 0) return str.substring(0, length); // 2. 1 의경우가아니면, length크기의 char 배열을생성하고공백으로채운다. char[] source = str.tochararray(); // 문자열을 char배열로변환 char[] result = new char[length]; for(int i=0; i < result.length; i++) result[i] = ' '; // 배열 result 를공백으로채운다. // 3. 정렬조건(alignment) 의값에따라문자열(str) 을복사할위치를결정한다. switch(alignment) { case 0 : default : System.arraycopy(source, 0, result, 0, source.length); break; case 1 : System.arraycopy(source, 0, result, diff/2, source.length); break; case 2 : System.arraycopy(source, 0, result, diff, source.length); break; // 4. 2에서생성한 char 배열을문자열로만들어서반환한다. return new String(result); // static String format(string str, int length, int alignment) { public static void main(string[] args) { String str = " 가나다"; System.out.println(format(str,7,0)); // 왼쪽정렬 System.out.println(format(str,7,1)); // 가운데정렬 System.out.println(format(str,7,2)); // 오른쪽정렬 실행결과 [ ] 가나다가나다가나다

Java의정석定石 323 [9-11] 커맨드라인으로 2~9사이의두개의숫자를받아서두숫자사이의구구단을출력 하는프로그램을작성하시오. 예를들어 3과 5를입력하면 3단부터 5 단까지출력한다. [ 실행결과] C:\jdk1.8\work\ch9>java Exercise9_11 2 시작단과끝단, 두개의정수를입력해주세요. USAGE : GugudanTest 3 5 C:\jdk1.8\work\ch9>java Exercise9_11 1 5 단의범위는 2와 9 사이의값이어야합니다. USAGE : GugudanTest 3 5 C:\jdk1.8\work\ch9>java Exercise9_11 3 5 3*1=3 3*2=6 3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27 4*1=4 4*2=8 4*3=12 4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45 [ 정답] [ 연습문제]/ch9/Exercise9_11.java class Exercise9_11 { public static void main(string[] args) { int from = 0; int to = 0; try { if(args.length!=2)

324 Java의정석定石 throw new Exception(" 시작단과끝단, 두개의정수를입력해주세요."); from = Integer.parseInt(args[0]); to = Integer.parseInt(args[1]); if(!(2 <= from && from <= 9 && 2 <= to && to <= 9)) throw new Exception(" 단의범위는 2와 9 사이의값이어야합니다."); catch(exception e) { System.out.println(e.getMessage()); System.out.println("USAGE : GugudanTest 3 5"); System.exit(0); // 시작단(from) 이끝단(to) 보다작아야하니까 // to보다 from 의값이크면두값을바꾼다. if(from > to) { int tmp = from; from = to; to = tmp; // from단부터 to 단까지출력한다. for(int i=from;i<=to;i++) { for(int j=1;j<=9;j++) { System.out.println(i+"*"+j+"="+i*j); System.out.println(); // main [ 해설] 커맨드라인을통해두개의정수를입력받고유효성검사를하는부분을예외로 처리하였는데, 그냥 if 문으로만처리해도되지만코드의중복을줄이려고그렇게했다. 특별히어려운부분은없으므로자세한설명은생략하겠다.

Java의정석定石 325 [9-12] 다음과같이정의된메서드를작성하고테스트하시오. [ 주의] Math.random() 을사용하는경우실행결과와다를수있음. 메서드명 : getrand 기능 : 주어진범위(from~to) 에속한임의의정수값을반환한다. 반환타입 : int ( 양쪽경계값모두범위에포함) from의값이 to 의값보다클경우도처리되어야한다. 매개변수 : int from - 범위의시작값 int to - 범위의끝값 [Hint] Math.random() 과절대값을반환하는 Math.abs(int a), 그리고둘중에작은값을반환하는 Math.min(int a, int b) 를사용하라. [ 연습문제]/ch9/Exercise9_12.java class Exercise9_12 { public static int getrand(int from, int to) { return (int)(math.random() * (Math.abs(to-from)+1))+ Math.min(from,to); public static void main(string[] args) { for(int i=0; i< 20; i++) System.out.print(getRand(1,-3)+","); 실행결과 [ ] 0,-1,1,0,-2,-2,1,1,-3,0,-1,1,1,1,0,-1,1,0,-1,-3, [ 해설] 만일 1~10 범위의임의의값을구하려면, 아래와같은식으로구할수있다는것을 이미배웠다. 1 <= (int)(math.random()*10)+1 < 11 위의식에서 Math.random() 에곱해준값 10은바로범위에포함된정수의개수라는것을 알수있다. 예를들어 1~10의범위라면 10 개의정수중의하나가임의로선택될것이다. 이값은 '( 끝값- 시작값)+1' 로구할수있다. '(10-1)+1' 을계산한결과는 10 이된다. 1 <= (int)(math.random()*(to-from+1)+1 < 11 문제의조건중에 from의값이 to의값보다클경우도처리하라는것이있으므로 Math.abs() 를이용해서 ' 끝값- 시작값' 이음수가되지않도록처리해야한다. 1 <= (int)(math.random()*(math.abs(to-from)+1)+1 < 11

326 Java의정석定石 Math.random() 에더해주는값은범위의시작값이다. 문제의조건중에 from의값이 to값 보다클경우도처리해야하므로 from과 to 중에서작은값이더해져야한다. 삼항연산자 를써서처리할수도있지만, Math.min() 을사용했다. 1 <= (int)(math.random()*(math.abs(to-from)+1)+1 < 11 1 <= (int)(math.random()*(math.abs(to-from)+1) +(from < to? from:to) < 11 1 <= (int)(math.random()*(math.abs(to-from)+1) + Math.min(from,to) < 11

Java의정석定石 327 [9-13] 다음은하나의긴문자열(source) 중에서특정문자열과일치하는문자열의개수 를구하는예제이다. 빈곳을채워예제를완성하시오. [ 연습문제]/ch9/Exercise9_13.java public class Exercise9_13 { public static void main(string[] args) { String src = "aabbccaabbccaa"; System.out.println(src); System.out.println("aa 를 " + stringcount(src, "aa") +" 개찾았습니다."); static int stringcount(string src, String key) { return stringcount(src, key, 0); static int stringcount(string src, String key, int pos) { int count = 0; int index = 0; if (key == null key.length() == 0) return 0; while((index = src.indexof(key, pos))!=-1) { count++; pos = index + key.length(); return count; [ 실행결과] aabbccaabbccaa aa를 2 개찾았습니다. [ 해설] String클래스의 indexof() 는특정문자열(src) 에서찾으려는문자열(key) 이존재 하면해당문자열이시작하는위치를반환하고, 존재하지않으면 -1 을반환한다. pos는 비교를시작할위치이며, pos의값이 0 이면문자열의처음부터검색한다. 반복문을이용해서 indexof() 의결과가 -1 아될때까지반복하면된다. while((index = src.indexof(key, pos))!=-1) { count++; // 일치하는부분을찾으면, count의값을 1증가 pos = index + key.length(); // 검색을시작할위치를변경 while 문의조건식은아래의문장과조건식을하나로합친것과같다. index = src.indexof(key, pos); // src에 key와일치하는부분의위치를반환 index!=-1 // 조건식. index의값이 -1인지비교 여기서한가지주의할점은, 검색하려는문자열(key) 와일치하는위치를찾으면그다음

328 Java의정석定石 에는 pos 의위치를변경해줘야한다. 그래야그다음으로일치하는위치를찾을수있다. 검색을시작할위치(pos) 를변경하지않으면, 계속해서같은위치를반환하기때문에무 한반복에빠지게된다. while((index = src.indexof(key, pos))!=-1) { count++; pos = index + key.length(); // 검색을시작할위치(pos) 를 // 발견위치(index)+ 찾을문자열길이(key.length()) 로변경

Java의정석定石 329 [9-14] 다음은화면으로부터전화번호의일부를입력받아일치하는전화번호를주어진 문자열배열에서찾아서출력하는프로그램이다. 알맞은코드를넣어프로그램을완성하 시오. [Hint] Pattern, Matcher 클래스를사용하라. [ 연습문제]/ch11/Exercise11_18.java import java.util.*; import java.util.regex.*; class Exercise11_18 { public static void main(string[] args) { String[] phonenumarr = { "012-3456-7890", "099-2456-7980", "088-2346-9870", "013-3456-7890" ; Vector list = new Vector(); // 검색결과를담을 Vector Scanner s = new Scanner(System.in); while(true) { System.out.print(">>"); String input = s.nextline().trim(); // trim() 으로입력내용에서공백을제거 if(input.equals("")) { continue; else if(input.equalsignorecase("q")) { System.exit(0); String pattern = ".*"+input+".*"; // input 을포함하는모든문자열 Pattern p = Pattern.compile(pattern); for(int i=0; i< phonenumarr.length;i++) { String phonenum = phonenumarr[i]; String tmp = phonenum.replace("-",""); // phonenum 에서 '-' 를제거 Matcher m = p.matcher(tmp); if(m.find()) { // 패턴과일치하면, list에 phonenum 을추가한다. list.add(phonenum); if(list.size()>0) { // 검색결과가있으면 System.out.println(list); // 검색결과를출력하고 list.clear(); // 검색결과를삭제 else { System.out.println(" 일치하는번호가없습니다."); // main

330 Java의정석定石 실행결과 [ ] >> >> >>asdf 일치하는번호가없습니다. >> >> >>0 [012-3456-7890, 099-2456-7980, 088-2346-9870, 013-3456-7890] >>234 [012-3456-7890, 088-2346-9870] >>7890 [012-3456-7890, 013-3456-7890] >>q [ 해설] 입력받은문자열을포함하는모든문자열을의미하는패턴은다음과같다. String pattern = ".*"+input+".*"; // input을포함하는모든문자열 Pattern p = Pattern.compile(pattern); 패턴을정의하였으니, 이제는반복문으로배열 phonenumarr의전화번호를하나씩읽어서 패턴과일치하는지확인한다. 이때주의해야할것은사용자가 "234" 를입력했을때 "012-3456-8790" 과 "088-2346-9870" 이모두검색될수있도록전화번호에서 '-' 를제거한 후에패턴과일치하는지확인해야한다는것이다. for(int i=0; i< phonenumarr.length;i++) { String phonenum = phonenumarr[i]; String tmp = phonenum.replace("-",""); // phonenum 에서 '-' 를제거 Matcher m = p.matcher(tmp); if(m.find()) { // 패턴과일치하는부분을찾으면, list에 phonenum 을추가한다. list.add(phonenum);

Java의정석定石 331 [ 연습문제 - 모범답안 ] [10-1] Calendar클래스와 SimpleDateFormat클래스를이용해서 2010년의매월두번째 일요일의날짜를출력하시오. [ 실행결과] 2010-01-10은 2 번째일요일입니다. 2010-02-14은 2 번째일요일입니다. 2010-03-14은 2 번째일요일입니다. 2010-04-11은 2 번째일요일입니다. 2010-05-09은 2 번째일요일입니다. 2010-06-13은 2 번째일요일입니다. 2010-07-11은 2 번째일요일입니다. 2010-08-08은 2 번째일요일입니다. 2010-09-12은 2 번째일요일입니다. 2010-10-10은 2 번째일요일입니다. 2010-11-14은 2 번째일요일입니다. 2010-12-12은 2 번째일요일입니다. [ 정답] [ 연습문제]/ch10/Exercise10_1.java import java.util.*; import java.text.*; class Exercise10_1 { public static void main(string[] args) { Calendar cal = Calendar.getInstance(); cal.set(2010,0,1); // cal의날짜를 2010년 1월 1 일로설정한다. for(int i=0; i < 12;i++) { int weekday = cal.get(calendar.day_of_week); // 1 일의요일을구한다. // 두번째일요일은 1 일의요일에따라달라진다. // 1일이일요일인경우에는두번째일요일은 8 일이고, // 1일이다른요일일때는 16에서 1 일의요일(weekday) 을빼면알수있다. int secondsunday = (weekday==1)? 8 : 16 - weekday; // 두번째일요일(secondSunday) 로 cal 의날짜(DAY_OF_MONTH) 를바꾼다. cal.set(calendar.day_of_month, secondsunday); Date d = cal.gettime(); // Calendar를 Date 로변환한다. System.out.println(new SimpleDateFormat("yyyy-MM-dd은 F번째 E요일입니 다.").format(d)); // 날짜를다음달 1 일로변경한다. cal.add(calendar.month, 1); cal.set(calendar.day_of_month,1);

332 Java의정석定石 [ 해설] 매월두번째일요일(secondSunday) 을구하려면, 매월 1일이무슨요일인지알아 내야한다. 만일 1일이일요일이라면 2번째일요일은 8 일이된다. 1일이월요일이라면 2 번째일요일은 14 일이된다. 1일이일요일인경우를제외하고는 1 일의요일(weekday) 과 2 번째일요일의날짜를더하면일정한값(16) 이라는것을알수있다. 즉, 16에서 1일의 요일(weekday) 을빼면 2 번째일요일이며칠인지알수있는것이다.(1일이일요일인경우 에는 9에서 1을뺀 8 이된다.) int secondsunday = (weekday==1)? 8 : 16 - weekday; 1일의요일 weekday 2번째일요일 weekday+2번째일요일 일 1 8일 9 월 2 14일 16 화 3 13일 16 수 4 12일 16 목 5 11일 16 금 6 10일 16 토 7 9일 16 이제두번째일요일의날짜(secondSunday) 를알아냈으니, set() 를사용해서 cal의날짜 (DAY_OF_MONTH) 를두번째일요일의날짜로변경한다. SimpleDateFormat클래스의 format 메서드는매개변수로 Date타입을받기때문에 cal.gettime() 을호출해서 Calendar를 Date 로변환해야한다. // 두번째일요일(secondSunday) 로 cal 의날짜(DAY_OF_MONTH) 를바꾼다. cal.set(calendar.day_of_month, secondsunday); Date d = cal.gettime(); // Calendar를 Date 로변환한다. System.out.println(new SimpleDateFormat("yyyy-MM-dd은 F번째 E요일입니 다.").format(d));

Java의정석定石 333 [10-2] 어떤회사의월급날이매월 21 일이다. 두날짜사이에월급날이몇번있는지계 산해서반환하는메서드를작성하고테스트하시오. [ 연습문제]/ch10/Exercise10_2.java import java.util.*; import java.text.*; class Exercise10_2 { static int paycheckcount(calendar from, Calendar to) { // 1. from 또는 to가 null이면 0 을반환한다. if(from==null to==null) return 0; // 2. from와 to가같고날짜가 21일이면 1 을반환한다. if(from.equals(to) && from.get(calendar.day_of_month)==21) { return 1; int fromyear = from.get(calendar.year); int frommon = from.get(calendar.month); int fromday = from.get(calendar.day_of_month); int toyear = to.get(calendar.year); int tomon = to.get(calendar.month); int today = to.get(calendar.day_of_month); // 3. to와 from이몇개월차이인지계산해서변수 mondiff 에담는다. int mondiff = (toyear * 12 + tomon) - (fromyear * 12 + frommon); // 4. mondiff가음수이면 0 을반환한다. if(mondiff < 0) return 0; // 5. 만일 from 의일(DAY_OF_MONTH) 이 21일이거나이전이고 // to 의일(DAY_OF_MONTH) 이 21일이거나이후이면 mondiff의값을 1 증가시킨다. if(fromday <= 21 && today >= 21) mondiff++; // 6. 만일 from 의일(DAY_OF_MONTH) 이 21일이후고 // to 의일(DAY_OF_MONTH) 이 21일이전이면 mondiff의값을 1 감소시킨다. if(fromday > 21 && today < 21) mondiff--; return mondiff; static void printresult(calendar from, Calendar to) { Date fromdate = from.gettime(); Date todate = to.gettime(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); System.out.print(sdf.format(fromDate)+" ~ " +sdf.format(todate)+":"); System.out.println(paycheckCount(from, to)); public static void main(string[] args) { Calendar fromcal = Calendar.getInstance();

334 Java의정석定石 Calendar tocal = Calendar.getInstance(); fromcal.set(2010,0,1); tocal.set(2010,0,1); printresult(fromcal, tocal); fromcal.set(2010,0,21); tocal.set(2010,0,21); printresult(fromcal, tocal); fromcal.set(2010,0,1); tocal.set(2010,2,1); printresult(fromcal, tocal); fromcal.set(2010,0,1); tocal.set(2010,2,23); printresult(fromcal, tocal); fromcal.set(2010,0,23); tocal.set(2010,2,21); printresult(fromcal, tocal); fromcal.set(2011,0,22); tocal.set(2010,2,21); printresult(fromcal, tocal); [ 실행결과] 2010-01-01 ~ 2010-01-01:0 2010-01-21 ~ 2010-01-21:1 2010-01-01 ~ 2010-03-01:2 2010-01-01 ~ 2010-03-23:3 2010-01-23 ~ 2010-03-21:2 2011-01-22 ~ 2010-03-21:0 [ 해설] 지정된날짜범위에 21 일이몇번포함되는지계산하려면, 범위의시작일과마지 막일간의개월수차이를구한다음에시작일또는마지막일이 서둘다 21일이면 1을더하고둘다 21일이아니면 1 을뺀다. 21일인지아닌지확인해 [ 참고] 1~5의범위의정수가몇개인지알려면범위의끝값인 5에서시작값인 1을뺀다음에 1과 5가범위에 포함된다면 1을더해서 5-1+1=5 가된다.(1,2,3,4,5) 그러나 1과 5가범위에포함되지않는다면 1을빼서 5-1-1=3 이된다.(2,3,4) 어느한쪽경계값만범위에포함된다면두경계값의차이(5-1=4) 가범위에포함된정수의개수이 다. // 3. to와 from이몇개월차이인지계산해서변수 mondiff 에담는다. int mondiff = (toyear * 12 + tomon) - (fromyear * 12 + frommon); // 4. mondiff가음수이면 0 을반환한다. if(mondiff < 0) return 0; // 5. 만일 from 의일(DAY_OF_MONTH) 이 21일이거나이전이고 // to 의일(DAY_OF_MONTH) 이 21일이거나이후이면 mondiff의값을 1 증가시킨다. if(fromday <= 21 && today >= 21) mondiff++; // 6. 만일 from 의일(DAY_OF_MONTH) 이 21일이후고 // to 의일(DAY_OF_MONTH) 이 21일이전이면 mondiff의값을 1 감소시킨다. if(fromday > 21 && today < 21) mondiff--;

Java의정석定石 335 [10-3] 문자열 123,456,789.5 를소수점첫번째자리에서반올림하고, 그값을만단 위마다콤마(,) 로구분해서출력하시오. [ 실행결과] data:123,456,789.5 반올림 :123456790 만단위 :1,2345,6790 [ 정답] [ 연습문제]/ch10/Exercise10_3.java import java.text.*; class Exercise10_3 { public static void main(string[] args) { String data = "123,456,789.5"; DecimalFormat df = new DecimalFormat("#,###.##"); // DecimalFormat df2 = new DecimalFormat("#,####"); 변환할문자열의형식을지정 try { Number num = df.parse(data); double d = num.doublevalue(); System.out.println("data:"+data); System.out.println(" 반올림:"+Math.round(d)); System.out.println(" 만단위:"+df2.format(d)); catch(exception e) { // main [ 해설] 특정형식의문자열을숫자로변환하려면 DecimalFormat클래스에형식을정의해준 다음에 parse() 를이용하면된다. parse() 의반환타입이 Number 이기때문에, Number에서 다시 doublevalue() 를호출해서 double 타입의값을얻어야한다. DecimalFormat df = new DecimalFormat("#,###.##"); // 변환할문자열의형식을지정 Number num = df.parse(data); // 문자열(data) 에서숫자를뽑아내서 Number 를반환한다. double d = num.doublevalue(); // Number에서숫자를 double 형태로뽑아낸다. format() 은주어진값을정해진형식에맞게변환한다음에문자열(String) 로반환한다. DecimalFormat df2 = new DecimalFormat("#,####"); System.out.println(" 만단위:"+df2.format(d));

336 Java의정석定石 [10-4] 화면으로부터날짜를 2007/05/11 의형태로입력받아서무슨요일인지출력하 는프로그램을작성하시오. 단, 입력된날짜의형식이잘못된경우메세지를보여주고다시입력받아야한다. [ 실행결과] 날짜를 yyyy/mm/dd 의형태로입력해주세요.( 입력예:2007/05/11) >>2009-12-12 날짜를 yyyy/mm/dd 의형태로입력해주세요.( 입력예:2007/05/11) >>2009/12/12 입력하신날짜는토요일입니다. [ 정답] [ 연습문제]/ch10/Exercise10_4.java import java.util.*; import java.text.*; class Exercise10_4 { public static void main(string[] args) { String pattern = "yyyy/mm/dd"; String pattern2 = " 입력하신날짜는 E 요일입니다."; // 'E' 는일~ 토중의하나가된다. DateFormat df = new SimpleDateFormat(pattern); DateFormat df2 = new SimpleDateFormat(pattern2); Scanner s = new Scanner(System.in); Date indate = null; do { System.out.println(" 날짜를 " + pattern + " 의형태로입력해주세요.( 입력예:2007/05/11)"); try { System.out.print(">>"); indate = df.parse(s.nextline()); // 입력받은날짜를 Date 로변환한다. break; // parse() 에서예외가발생하면이문장은수행되지않는다. catch(exception e) { while(true); System.out.println(df2.format(inDate)); // main [ 해설] SimpleDateFormat은날짜를지정된형식으로출력하거나문자열을지정된형식으 로변환또는유효성검사에사용할수있다. 이문제에서는입력된날짜가지정된형식 에맞는지검사하고, 변환하는역할을한다. Scanner 를이용해서화면으로부터날짜를입력받고, 입력받은날짜( 문자열) 가지정된 형식과다르면 parse() 에서 ParseException 이발생한다.

Java의정석定石 337 do { System.out.println(" 날짜를 " + pattern + " 의형태로입력해주세요.( 입력예:2007/05/11)"); try { System.out.print(">>"); indate = df.parse(s.nextline()) ; // ParseException 이발생할수있다. break; // parse() 에서예외가발생하면이문장은수행되지않는다. catch(exception e) { while(true); parse() 에서예외가발생하면 break문이수행되지않기때문에예외가발생하지않을때 까지, 즉지정된형식에맞게날짜가입력될때까지반복하게된다.

338 Java의정석定石 [10-5] 다음과같이정의된메서드를작성하고테스트하시오. 메서드명 : getdaydiff 기능 : yyyymmdd 형식의두문자열을넘겨받으면두날짜의차이를일(day) 단위로반환한다. 반환타입 : int 단, 첫번째날짜빼기두번째날짜의결과를반환한다. 만일주어진문자열이유효하지않으면 매개변수 : String yyyymmdd1 - 시작날짜 String yyyymmdd2 - 끝날짜 0 을반환한다. [ 연습문제]/ch10/Exercise10_5.java import java.util.*; class Exercise10_5 { static int getdaydiff(string yyyymmdd1, String yyyymmdd2) { int diff = 0; try { int year1 = Integer.parseInt(yyyymmdd1.substring(0,4)); int month1 = Integer.parseInt(yyyymmdd1.substring(4,6)) - 1; int day1 = Integer.parseInt(yyyymmdd1.substring(6,8)); int year2 = Integer.parseInt(yyyymmdd2.substring(0,4)); int month2 = Integer.parseInt(yyyymmdd2.substring(4,6)) - 1; int day2 = Integer.parseInt(yyyymmdd2.substring(6,8)); Calendar date1 = Calendar.getInstance(); Calendar date2 = Calendar.getInstance(); date1.set(year1, month1, day1); date2.set(year2, month2, day2); diff = (int)((date1.gettimeinmillis()-date2.gettimeinmillis()) /(24*60*60*1000)); catch(exception e) { diff = 0; // substring(), parseint() 에서예외가발생하면 0 을반환한다. return diff; public static void main(string[] args){ System.out.println(getDayDiff("20010103","20010101")); System.out.println(getDayDiff("20010103","20010103")); System.out.println(getDayDiff("20010103","200103")); 실행결과 [ ] 2 0 0

Java의정석定石 339 [ 해설] 넘겨받은문자열을 substring() 으로잘라서년, 월, 일을각각구한다음, 이값 들을가지고 Calendar 의년월일을설정한다. [ 참고] Calendar클래스의 month값은 1이아닌 0부터시작하기때문에 1 을빼주어야한다. int year1 = Integer.parseInt(yyyymmdd1.substring(0,4)); int month1 = Integer.parseInt(yyyymmdd1.substring(4,6)) - 1; int day1 = Integer.parseInt(yyyymmdd1.substring(6,8)); Calendar date1 = Calendar.getInstance(); date1.set(year1, month1, day1); Calendar의 gettimeinmillis() 는날짜를천분의일초단위로변환해서반환한다. gettime Millis() 를이용해서두날짜를천분의일초로변환해서차이를구한다음에일(day) 단 위로변환하면두날짜의날(day) 차이를구할수있다. 천분의일초단위를일단위로바꾸려면 24*60*60*1000 로나눠주면된다.(1 일 = 24시간 = 24*60 분 = 24*60*60 초 = 24*60*60*1000 밀리세컨드) date1.set(year1, month1, day1); date2.set(year2, month2, day2); diff = (int)((date1.gettimeinmillis()-date2.gettimeinmillis()) /(24*60*60*1000));

340 Java의정석定石 [10-6] 자신이태어난날부터지금까지며칠이지났는지계산해서출력하시오. [ 실행결과] birth day=2000-01-01 today =2016-01-29 5872 days [ 정답] LocalDate의 until() 을이용하면쉽게해결된다. [ 연습문제]/ch10/Exercise10_6.java import java.time.*; import java.time.temporal.*; class Exercise10_6 { public static void main(string[] args) { LocalDate birthday = LocalDate.of(2000, 1, 1); // 자신의생일을지정 LocalDate now = LocalDate.now(); long days = birthday.until(now, ChronoUnit.DAYS); System.out.println("birth day="+birthday); System.out.println("today ="+now); System.out.println(days +" days");

Java의정석定石 341 [10-7] 2016년 12 월넷째주화요일의날짜를아래와같이출력하시오. [ 실행결과] 2016-12-27 [ 정답]? 째주? 요일은 TemporalAdjusters클래스의 dayofweekinmonth() 를이용하면된다. [ 연습문제]/ch10/Exercise10_7.java import java.time.*; import static java.time.dayofweek.*; import static java.time.temporal.temporaladjusters.*; class Exercise10_7 { public static void main(string[] args) { LocalDate date = LocalDate.of(2016, 12, 1); System.out.println(date.with(dayOfWeekInMonth(4, TUESDAY)));

342 Java의정석定石 [10-8] 서울과뉴욕간의시차가얼마인지계산하여출력하시오. [ 실행결과] 2016-01-28T23:01:00.136+09:00[Asia/Seoul] 2016-01-28T09:01:00.138-05:00[America/New_York] sec1=32400 sec2=-18000 diff=14 hrs [ 정답] [ 연습문제]/ch10/Exercise10_8.java import java.time.*; class Exercise10_8 { public static void main(string[] args) { ZonedDateTime zdt = ZonedDateTime.now(); ZoneId nyid = ZoneId.of("America/New_York"); ZonedDateTime zdtny = ZonedDateTime.now().withZoneSameInstant(nyId); System.out.println(zdt); System.out.println(zdtNY); long sec1 = zdt.getoffset().gettotalseconds(); long sec2 = zdtny.getoffset().gettotalseconds(); long diff = (sec1 - sec2)/3600; System.out.println("sec1="+sec1); System.out.println("sec2="+sec2); System.out.printf("diff=%d hrs%n",diff); [ 해설] ZonedDateTime의 getoffset() 은 ZoneOffset 을반환한다. ZoneOffset의 gettotalseconds() 를호출하면, 날짜와시간을초단위로변환한결과를얻을수있다. ZoneOffset offset = zdt.getoffset(); long sec1 = offset.gettotalseconds(); 현재서울과뉴욕의날짜와시간을초단위로바꾼다음에, 차이를구하면시차를초단위로 구할수있다. 이값을 3600 초(1 시간) 으로나누면, 시간단위의값을구할수있다.

Java의정석定石 343 [ 연습문제 - 모범답안 ] [11-1] 다음은정수집합 1,2,3,4와 3,4,5,6 의교집합, 차집합, 합집합을구하는코드이 다. 코드를완성하여실행결과와같은결과를출력하시오. [Hint] ArrayList클래스의 addall(), removeall(), retainall() 을사용하라. [ 연습문제]/ch11/Exercise11_1.java import java.util.*; class Exercise11_1 { public static void main(string[] args) { ArrayList list1 = new ArrayList(); ArrayList list2 = new ArrayList(); ArrayList kyo = new ArrayList(); // 교집합 ArrayList cha = new ArrayList(); // 차집합 ArrayList hap = new ArrayList(); // 합집합 list1.add(1); list1.add(2); list1.add(3); list1.add(4); list2.add(3); list2.add(4); list2.add(5); list2.add(6); kyo.addall(list1); // list1의모든요소를 kyo 에저장한다. kyo.retainall(list2); // list2와 kyo 의공통요소만남기고삭제한다. cha.addall(list1); cha.removeall(list2); // cha에서 list2 와공통된요소들을모두삭제한다. hap.addall(list1); // list1의모든요소를 hap 에저장한다. hap.removeall(kyo); // hap에서 kyo 와공통된모든요소를삭제한다. hap.addall(list2); // list2의모든요소를 hap 에저장한다. System.out.println("list1="+list1); System.out.println("list2="+list2); System.out.println("kyo="+kyo); System.out.println("cha="+cha); System.out.println("hap="+hap); 실행결과 [ ] list1=[1, 2, 3, 4] list2=[3, 4, 5, 6] kyo=[3, 4] cha=[1, 2] hap=[1, 2, 3, 4, 5, 6]

344 Java의정석定石 [11-2] 다음코드의실행결과를적으시오. [ 연습문제]/ch11/Exercise11_2.java import java.util.*; class Exercise11_2 { public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(3); list.add(6); list.add(2); list.add(2); list.add(2); list.add(7); HashSet set = new HashSet(list); // 중복요소들이제거되고순서유지안됨 2,6,3,7 TreeSet tset = new TreeSet(set); // 오름차순으로정렬된다. 2,3,6,7 Stack stack = new Stack(); // Stack 에넣었다꺼내면저장순서가반대가된다. stack.addall(tset); // TreeSet의저장된모든요소를 stack 에담는다. while(!stack.empty()) System.out.println(stack.pop()); // stack 에저장된값을하나씩꺼낸다. [ 정답] 실행결과 [ ] 7 6 3 2 [ 해설] 각컬렉션클래스들의특징을이해하고있는지확인하는문제이다. ArrayList는 중복을허용하고저장순서를유지한다. HashSet은중복을허용하지않기때문에중복요소 들은저장되지않는다. 그래서 HashSet에는 2,6,3,7 이저장된다.(HashSet은저장순서를 유지하지않는다는사실을잊지말자 ) HashSet set = new HashSet(list); // 중복요소들이제거되고순서유지안됨 2,6,3,7 TreeSet 은정렬해서저장하기때문에, 그리고따로정렬기준을주지않았기때문에숫자 의기본정렬인오름차순으로정렬한다. 그래서 2,3,6,7 이된다. TreeSet tset = new TreeSet(set); // 오름차순으로정렬된다. 2,3,6,7 Stack은 FILO 구조( 처음넣은것이마지막에나오는구조) 로되어있기때문에 TreeSet의 모든요소들을저장한다음다시꺼내면저장한순서와반대가된다. Stack stack = new Stack(); // Stack 에넣었다꺼내면저장순서가반대가된다. stack.addall(tset); // TreeSet의저장된모든요소를 stack 에담는다. while(!stack.empty()) System.out.println(stack.pop()); // stack 에저장된값을하나씩꺼낸다.

Java의정석定石 345 [11-3] 다음중 ArrayList 에서제일비용이많이드는작업은? 단, 작업도중에 ArrayList 의크기변경이발생하지않는다고가정한다. a. b. c. d. 첫번째요소삭제 마지막요소삭제 마지막에새로운요소추가 중간에새로운요소추가 [ 정답] a [ 해설] ArrayList 는배열을기반으로하고, 배열은크기를변경할수없기때문에저장할 공간이부족하면새로운배열을만들고내용을복사해야하므로많은비용이든다. 그리고배열의중간에새로운요소를추가또는삭제하는것은다른요소들을이동시켜 야하기때문에배열을새로생성하는것보다는적지만역시비용이많이드는작업이다. 특히배열의첫번째요소를삭제하면, 빈자리를채우기위해나머지모든요소들을이 동시켜야하기때문에많은비용이든다. 반면에 ArrayList의마지막에요소를추가또는삭제하는것은다른요소들을이동시킬 필요가없기때문에아주적은비용만으로처리가가능하다.

346 Java의정석定石 [11-4] LinkedList 클래스는이름과달리실제로는이중원형연결리스트(doubly circular linked list) 로구현되어있다. LinkedList인스턴스를생성하고 11개의요소를 추가했을때, 이 11 개의요소중접근시간(access time) 이가장오래걸리는요소는몇 번째요소인가? [ 정답] 여섯번째요소(LinkedList 에서제일가운데위치한요소) [ 해설] LinkedList 는각요소가서로참조로연결되어있어서, n번째요소에접근하기위 해서는첫번째요소부터순서대로각요소를거쳐야된다. 예를들어세번째요소에접 근하기위해서는첫번째요소에서두번째요소로, 두번째요소에서세번째요소로이 동해야한다. linkedlist 0x200 0x300 0x350 0x380 0x400 0x200 0x300 0x350 0x380 0x400 null 0 1 2 3 4 이런식이면 LinkedList의마지막요소에접근하는것이시간이제일많이걸릴것같은 데, 그렇지않은이유는 LinkedList가실제로는아래의그림과같은이중원형연결리스 트로되어있기때문이다. 0x200 0x300 0x350 0x380 0x400 0x200 0x300 0x350 0x380 0x400 0x200 0x400 0x200 0x300 0x350 0x380 0 0 0 0 0 [ 그림11-11] 더블써큘러링크드리스트( 이중원형연결리스트, doubly circular linked list) 이중원형연결리스트는첫번째요소와마지막요소를연결해서 LinkedList의단점인접 근성(accessibility) 를향상시킨것이다. 이중원형연결리스트에서는마지막요소에접 근하기위해서는첫번째요소에서한번만이동하면된다. 마지막요소에서첫번째요 소에접근하기위해서도역시한번만이동하면된다. 이것은마치 Tv 리모콘의첫번째채널에서채널을감소시키면마지막채널로이동하고, 마지막채널에서채널을증가시키면첫번째채널로이동하는것과같다고할수있다. 그래서 다. LinkedList의제일가운데있는요소가접근시간이가장길다는것을알수있

Java의정석定石 347 [11-5] 다음에제시된 Student클래스가 Comparable인터페이스를구현하도록변경해서 이름(name) 이기본정렬기준이되도록하시오. [ 연습문제]/ch11/Exercise11_5.java import java.util.*; class Student implements Comparable { String name; int ban; int no; int kor, eng, math; Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; int gettotal() { return kor+eng+math; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage(); public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return name.compareto(tmp.name); // String클래스의 compareto() 를호출 else { return -1; class Exercise11_5 { public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(new Student(" 홍길동",1,1,100,100,100)); list.add(new Student(" 남궁성",1,2,90,70,80)); list.add(new Student(" 김자바",1,3,80,80,90)); list.add(new Student(" 이자바",1,4,70,90,70)); list.add(new Student(" 안자바",1,5,60,100,80)); Collections.sort(list); // list 에저장된요소들을정렬한다.(compareTo() 호출) Iterator it = list.iterator();

348 Java의정석定石 while(it.hasnext()) System.out.println(it.next()); [ 실행결과] 김자바,1,3,80,80,90,250,83.3 남궁성,1,2,90,70,80,240,80.0 안자바,1,5,60,100,80,240,80.0 이자바,1,4,70,90,70,230,76.7 홍길동,1,1,100,100,100,300,100.0 [ 해설] Collections.sort(List list) 를이용하면 ArrayList에저장된요소들을쉽게정렬할수있다. Collections.sort(list); // list 에저장된요소들을정렬한다.(compareTo() 호출) 그러나한가지조건이있다. ArrayList에저장된요소들은모두 Comparable인터페이스를 구현한것이어야한다는것이다. 이인터페이스에는 compareto 메서드가정의되어있는데, 이메서드는 Collections.sort(List list) 에의해호출되어정렬기준을제공하게된다. public interface Comparable { public int compareto(object o); // 주어진객체(o) 와자신의멤버변수를비교 compareto 메서드는매개변수로주어진객체(o) 를인스턴스자신과비교해서자신이작으면 음수를, 같으면 0 을, 크면양수를반환하도록구현되어야한다. 문제에서는학생의이름으로정렬될것을요구했으므로, 인스턴스변수 name만비교하도 록 compareto 메서드를구현하면된다. 문자열 name 을어떻게비교하도록구현해야할까? 고민되겠지만, String클래스에는이미문자열비교를위한 compareto메서드를구현해놓 았고우리는단지그것을활용하기만하면된다. public final class String implements java.io.serializable, Comparable<String>, CharSequence {... class Student implements Comparable {... public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return name.compareto(tmp.name) ; // String클래스의 compareto() 를호출 else { return -1;

Java의정석定石 349 참고로지네릭스(generics) 를적용한예제를추가한다. 어떤차이가있는지잘비교해보 자. 아직지네릭스를배우지않았으므로, 나중에지네릭스를배우고나서봐도좋다. [ 연습문제]/ch11/Exercise11_5_2.java import java.util.*; class Student implements Comparable<Student> { String name; int ban; int no; int kor, eng, math; Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; int gettotal() { return kor+eng+math; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage(); public int compareto(student s) { return name.compareto(s.name); class Exercise11_5_2 { public static void main(string[] args) { ArrayList<Student> list = new ArrayList<Student>(); list.add(new Student(" 홍길동",1,1,100,100,100)); list.add(new Student(" 남궁성",1,2,90,70,80)); list.add(new Student(" 김자바",1,3,80,80,90)); list.add(new Student(" 이자바",1,4,70,90,70)); list.add(new Student(" 안자바",1,5,60,100,80)); Collections.sort(list); Iterator it = list.iterator(); while(it.hasnext()) System.out.println(it.next());

350 Java의정석定石 [11-6] 다음의코드는성적평균의범위별로학생수를세기위한것이다. TreeSet이학 생들의평균을기준으로정렬하도록 주면해당범위에속한학생의수를반환하는 [Hint] TreeSet의 subset(object from, Object to) 를사용하라. compare(object o1, Object o2) 와평균점수의범위를 getgroupcount() 를완성하라. [ 연습문제]/ch11/Exercise11_6.java import java.util.*; class Student implements Comparable { String name; int ban; int no; int kor; int eng; int math; Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; int gettotal() { return kor+eng+math; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage() ; public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return name.compareto(tmp.name); else { return -1; // class Student

Java의정석定石 351 class Exercise11_6 { static int getgroupcount(treeset tset, int from, int to) { Student s1 = new Student("",0,0,from,from,from); Student s2 = new Student("",0,0,to,to,to); return tset.subset(s1,s2).size(); public static void main(string[] args) { TreeSet set = new TreeSet(new Comparator() { // 익명클래스 public int compare(object o1, Object o2) { if(o1 instanceof Student && o2 instanceof Student) { Student s1 = (Student)o1; Student s2 = (Student)o2; return (int)(s1.getaverage() - s2.getaverage()); ); return -1; set.add(new Student(" 홍길동",1,1,100,100,100)); set.add(new Student(" 남궁성",1,2,90,70,80)); set.add(new Student(" 김자바",1,3,80,80,90)); set.add(new Student(" 이자바",1,4,70,90,70)); set.add(new Student(" 안자바",1,5,60,100,80)); Iterator it = set.iterator(); while(it.hasnext()) System.out.println(it.next()); System.out.println("[60~69] :"+getgroupcount(set,60,70)); System.out.println("[70~79] :"+getgroupcount(set,70,80)); System.out.println("[80~89] :"+getgroupcount(set,80,90)); System.out.println("[90~100] :"+getgroupcount(set,90,101)); [ 실행결과] 이자바,1,4,70,90,70,230,76.7 남궁성,1,2,90,70,80,240,80.0 김자바,1,3,80,80,90,250,83.3 홍길동,1,1,100,100,100,300,100.0 [60~69] :0 [70~79] :1 [80~89] :2 [90~100] :1

352 Java의정석定石 [ 해설] 평균이지정된범위(from~to) 에속하는학생의수를세는메서드 getgroupcount를 작성하는문제이다. TreeSet 은정렬된상태로요소(element) 를저장하고, 검색과정렬특 히부분정렬에유리하다. TreeSet클래스의 subset() 은지정된범위에속하는요소들이포 함된 TreeSet 을반환한다. 단, 끝범위의경계값(to) 은결과에포함되지않는다.(from x < to) static int getgroupcount(treeset tset, int from, int to) { Student s1 = new Student("",0,0,from,from,from); Student s2 = new Student("",0,0,to,to,to); return tset.subset(s1,s2).size(); 왼쪽의코드는오른쪽의코드를한줄로간단히쓴것이다. 두코드를잘비교해보자. return tset.subset(s1,s2).size(); TreeSet tmp = tset.subset(s1,s2); return tmp.size(); // 크기를반환 compare(object o1, Object o2) 는주어진두객체를비교해서그결과를양수, 0, 음수 중의하나로반환한다. 그래서학생점수의평균을반환하는 getaverage() 로계산한다음 에 int 타입으로형변환해주었다. TreeSet set = new TreeSet(new Comparator() { // 익명클래스 public int compare(object o1, Object o2) { if(o1 instanceof Student && o2 instanceof Student) { Student s1 = (Student)o1; Student s2 = (Student)o2; return (int)(s1.getaverage() - s2.getaverage()); return -1; TreeSet 은요소(element) 를저장할때정렬해서저장하는데, 그정렬기준은어떤것일 까? 이미배운것과같이 Comparable 인터페이스를구현한클래스, 예를들면, Integer와 같은 wrapper클래스나 String 은정렬기준이내부에정의되어있다. 이처럼 Comparable인터페이스를구현해서내부적으로정렬기준을가지고있는클래스의 객체들은 TreeSet 에저장할때, 정렬기준을지정해주지않아도되지만, Comparable인터페 이스를구현하지않은클래스( 정렬기준이없는클래스) 는생성자 TreeSet(Comparator c) 를이용해서반드시정렬기준을제공해주어야한다. 정렬기준이내부에정의되어있어도다른기준으로정렬하고싶을때이생성자를사용 하면된다.

Java의정석定石 353 Student클래스는 Comparable 인터페이스를구현함으로써기본정렬기준을정의하였다. class Student implements Comparable { String name;... public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return name.compareto(tmp.name) ; // 이름을기준으로정렬( 오름차순) // return tmp.name.compareto(name); // 이름을기준으로정렬( 내림차순) else { return -1; // public int comareto(object o) 이와달리평균을기준으로오름차순정렬을하기위해서는다른정렬기준을제공해야한 다. 그래서 Comparator인터페이스를구현한클래스를작성하고이클래스의인스턴스를 생성자 TreeSet(Comparator c) 의매개변수로넘겨주었다. // 생성자 TreeSet(Comparator c) 를사용. TreeSet set = new TreeSet(new Comparator() { // 익명클래스 public int compare(object o1, Object o2) {... 매개변수를통해넘겨진정렬기준은 TreeSet의멤버변수로정의된 comparator에저장된 다. 그리고이 comparator는 TreeSet에요소를저장할때사용되는메서드 put() 에서저 장할위치를결정하기위해사용된다. [ 참고] 아래의코드는 TreeSet 의원본소스를이해하기쉽게재구성한것이므로원본과다르다. TreeSet set = new TreeSet(new Comparator(){... ); // Comparator 를제공받는다. class TreeSet { private Comparator comparator = null; // Comparator( 정렬기준) 가정의되어있다. TreeSet(Comparator c) { this.comparator = c; // 생성자를통해제공받은정렬기준을 comparator로설정 // TreeSet 에요소를저장하는데사용되는메서드. 저장할때정렬해서저장하므로 compare() 를호출 public Object put(object key, Object value) {... while(true) { int cmp = comparator.compare(key, t.key) ; // compare() 를호출한다.......

354 Java의정석定石 [11-7] 다음에제시된 BanNoAscending 클래스를완성하여, ArrayList에담긴 Student인 스턴스들이반(ban) 과번호(no) 로오름차순정렬되게하시오.( 반이같은경우번호를비 교해서정렬한다.) [ 연습문제]/ch11/Exercise11_7.java import java.util.*; class Student { String name; int ban; int no; int kor; int eng; int math; Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; int gettotal() { return kor+eng+math; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage() ; // class Student class BanNoAscending implements Comparator { public int compare(object o1, Object o2) { if(o1 instanceof Student && o2 instanceof Student) { Student s1 = (Student)o1; Student s2 = (Student)o2; int result = s1.ban - s2.ban; if(result==0) { // 반이같으면, 번호를비교한다. return s1.no - s2.no;

Java의정석定石 355 return result; return -1; class Exercise11_7 { public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(new Student(" 이자바",2,1,70,90,70)); list.add(new Student(" 안자바",2,2,60,100,80)); list.add(new Student(" 홍길동",1,3,100,100,100)); list.add(new Student(" 남궁성",1,1,90,70,80)); list.add(new Student(" 김자바",1,2,80,80,90)); Collections.sort(list, new BanNoAscending()); Iterator it = list.iterator(); while(it.hasnext()) System.out.println(it.next()); [ 실행결과] 남궁성,1,1,90,70,80,240,80.0 김자바,1,2,80,80,90,250,83.3 홍길동,1,3,100,100,100,300,100.0 이자바,2,1,70,90,70,230,76.7 안자바,2,2,60,100,80,240,80.0 [ 해설] 조금어렵다고느꼈을지도모르겠다. 그러나답은쉽다. 반(ban) 을뺄셈한결과가 0 이면( 반이같으면), 번호(no) 를뺄셈해서반환하기만하면된다. public int compare(object o1, Object o2) { if(o1 instanceof Student && o2 instanceof Student) { Student s1 = (Student)o1; Student s2 = (Student)o2; int result = s1.ban - s2.ban; if(result==0) { // 반이같으면, 번호를비교한다. return s1.no - s2.no; return result; return -1;

356 Java의정석定石 위의코드를삼항연산자를이용해서작성하면다음과같다. public int compare(object o1, Object o2) { if(o1 instanceof Student && o2 instanceof Student) { Student s1 = (Student)o1; Student s2 = (Student)o2; return s1.ban==s2.ban? s1.no - s2.no : s1.ban - s2.ban; return -1;

Java의정석定石 357 [11-8] 문제11-7의 Student 클래스에총점(total) 과전교등수(schoolRank) 를저장하기 위한인스턴스변수를추가하였다. Student 클래스의기본정렬을이름(name) 이아닌총점 (total) 을기준으로한내림차순으로변경한다음, 총점을기준으로각학생의전교등수 를계산하고전교등수를기준으로오름차순정렬하여출력하시오. [ 연습문제]/ch11/Exercise11_8.java import java.util.*; class Student implements Comparable { String name; int ban; int no; int kor; int eng; int math; int total; // 총점 int schoolrank; // 전교등수 Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; total = kor+eng+math; int gettotal() { return total; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return tmp.total - this.total; // 총점기준( 내림차순) 으로정렬한다. else { return -1; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math

358 Java의정석定石 +","+gettotal() +","+getaverage() +","+schoolrank // 새로추가 ; // class Student class Exercise11_8 { public static void calculateschoolrank(list list) { Collections.sort(list); // 먼저 list 를총점기준내림차순으로정렬한다. int prevrank = -1; // 이전전교등수 int prevtotal = -1; // 이전총점 int length = list.size(); // 1. 반복문을이용해서 list에저장된 Student 객체를하나씩읽는다. for(int i=0;i < length; i++) { Student s = (Student)list.get(i); // 1.1 총점(total) 이이전총점(prevTotal) 과같으면 // 이전등수(prevRank) 를등수(schoolRank) 로한다. if(s.total==prevtotal) { s.schoolrank = prevrank; else { // 1.2 총점이서로다르면, // 등수(schoolRank) 의값을알맞게계산해서저장한다. // 이전에동점자였다면, 그다음등수는동점자의수를고려해야한다. s.schoolrank = i + 1; // 1.3 현재총점과등수를이전총점(prevTotal) 과이전등수(prevRank) 에저장한다. prevrank = s.schoolrank; prevtotal = s.total; // for public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(new Student(" 이자바",2,1,70,90,70)); list.add(new Student(" 안자바",2,2,60,100,80)); list.add(new Student(" 홍길동",1,3,100,100,100)); list.add(new Student(" 남궁성",1,1,90,70,80)); list.add(new Student(" 김자바",1,2,80,80,90)); calculateschoolrank(list); Iterator it = list.iterator(); while(it.hasnext()) System.out.println(it.next()); [ 실행결과] 홍길동,1,3,100,100,100,300,100.0,1 김자바,1,2,80,80,90,250,83.3,2 안자바,2,2,60,100,80,240,80.0,3

Java의정석定石 359 남궁성,1,1,90,70,80,240,80.0,3 이자바,2,1,70,90,70,230,76.7,5 [ 해설] 등수를계산하기위해서는먼저총점기준의내림차순으로정렬되어있어야한다. 그리고바로전데이터와의비교를위해이전등수(prevRank), 이전총점(prevTotal) 을 저장하는변수를선언했다. public static void calculateschoolrank(list list) { Collections.sort(list); // 먼저 list 를총점기준내림차순으로정렬한다. int prevrank = -1; // 이전전교등수 int prevtotal = -1; // 이전총점 int length = list.size();... 반복문을이용해서 list 에저장된학생정보를하나씩가져와이전총점(prevTotal) 과비 교한다. 현재데이터의총점(s.total) 과이전총점(prevTotal) 이같으면, 등수(s.school Rank) 를이전등수(prevRank) 로저장한다. if(s.total==prevtotal) { // 총점이이전총점과같으면, s.schoolrank = prevrank; // 등수를이전등수와같은값으로한다. else { s.schoolrank = i + 1; 다음은실행과정에서변수값의변화를표로나타낸것이다. schoolrank가 i+1의값으로 저장되지만, s.total과 prevtotal의값이같을때는 i+1의값이아닌 prevrank의값으로 저장되는것을알수있다. s.total prevtotal prevrank schoolrank i+1 300-1 -1 1 1 250 300 1 2 2 240 250 2 3 3 240 240 3 3 4 230 240 3 5 5

360 Java의정석定石 [11-9] 문제11-8의 Student 클래스에반등수(classRank) 를저장하기위한인스턴스변수 를추가하였다. 반등수를계산하고반과반등수로오름차순정렬하여결과를출력하시오. (1)~(2) 에알맞은코드를넣어완성하시오. [ 연습문제]/ch11/Exercise11_9.java import java.util.*; class Student implements Comparable { String name; int ban; int no; int kor; int eng; int math; int total; int schoolrank; // 전교등수 int classrank; // 반등수 Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; total = kor+eng+math; int gettotal() { return total; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return tmp.total - this.total; else { return -1; public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math

Java의정석定石 361 +","+gettotal() +","+getaverage() +","+schoolrank +","+classrank // ; // class Student 새로추가 class ClassTotalComparator implements Comparator { public int compare(object o1, Object o2) { Student s1 = (Student)o1; Student s2 = (Student)o2; int result = s1.ban - s2.ban; // 반(ban) 기준정렬( 오름차순) if(result==0) result = s2.total - s1.total; // 총점(total) 기준정렬( 내림차순) return result; class Exercise11_9 { public static void calculateclassrank(list list) { // 먼저반별총점기준내림차순으로정렬한다. Collections.sort(list, new ClassTotalComparator()); int prevban = -1; int prevrank = -1; int prevtotal = -1; int length = list.size(); for(int i=0, n=0; i < length; i++, n++) { // 1. 반복문을이용해서 list에저장된 Student 객체를하나씩읽는다. Student s = (Student)list.get(i); // 1.1 반이달라지면,(ban와 prevban 이다르면) // 이전등수(prevRank) 와이전총점(prevTotal) 을초기화한다. if(s.ban!=prevban) { prevrank = -1; prevtotal = -1; n = 0; // 1.2 총점(total) 이이전총점(prevTotal) 과같으면 // 이전등수(prevRank) 를등수(classRank) 로한다. if(s.total==prevtotal) { s.classrank = prevrank; else { // 1.3 총점이서로다르면, // 등수(classRank) 의값을알맞게계산해서저장한다. // 이전에동점자였다면, 그다음등수는동점자의수를고려해야한다. s.classrank = n + 1; // 1.4 현재반과총점과등수를이전반(prevBan), // 이전총점(prevTotal), 이전등수(prevRank) 에저장한다.

362 Java의정석定石 prevban = s.ban; prevrank = s.classrank; prevtotal = s.total; // public static void calculateclassrank(list list) { public static void calculateschoolrank(list list) { Collections.sort(list); // 먼저 list 를총점기준내림차순으로정렬한다. int prevrank = -1; // 이전전교등수 int prevtotal = -1; // 이전총점 int length = list.size(); for(int i=0;i < length; i++) { Student s = (Student)list.get(i); if(s.total==prevtotal) { s.schoolrank = prevrank; else { s.schoolrank = i + 1; prevrank = s.schoolrank; prevtotal = s.total; // for public static void main(string[] args) { ArrayList list = new ArrayList(); list.add(new Student(" 이자바",2,1,70,90,70)); list.add(new Student(" 안자바",2,2,60,100,80)); list.add(new Student(" 홍길동",1,3,100,100,100)); list.add(new Student(" 남궁성",1,1,90,70,80)); list.add(new Student(" 김자바",1,2,80,80,90)); calculateschoolrank(list); calculateclassrank(list); Iterator it = list.iterator(); while(it.hasnext()) System.out.println(it.next()); [ 실행결과] 홍길동,1,3,100,100,100,300,100.0,1,1 김자바,1,2,80,80,90,250,83.3,2,2 남궁성,1,1,90,70,80,240,80.0,3,3 안자바,2,2,60,100,80,240,80.0,3,1 이자바,2,1,70,90,70,230,76.7,5,2 [ 해설] 문제11-8 을보다발전시킨예제이다. 문제11-8과달리반별오름차순과총점별내 림차순, 2 가지기준으로정렬한다음, 반이달라질때마다이전총점과이전등수, 그리 고등수(n) 를초기화해준다는것만다르다.

Java의정석定石 363 등수를계산하기위해서는먼저반별오름차순과총점별내림차순, 2가지기준으로정렬 한다. 그래서 ClassTotalComparator 는반을기준으로비교하고, 반이같으면총점을비교 해서정렬하도록정의하고, 반별총점을계산하는 calculateclassrank메서드내의 sort() 에 ClassTotalComparator 인스턴스를정렬기준으로제공한다. class ClassTotalComparator implements Comparator { public int compare(object o1, Object o2) { Student s1 = (Student)o1; Student s2 = (Student)o2; int result = s1.ban - s2.ban; // 반(ban) 기준정렬( 오름차순) if(result==0) // 반이같으면, 총점을비교한다. result = s2.total - s1.total; // 총점(total) 기준정렬( 내림차순) return result; // return {s1.ban==s2.ban? s1.ban-s2.ban : s2.total-s1.total; class Exercise11_9 { public static void calculateclassrank(list list) { // 먼저반별총점기준내림차순으로정렬한다. Collections.sort(list, new ClassTotalComparator()); 그다음에는문제11-8에서와같이반복문을이용해서정렬된데이터를한줄씩읽어서 등수를계산한다. 문제11-8 과다른점은, 반이달라지면다시 1등부터시작해서등수를 매겨야하므로이전총점(prevTotal), 이전등수(prevRank), 등수(n) 을초기화한다는것이 다. for(int i=0, n=0; i < length; i++, n++) { Student s = (Student)list.get(i); // 1.1 반이달라지면,(ban와 prevban 이다르면) // 이전등수(prevRank) 와이전총점(prevTotal) 을초기화한다. if(s.ban!=prevban) { prevrank = -1; prevtotal = -1; n = 0; if(s.total==prevtotal) { s.classrank = prevrank; else { s.classrank = n + 1; prevban = s.ban; prevrank = s.classrank; prevtotal = s.total;

364 Java의정석定石 다음은실행과정에서변수값의변화를표로나타낸것이다. 전과는달리등수를매길때 반복문의카운터 i대신 n 을사용하였으며, 현재반(s.ban) 과이전반(prevBan) 의값이다 르면, 이전총점(prevTotal), 이전등수(prevRank), 등수(n) 을초기화한다는것을확인하 자. s.total s.ban prevban prevtotal prevrank classrank i n n+1 300 1-1 -1-1 1 0 0 1 250 1 1 300 1 2 1 1 2 240 1 1 250 2 3 2 2 3 240 2 1-1 -1 1 3 0 1 230 2 2 240 1 2 4 1 2

Java의정석定石 365 [11-10] 다음예제의빙고판은 1~30 사이의숫자들로만든것인데, 숫자들의위치가잘 섞이지않는다는문제가있다. 이러한문제가발생하는이유와이문제를개선하기위한 방법을설명하고, 이를개선한새로운코드를작성하시오. [ 연습문제]/ch11/Exercise11_10.java import java.util.*; class Exercise11_10 { public static void main(string[] args) { Set set = new HashSet(); int[][] board = new int[5][5]; for(int i=0; set.size() < 25; i++) { set.add((int)(math.random()*30)+1+""); Iterator it = set.iterator(); for(int i=0; i < board.length; i++) { for(int j=0; j < board[i].length; j++) { board[i][j] = Integer.parseInt((String)it.next()); System.out.print((board[i][j] < 10? " " : " ") + board[i][j]); System.out.println(); // main [ 정답] HashSet은중복을허용하지않고순서를유지하지않기때문에발생하는문제이 다. 아무리임의의순서로저장을해도, 해싱(hashing) 알고리즘의특성상한숫자가고 정된위치에저장되기때문이다. 이문제를해결하기위해서는저장순서를유지하는 래스를사용하도록변경해야한다. [ 연습문제]/ch11/Exercise11_10_2.java import java.util.*; class Exercise11_10_2 { public static void main(string[] args) { Set set = new HashSet(); int[][] board = new int[5][5]; for(int i=0; set.size() < 25; i++) { set.add((int)(math.random()*30)+1+""); ArrayList list = new ArrayList(set); Collections.shuffle(list); List인터페이스를구현한컬렉션클

366 Java의정석定石 Iterator it = list.iterator(); for(int i=0; i < board.length; i++) { for(int j=0; j < board[i].length; j++) { board[i][j] = Integer.parseInt((String)it.next()); System.out.print((board[i][j] < 10? " " : " ") + board[i][j]); System.out.println(); // main [ 해설] 중복된값을허용하지않는다는특성을이용해서 HashSet에서로다른임의의값 을저장하는것까지는좋았는데, 해싱알고리즘의특성상같은값은같은자리에저장되기 때문에빙고판의숫자들이잘섞이지않는다는문제가발생하였다. Set set = new HashSet(); int[][] board = new int[5][5]; for(int i=0; set.size() < 25; i++) { set.add((int)(math.random()*30)+1+""); 그래서저장순서를유지하는 ArrayList에 HashSet 의데이터를옮겨담은다음, Collections.shuffle() 을이용해서저장된데이터들의순서를뒤섞었다. ArrayList list = new ArrayList(set); // set과같은데이터를가진 ArrayList를생성 Collections.shuffle(list); // list 에저장된데이터의순서를섞는다. Iterator it = list.iterator(); 이처럼대부분의컬렉션클래스들은다른컬렉션으로데이터를쉽게옮길수있게설계되 어있다. 매개변수의타입이 Collection인터페이스이므로 Collection인터페이스의자손인 List인터페이스와 다. Set인터페이스를구현한모든클래스의인스턴스가매개변수로가능하 ArrayList(Collection<? extends E> c) LinkedList(Collection<? extends E> c) Vector(Collection<? extends E> c) HashSet(Collection<? extends E> c) TreeSet(Collection<? extends E> c) LinkedHashSet(Collection<? extends E> c)

Java의정석定石 367 [11-11] 다음은 SutdaCard클래스를 HashSet 에저장하고출력하는예제이다. HashSet에 중복된카드가저장되지않도록 SutdaCard의 hashcode() 를알맞게오버라이딩하시오. [Hint] String클래스의 hashcode() 를사용하라. [ 연습문제]/ch11/Exercise11_11.java import java.util.*; class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public boolean equals(object obj) { if(obj instanceof SutdaCard) { SutdaCard c = (SutdaCard)obj; return num==c.num && iskwang==c.iskwang; else { return false; public String tostring() { return num + ( iskwang? "K":""); public int hashcode() { return tostring().hashcode(); // String클래스의 hashcode() 를호출한다. class Exercise11_11 { public static void main(string[] args) { SutdaCard c1 = new SutdaCard(3,true); SutdaCard c2 = new SutdaCard(3,true); SutdaCard c3 = new SutdaCard(1,true); HashSet set = new HashSet(); set.add(c1); set.add(c2); set.add(c3); System.out.println(set); 실행결과 [ ] [3K, 1K]

368 Java의정석定石 [ 해설] hashcode() 의기본구현은클래스이름과메모리주소와관련된정수값으로이루어 져있기때문에, 두객체의 hashcode() 값은절대로같을수가없다.( 서로다른두객체가 같은메모리번지에존재할수없기때문에 ) 대부분의경우서로다른객체라도클래스의인스턴스변수값이같으면, 예를들어 SutdaCar의경우 num과 iskwang 의값이같으면같은객체로인식해야한다. 즉, equals() 의결과가 true 이어야하고, 두객체의해시코드(hashCode() 를호출한결과) 가같아야한 다. 그래서 equals() 와 hashcode() 를적절히오버라이딩해줘야한다. 때로는 equals() 만오버라이딩해줘도되지만, 해시알고리즘을사용하는 HashSet에담을 때는반드시 hashcode() 도오버라이딩해줘야한다. 이문제의실행결과를보면중복을허용하지않는 HashSet 을사용하고도 [1K, 3K, 3K] 와 같은결과를얻는다. 그이유는 hashcode() 를오버라이딩하지않았기때문이다. 그러나 hashcode() 를오버라이딩한후에는 [3K, 1K] 와같이중복이제거된결과를얻을 수있다. hashcode() 를오버라이딩하라고하면어떻게해야할지막막할것이다. 그러나걱정하지 말자. 이미다구현되어있으니그냥가져다쓰기만하면된다. String클래스의 hashcode() 는객체의주소가아닌문자열의내용을기반으로해시코드를 생성하므로문자열의내용이같으면항상같은값의해시코드를반환한다. SutdaCard의 tostring() 이 num과 iskwang 의값으로문자열을만들어반환하기때문에, tostring() 을호출한결과에 hashcode() 를호출함으로써 SutdaCard의 hashcode() 를간단 히구현할수있었다. public String tostring() { return num + ( iskwang? "K":""); public int hashcode() { return tostring().hashcode(); // String클래스의 hashcode() 를호출한다. 인스턴스변수들의값을결합한문자열을만들고, 그문자열에대해 hashcode() 를호출하 는방법은쉬우면서도효과적이다.

Java의정석定石 369 [11-12] 다음은섯다게임에서카드의순위를결정하는등급목록( 족보) 이다. HashMap에 등급과점수를저장하는 registerjokbo() 와게임참가자의점수를계산해서반환하는 getpoint() 를완성하시오. [ 참고] 섯다게임은두장의카드의숫자를더한값을 10 으로나눈나머지가높은쪽이이기는게임이다. 그외에 도특정숫자로구성된카드로이루어진등급( 족보) 이있어서높은등급의카드가이긴다. 카드1 카드2 점수 K K 4000 10 10 3100 9 9 3090 8 8 3080 7 7 3070 6 6 3060 5 5 3050 4 4 3040 3 3 3030 2 2 3020 1 1 3010 - - - 카드1 카드2 점수 1 2 2060 2 1 2060 1 4 2050 4 1 2050 1 9 2040 9 1 2040 1 10 2030 10 1 2030 4 10 2020 10 4 2020 4 6 2010 6 4 2010 [ 연습문제]/ch11/Exercise11_12.java import java.util.*; class Exercise11_12 { public static void main(string args[]) throws Exception { SutdaDeck deck = new SutdaDeck(); deck.shuffle(); Player p1 = new Player(" 타짜", deck.pick(), deck.pick()); Player p2 = new Player(" 고수", deck.pick(), deck.pick()); System.out.println(p1+" "+deck.getpoint(p1)); System.out.println(p2+" "+deck.getpoint(p2)); class SutdaDeck { final int CARD_NUM = 20; SutdaCard[] cards = new SutdaCard[CARD_NUM]; int pos = 0; // 다음에가져올카드의위치 HashMap jokbo = new HashMap(); // 족보를저장할 HashMap SutdaDeck() { for(int i=0;i < cards.length;i++) { int num = i%10 + 1; boolean iskwang = i < 10 && (num==1 num==3 num==8); cards[i] = new SutdaCard(num,isKwang); registerjokbo(); // 족보를등록한다.

370 Java의정석定石 void registerjokbo() { jokbo.put("kk", 4000); jokbo.put("1010",3100); jokbo.put("99", 3090); jokbo.put("88", 3080); jokbo.put("77", 3070); jokbo.put("66", 3060); jokbo.put("55", 3050); jokbo.put("44", 3040); jokbo.put("33", 3030); jokbo.put("22", 3020); jokbo.put("11", 3010); jokbo.put("12", 2060); jokbo.put("21", 2060); jokbo.put("14", 2050); jokbo.put("41", 2050); jokbo.put("19", 2040); jokbo.put("91", 2040); jokbo.put("110", 2030); jokbo.put("101", 2030); jokbo.put("104", 2020); jokbo.put("410", 2020); jokbo.put("46", 2010); jokbo.put("64", 2010); int getpoint(player p) { if(p==null) return 0; SutdaCard c1 = p.c1; SutdaCard c2 = p.c2; Integer result = 0; // Integer result = new Integer(0); // 1. 카드두장이모두광이면, jokbo 에서키를 "KK" 로해서점수를조회한다. if(c1.iskwang && c2.iskwang) { result = (Integer)jokbo.get("KK"); else { // 2. 두카드의숫자(num) 로 jokbo 에서등급을조회한다. result = (Integer)jokbo.get(""+c1.num+c2.num); // 3. 해당하는등급이없으면, 아래의공식으로점수를계산한다. // (c1.num + c2.num) % 10 + 1000 if(result==null) { result = new Integer((c1.num + c2.num) % 10 + 1000); // 4. Player 의점수(point) 에계산한값을저장한다. p.point = result.intvalue(); return result.intvalue();

Java의정석定石 371 SutdaCard pick() throws Exception { SutdaCard c = null; if(0 <= pos && pos < CARD_NUM) { c = cards[pos]; cards[pos++] = null; else { throw new Exception(" 남아있는카드가없습니다."); return c; void shuffle() { for(int x=0; x < CARD_NUM * 2; x++) { int i = (int)(math.random() * CARD_NUM); int j = (int)(math.random() * CARD_NUM); SutdaCard tmp = cards[i]; cards[i] = cards[j]; cards[j] = tmp; // SutdaDeck class Player { String name; SutdaCard c1; SutdaCard c2; int point; // 카드의등급에따른점수 - 새로추가 Player(String name, SutdaCard c1, SutdaCard c2) { this.name = name ; this.c1 = c1 ; this.c2 = c2 ; public String tostring() { return "["+name+"]"+ c1.tostring() +","+ c2.tostring(); // class Player class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public String tostring() {

372 Java의정석定石 return num + ( iskwang? "K":""); [ 실행결과] [ 타짜]5,9 1004 [ 고수]1,1K 3010 [ 해설] registerjokbo() 는단순히 put() 을호출해서 HashMap에값을저장하는것이므로 설명하지않아도이해하는데어려움이없을것같다. 굳이설명한다면, put(object key, Object value) 에대한것인데, 이메서드의매개변수타입을보면 Object라서오른쪽의 코드와같이 wrapper 클래스를써야하는것이원칙이다. 그러나 jdk1.5 에서부터오토박싱기능이추가되어컴파일러가기본형(primitive type) 을 자동적으로 wrapper 클래스로변환해준다. 그래서왼쪽과같은코드가가능한것이다. 왼쪽과같이코드를작성해도컴파일러가오른쪽과같은코드로자동변환해주는것이 다. jokbo.put("kk", 4000); jokbo.put("kk", new Integer(4000); getpoint(player p) 는게임참가자(Player) 의카드를평가해서점수를반환하는메서드인 데, 게임참가자가가진카드의숫자를족보(jokbo) 에서찾아서해당점수를가져온다. 카드의숫자를문자열로만들어서 get(object key) 를호출하면, 족보에해당하는지알 수있다. get메서드의호출결과가 null 이면족보에없다는것을의미한다. 족보에없는 숫자조합이라면, 두숫자를더한다음 10으로나눈나머지에 1000을더해서점수를계산 한다. // 1. 카드두장이모두광이면, jokbo 에서키를 "KK" 로해서점수를조회한다. if(c1.iskwang && c2.iskwang) { result = (Integer)jokbo.get("KK"); else { // 2. 두카드의숫자(num) 로 jokbo 에서등급을조회한다. result = (Integer)jokbo.get(""+c1.num+c2.num); // 3. 해당하는등급이없으면, 아래의공식으로점수를계산한다. // (c1.num + c2.num) % 10 + 1000 if(result==null) { result = new Integer((c1.num + c2.num) % 10 + 1000); // 4. Player 의점수(point) 에계산한값을저장한다. p.point = result.intvalue(); // Integer를 int 로변환해서반환한다.

Java의정석定石 373 [11-13] 다음코드는문제11-12를발전시킨것으로각 Player 들의점수를계산하고, 점 수가제일높은사람을출력하는코드이다. TreeMap의정렬기준을점수가제일높은사람 부터내림차순이되도록아래의코드를완성하시오. 단, 동점자처리는하지않는다. [ 연습문제]/ch11/Exercise11_13.java import java.util.*; class Exercise11_13 { public static void main(string args[]) throws Exception { SutdaDeck deck = new SutdaDeck(); deck.shuffle(); Player[] parr = { new Player(" 타짜", deck.pick(), deck.pick()), new Player(" 고수", deck.pick(), deck.pick()), new Player(" 물주", deck.pick(), deck.pick()), new Player(" 중수", deck.pick(), deck.pick()), new Player(" 하수", deck.pick(), deck.pick()) ; TreeMap rank = new TreeMap(new Comparator(){ public int compare(object o1, Object o2) { if(o1 instanceof Player && o2 instanceof Player) { Player p1 = (Player)o1; Player p2 = (Player)o2; return p2.point - p1.point; // 점수기준의내림차순으로정렬 ); return -1; for(int i=0; i < parr.length;i++) { Player p = parr[i]; rank.put(p, deck.getpoint(p)); System.out.println(p+" "+deck.getpoint(p)); System.out.println(); System.out.println("1 위는 "+rank.firstkey()+" 입니다."); class SutdaDeck { final int CARD_NUM = 20; SutdaCard[] cards = new SutdaCard[CARD_NUM]; int pos = 0; // 다음에가져올카드의위치 HashMap jokbo = new HashMap(); // 족보를저장할 HashMap SutdaDeck() { for(int i=0;i < cards.length;i++) { int num = i%10 + 1; boolean iskwang = i < 10 && (num==1 num==3 num==8);

374 Java의정석定石 cards[i] = new SutdaCard(num,isKwang); registerjokbo(); // 족보를등록한다. void registerjokbo() { jokbo.put("kk", 4000); jokbo.put("1010",3100); jokbo.put("12", 2060); jokbo.put("99", 3090); jokbo.put("21", 2060); jokbo.put("88", 3080); jokbo.put("14", 2050); jokbo.put("77", 3070); jokbo.put("41", 2050); jokbo.put("66", 3060); jokbo.put("19", 2040); jokbo.put("55", 3050); jokbo.put("91", 2040); jokbo.put("44", 3040); jokbo.put("110", 2030); jokbo.put("33", 3030); jokbo.put("101", 2030); jokbo.put("22", 3020); jokbo.put("104", 2020); jokbo.put("11", 3010); jokbo.put("410", 2020); jokbo.put("46", 2010); jokbo.put("64", 2010); int getpoint(player p) { if(p==null) return 0; SutdaCard c1 = p.c1; SutdaCard c2 = p.c2; Integer result = 0; if(c1.iskwang && c2.iskwang) { result = (Integer)jokbo.get("KK"); else { result = (Integer)jokbo.get(""+c1.num+c2.num); if(result==null) { result = new Integer((c1.num + c2.num) % 10 + 1000); p.point = result.intvalue(); return result.intvalue(); SutdaCard pick() throws Exception { SutdaCard c = null; if(0 <= pos && pos < CARD_NUM) { c = cards[pos]; cards[pos++] = null; else { throw new Exception(" 남아있는카드가없습니다."); return c;

Java의정석定石 375 void shuffle() { for(int x=0; x < CARD_NUM * 2; x++) { int i = (int)(math.random() * CARD_NUM); int j = (int)(math.random() * CARD_NUM); SutdaCard tmp = cards[i]; cards[i] = cards[j]; cards[j] = tmp; // SutdaDeck class Player { String name; SutdaCard c1; SutdaCard c2; int point; Player(String name, SutdaCard c1, SutdaCard c2) { this.name = name ; this.c1 = c1 ; this.c2 = c2 ; public String tostring() { return "["+name+"]"+ c1.tostring() +","+ c2.tostring(); // class Player class SutdaCard { int num; boolean iskwang; SutdaCard() { this(1, true); SutdaCard(int num, boolean iskwang) { this.num = num; this.iskwang = iskwang; public String tostring() { return num + ( iskwang? "K":""); [ 실행결과] [ 타짜]7,2 1009 [ 고수]2,5 1007 [ 물주]1,7 1008 [ 중수]10,4 2020 [ 하수]9,6 1005 1 위는 [ 중수]10,4 입니다.

376 Java의정석定石 [11-14] 다음은성적처리프로그램의일부이다. Scanner클래스를이용해서화면으로부 터데이터를입력하고보여주는기능을완성하시오. [ 연습문제]/ch11/Exercise11_14.java import java.io.*; import java.util.*; class Exercise11_14 { static ArrayList record = new ArrayList(); // 성적데이터를저장할공간 static Scanner s = new Scanner(System.in); public static void main(string args[]) { while(true) { switch(displaymenu()) { case 1 : inputrecord(); break; case 2 : displayrecord(); break; case 3 : System.out.println(" 프로그램을종료합니다."); System.exit(0); // while(true) // menu를보여주는메서드 static int displaymenu(){ System.out.println("**************************************************"); System.out.println("* 성적관리프로그램 *"); System.out.println("**************************************************"); System.out.println(); System.out.println(" 1. 학생성적입력하기 "); System.out.println(); System.out.println(" 2. 학생성적보기"); System.out.println(); System.out.println(" 3. 프로그램종료 "); System.out.println(); System.out.print(" 원하는메뉴를선택하세요.(1~3) : "); int menu = 0; do { try { menu = Integer.parseInt(s.nextLine().trim()); if(1 <= menu && menu <= 3) { break; else { throw new Exception(); catch(exception e) { System.out.println(" 메뉴를잘못선택하셨습니다. 다시입력해주세요.");

Java의정석定石 377 System.out.print(" 원하는메뉴를선택하세요.(1~3) : "); while(true); return menu; // public static int displaymenu(){ // 데이터를입력받는메서드 static void inputrecord() { System.out.println("1. 학생성적입력하기"); System.out.println(" 이름, 반, 번호, 국어성적, 영어성적, 수학성적' 의순서로공백없이입력하세요."); System.out.println(" 입력을마치려면 q 를입력하세요. 메인화면으로돌아갑니다."); while(true) { System.out.print(">>"); try { String input = s.nextline().trim(); if(!input.equalsignorecase("q")) { // Scanner 를이용해서화면으로부터데이터를입력받는다.(',' 를구분자로) Scanner s2 = new Scanner(input).useDelimiter(","); // 입력받은값으로 Student인스턴스를생성하고 record 에추가한다. record.add(new Student(s2.next(), s2.nextint(), s2.nextint(), s2.nextint(), s2.nextint(), s2.nextint())); System.out.println(" 잘입력되었습니다. 입력을마치려면 q 를입력하세요."); else { // 입력받은값이 q 또는 Q 이면메서드를종료한다. return; catch(exception e) { // 입력받은데이터에서예외가발생하면, " 입력오류입니다." 를보여주고다시입력받는다. System.out.println(" 입력오류입니다. 이름, 반, 번호, 국어성적, 영어성적, 수학성적' 의순서로입력하세요."); // end of while // public static void inputrecord() { // 데이터목록을보여주는메서드 static void displayrecord() { int koreantotal = 0; int englishtotal = 0; int mathtotal = 0; int total = 0; int length = record.size(); if(length > 0) { System.out.println(); System.out.println(" 이름반번호국어영어수학총점평균전교등수반등수"); System.out.println("===================================================="); for (int i = 0; i < length ; i++) { Student student = (Student)record.get(i); System.out.println(student); koreantotal += student.kor;

378 Java의정석定石 mathtotal += student.math; englishtotal += student.eng; total += student.total; System.out.println("===================================================="); System.out.println(" 총점: "+koreantotal+" "+englishtotal +" "+mathtotal+" "+total); System.out.println(); else { System.out.println("===================================================="); System.out.println(" 데이터가없습니다."); System.out.println("===================================================="); // static void displayrecord() { class Student implements Comparable { String name; int ban; int no; int kor; int eng; int math; int total; int schoolrank; int classrank; // 반등수 Student(String name, int ban, int no, int kor, int eng, int math) { this.name = name; this.ban = ban; this.no = no; this.kor = kor; this.eng = eng; this.math = math; total = kor+eng+math; int gettotal() { return total; float getaverage() { return (int)((gettotal()/ 3f)*10+0.5)/10f; public int compareto(object o) { if(o instanceof Student) { Student tmp = (Student)o; return tmp.total - this.total; else { return -1;

Java의정석定石 379 public String tostring() { return name +","+ban +","+no +","+kor +","+eng +","+math +","+gettotal() +","+getaverage() +","+schoolrank +","+classrank ; // class Student [ 실행결과] ************************************************** * 성적관리프로그램 * ************************************************** 1. 학생성적입력하기 2. 학생성적보기 3. 프로그램종료 원하는메뉴를선택하세요.(1~3) : 5 메뉴를잘못선택하셨습니다. 다시입력해주세요. 원하는메뉴를선택하세요.(1~3) : 2 ==================================================== 데이터가없습니다. ==================================================== ************************************************** * 성적관리프로그램 * ************************************************** 1. 학생성적입력하기 2. 학생성적보기 3. 프로그램종료 원하는메뉴를선택하세요.(1~3) : 1 1. 학생성적입력하기이름, 반, 번호, 국어성적, 영어성적, 수학성적' 의순서로공백없이입력하세요. 입력을마치려면 q 를입력하세요. 메인화면으로돌아갑니다. >> 입력오류입니다. 이름, 반, 번호, 국어성적, 영어성적, 수학성적' 의순서로입력하세요. >> 자바짱,1,1,100,100,100 잘입력되었습니다. 입력을마치려면 q 를입력하세요. >> 김자바,1,2,80,80,80 잘입력되었습니다. 입력을마치려면 q 를입력하세요.

380 Java의정석定石 >>q ************************************************** * 성적관리프로그램 * ************************************************** 1. 학생성적입력하기 2. 학생성적보기 3. 프로그램종료 원하는메뉴를선택하세요.(1~3) : 2 이름반번호국어영어수학총점평균전교등수반등수 ==================================================== 자바짱,1,1,100,100,100,300,100.0,0,0 김자바,1,2,80,80,80,240,80.0,0,0 ==================================================== 총점 : 180 180 180 540 ************************************************** * 성적관리프로그램 * ************************************************** 1. 학생성적입력하기 2. 학생성적보기 3. 프로그램종료 원하는메뉴를선택하세요.(1~3) : 3 프로그램을종료합니다. [ 해설] 다음은사용자로부터메뉴를입력받아처리하는부분이다. Scanner의 nextline() 을이용해서라인단위로입력을받고, 공백을제거하기위해 trim() 을사용했다. do-while 문을사용해서사용자가유효한값(1~3 범위의값) 을입력할때까지반복해서입 력을받도록하였다. int menu = 0; do { try { menu = Integer.parseInt(s.nextLine().trim()); if(1 <= menu && menu <= 3) { break; // 유효한메뉴값을입력하면 do-while 문을빠져나간다. else { throw new Exception(); // 메뉴의범위를벗어나면예외를발생시킨다. catch(exception e) { System.out.println(" 메뉴를잘못선택하셨습니다. 다시입력해주세요."); System.out.print(" 원하는메뉴를선택하세요.(1~3) : "); while(true); return menu;

Java의정석定石 381 다음은성적을입력하는부분이다. Scanner 를이용해서라인단위로입력받은다음, Scanner 를한번더사용해서라인을 ',' 을구분자로다시나눈다. 그리고이값을이용 해서 Student인스턴스를생성해서성적데이터를저장하는공간인 record 에추가한다. 무 한반복문(while) 에둘러쌓여있기때문에, 'q' 나 'Q' 를입력할때까지반복해서성적을입 력할수있다. while(true) { System.out.print(">>"); try { String input = s.nextline().trim(); if(!input.equalsignorecase("q")) { // Scanner 를이용해서화면으로부터데이터를입력받는다.(',' 를구분자로) Scanner s2 = new Scanner(input).useDelimiter(","); // 입력받은값으로 Student인스턴스를생성하고 record 에추가한다. record.add(new Student(s2.next(), s2.nextint(), s2.nextint(), s2.nextint(), s2.nextint(), s2.nextint())); System.out.println(" 잘입력되었습니다. 입력을마치려면 q 를입력하세요."); else { // 입력받은값이 q 또는 Q 이면메서드를종료한다. return; catch(exception e) { // 입력받은데이터에서예외가발생하면, " 입력오류입니다." 를보여주고다시입력받는다. System.out.println(" 입력오류입니다. 이름, 반, 번호, 국어성적, 영어성적, 수학성적' 의순서로입력하세요."); // end of while

382 Java의정석定石 [ 연습문제 - 모범답안 ] [12-1] 클래스 Box 가다음과같이정의되어있을때, 다음중오류가발생하는문장은? 경고가발생하는문장은? class Box<T> { // 지네릭타입 T를선언 T item; void setitem(t item) { this.item = item; T getitem() { return item; a. Box<Object> b = new Box<String>(); b. Box<Object> b = (Object)new Box<String>(); c. new Box<String>().setItem(new Object()); d. new Box<String>().setItem("ABC"); [ 정답] a, b, c [ 해설] a. Box<Object> b = new Box<String>(); // 에러. 대입된타입이반드시같아야한다. b. Box<Object> b = (Object) new Box<String>(); // 에러. Object타입을 Box<Object> 타 입의참조변수에저장불가.( 타입불일치) c. new Box<String>().setItem(new Object() ); // 에러. 대입된타입이 String 이므로, setitem(t item) 의매개변수역시, String 타입만허용된다. d. new Box<String>().setItem("ABC" ); // OK. 대입된타입인 String과일치하는타입을 매개변수로지정했기때문에 OK.

Java의정석定石 383 [12-2] 지네릭메서드 makejuice() 가아래와같이정의되어있을때, 이메서드를올바 르게호출한문장을모두고르시오. (Apple과 Grape는 Fruit 의자손이라고가정하자.) class Juicer { static <T extends Fruit> String makejuice(fruitbox<t> box) { String tmp = ""; for(fruit f : box.getlist()) tmp += f + " "; return tmp; a. Juicer.<Apple>makeJuice(new FruitBox<Fruit>()); b. Juicer.<Fruit>makeJuice(new FruitBox<Grape>()); c. Juicer.<Fruit>makeJuice(new FruitBox<Fruit>()); d. Juicer.makeJuice(new FruitBox<Apple>()); e. Juicer.makeJuice(new FruitBox<Object>()); [ 정답] c, d [ 해설] a. Juicer.<Apple>makeJuice(new FruitBox<Fruit>()); // 에러. 지네릭메서드에대입된 타입이 Apple 이므로, 이메서드의매개변수는 'FruitBox<Apple>' 타입이된다. new FruitBox<Fruit>() 는매개변수의타입과일치하지않으며, 자동형변환도불가능한타입이 므로에러이다. b. Juicer.<Fruit>makeJuice(new FruitBox<Grape>()); // 에러. Grape가 Fruit의자손이 라고해도, 타입이다르기때문에같은이유로에러. c. Juicer.<Fruit>makeJuice(new FruitBox<Fruit>()); // OK. d. Juicer.makeJuice(new FruitBox<Apple>()); // OK. 지네릭메서드의타입호출이생 략된형태. 생략하지않았다면, Juicer.<Apple>makeJuice(new FruitBox<Apple>());' 과 같다. 대부분의경우이처럼생략한다. e. Juicer.makeJuice(new FruitBox<Object>()); // 에러. 지네릭메서드의타입호출이 생략되지않았다면, Juicer.<Object>makeJuice(new FruitBox<Object>());' 과같다. d 번의경우와같이타입이일치하긴하지만, <T extends Fruit> 로제한이걸려있으므로, 타 입 T는 Fruit 의자손이어야한다. Object는 Fruit 의자손이아니므로에러.

384 Java의정석定石 [12-3] 다음중올바르지않은문장을모두고르시오. class Box<T extends Fruit> { // 지네릭타입 T를선언 T item; void setitem(t item) { this.item = item; T getitem() { return item; a. Box<?> b = new Box(); b. Box<?> b = new Box<>(); c. Box<?> b = new Box<Object>(); d. Box<Object> b = new Box<Fruit>(); e. Box b = new Box<Fruit>(); f. Box<? extends Fruit> b = new Box<Apple>(); g. Box<? extends Object> b = new Box<? extends Fruit>(); [ 정답] c, d, g [ 해설] a. Box<?> b = new Box(); // OK. Box<?> 는 Box<? extends Object> 를줄여쓴것이다. 객 체생성에지네릭타입을지정해주지않았지만문제가되지는않는다. 그래도, new Box() 대신 new Box<>() 를사용하는것이좋다. b. Box<?> b = new Box<>(); // OK. new Box<>(); 는타입을생략한것으로, 일반적으로는 참조변수의타입과같은타입으로간주된다. 참조변수의타입이 <?>, 즉 <? extends Object> 이므로생략된타입은 Object 이라고생각하기쉬운데, 여기서는지네릭클래스 Box 에정의된타입이 <T extends Fruit> 와같이제한되어있기때문에, 'Object' 가아니 라 Fruit' 이생략된것으로봐야한다. 그래서 Box<?> b = new Box<Object>(); 와같이 하면에러가발생한다. Object는 Fruit 의자손이아니기때문이다. Box<?> b = new Box<>(); // OK. Box<?> b = new Box<Fruit>(); 와동일 Box<?> b = new Box<Object>(); // 에러 Box<?> b = new Box<Fruit>(); // OK Box<? extends Object> 는 Box<Object> 와같지않음에주의하자. 지네릭클래스 Box는 타입 T가 Fruit 의자손으로제한되어있기때문에, Box<Object> 와같이 Fruit의자손이 아닌클래스를대입할수없다. 그러나, 'Box<? extneds Object>' 와같이와일드카드를 사용하는것은가능하다. c. Box<?> b = new Box<Object>(); // 에러 b의설명참조 d. Box<Object> b = new Box<Fruit>(); // 에러. 타입불일치 e. Box b = new Box<Fruit>(); // OK. 바람직하지않음. Box<?> b 가더나음. f. Box<? extends Fruit> b = new Box<Apple>(); // OK. g. Box<? extends Object> b = new Box<? extends Fruit>(); // 에러. new연산자는타입 이명확해야하므로와일드카드와같이사용불가

Java의정석定石 385 [12-4] 아래의메서드는두개의 ArrayList 를매개변수로받아서, 하나의새로운 ArrayList 로병합하는메서드이다. 이를지네릭메서드로변경하시오. public static ArrayList<? extends Product> merge( ArrayList<? extends Product> list, ArrayList<? extends Product> list2) { ArrayList<? extends Product> newlist = new ArrayList<>(list); newlist.addall(list2); return newlist; [ 정답] public static <T extends Product> ArrayList<T> merge( ArrayList<T> list, ArrayList<T> list2) { ArrayList<T> newlist = new ArrayList<>(list); newlist.addall(list2); return newlist;

386 Java의정석定石 [12-5] 아래는예제7-3에열거형 Kind와 Number 를새로정의하여적용한것이다. (1) 에 알맞은코드를넣어예제를완성하시오. (Math.random() 을사용했으므로실행결과가달라 질수있다.) [ 연습문제]/ch12/Exercise12_5.java class Exercise12_5 { public static void main(string args[]) { Deck d = new Deck(); // 카드한벌(Deck) 을만든다. Card c = d.pick(0); // 섞기전에제일위의카드를뽑는다. System.out.println(c); // System.out.println(c.toString()); 과같다. d.shuffle(); // 카드를섞는다. c = d.pick(0); // 섞은후에제일위의카드를뽑는다. System.out.println(c); class Deck { final int CARD_NUM = Card.Kind.values().length * Card.Number.values().length; // 카드의개수 Card cardarr[] = new Card[CARD_NUM]; // Card객체배열을포함 Deck () { int i=0; for(card.kind kind : Card.Kind.values()) { for(card.number num : Card.Number.values()) { cardarr[i++] = new Card(kind, num); Card pick(int index) { // 지정된위치(index) 에있는카드하나를꺼내서반환 return cardarr[index]; Card pick() { // Deck 에서카드하나를선택한다. int index = (int)(math.random() * CARD_NUM); return pick(index); void shuffle() { // 카드의순서를섞는다. for(int i=0; i < cardarr.length; i++) { int r = (int)(math.random() * CARD_NUM); Card temp = cardarr[i]; cardarr[i] = cardarr[r]; cardarr[r] = temp; // Deck클래스의끝 // Card 클래스 class Card { enum Kind { CLOVER, HEART, DIAMOND, SPADE

Java의정석定石 387 enum Number { ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING Kind kind; Number num; Card() { this(kind.spade, Number.ACE); Card(Kind kind, Number num) { this.kind = kind; this.num = num; public String tostring() { return "[" + kind.name() + "," + num.name() + "]"; // tostring() 의끝 // Card 클래스의끝 실행결과 [ ] [CLOVER,ACE] [HEART,TEN] [ 정답] int i=0; for(card.kind kind : Card.Kind.values()) { for(card.number num : Card.Number.values()) { cardarr[i++] = new Card(kind, num);

388 Java의정석定石 [12-6] 다음중메타애너테이션이아닌것을모두고르시오. a. Documented b. Target c. Native d. Inherited [ 정답] c 애너테이션 설명 @Override 컴파일러에게오버라이딩하는메서드라는것을알린다. @Deprecated 앞으로사용하지않을것을권장하는대상에붙인다. @SuppressWarnings 컴파일러의특정경고메시지가나타나지않게해준다. @SafeVarargs 지네릭스타입의가변인자에사용한다.(JDK1.7) @FunctionalInterface 함수형인터페이스라는것을알린다.(JDK1.8) @Native native 메서드에서참조되는상수앞에붙인다.(JDK1.8) @Target * 애너테이션이적용가능한대상을지정하는데사용한다. @Documented * 애너테이션정보가 javadoc 으로작성된문서에포함되게한다. @Inherited * 애너테이션이자손클래스에상속되도록한다. @Retention * 애너테이션이유지되는범위를지정하는데사용한다. @Repeatable * 애너테이션을반복해서적용할수있게한다.(JDK1.8) [ 표12-2] 자바에서기본적으로제공하는표준애너테이션 ( * 가붙은것은메타애너테이션 )

Java의정석定石 389 [12-7] 애너테이션 TestInfo 가다음과같이정의되어있을대, 이애너테이션이올바르 게적용되지않은것은? @interface TestInfo { int count() default 1; String[] value() default "aaa"; a. @TestInfo class Exercise12_7 { b. @TestInfo(1) class Exercise12_7 { c. @TestInfo("bbb") class Exercise12_7 { d. @TestInfo("bbb","ccc") class Exercise12_7 { [ 정답] b, d [ 해설] a. @TestInfo class Exercise12_7 { default 값이지정되어있는요소는애너테이션을적용할때값을생략할수있다. b. @TestInfo(1) class Exercise12_7 { 요소의이름이 value 가아닌경우에는요소의이름을생략할수없다. @TestInfo(count=1) 이라고써야맞음. c. @TestInfo("bbb") class Exercise12_7 { @TestInfo(count=1, value={"bbb") 의생략된형태 d. @TestInfo("bbb","ccc") class Exercise12_7 { 요소의타입이배열이고, 지정하려는값이여러개인경우괄호{ 가필요함. @TestInfo({"bbb", "ccc") 또는 @TestInfo(value={"bbb","ccc") 와같이써야함

390 Java의정석定石 [ 연습문제 - 모범답안 ] [13-1] 쓰레드를구현하는방법에는 Thread클래스로부터상속받는것과 Runnable인터페 이스를구현하는것두가지가있는데, 다음의코드는 Thread클래스를상속받아서쓰레드 를구현한것이다. 이코드를 Runnable 인터페이스를구현하도록변경하시오. [ 연습문제]/ch13/Exercise13_1.java class Exercise13_1 { public static void main(string args[]) { Thread1 th1 = new Thread1(); th1.start(); class Thread1 extends Thread { public void run() { for(int i=0; i < 300; i++) { System.out.print('-'); [ 정답] [ 연습문제]/ch13/Exercise13_1_2.java class Exercise13_1_2 { public static void main(string args[]) { Thread th1 = new Thread(new Thread1()); th1.start(); class Thread1 implements Runnable { public void run() { for(int i=0; i < 300; i++) { System.out.print('-');

Java의정석定石 391 [13-2] 다음코드의실행결과로옳은것은? [ 연습문제]/ch13/Exercise13_2.java class Exercise13_2 { public static void main(string[] args) { Thread2 t1 = new Thread2(); t1.run(); for(int i=0; i < 10; i++) System.out.print(i); class Thread2 extends Thread { public void run() { for(int i=0; i < 10; i++) System.out.print(i); a. 01021233454567689789처럼 0부터 9 까지의숫자가섞여서출력된다. b. 01234567890123456789처럼 0부터 9 까지의숫자가순서대로출력된다. c. IllegalThreadStateException 이발생한다. [ 정답] b [ 해설] Thread2 클래스의인스턴스를생성하긴했지만, start() 가아닌 run() 을호출함으 로써쓰레드를실행시킨것이아니라단순히 Thread2클래스의메서드를호출한셈이되었 다. 만일 run() 이아닌 start() 를호출하였다면, 숫자가섞여서출력되었을것이다.

392 Java의정석定石 [13-3] 다음중쓰레드를일시정지상태(WAITING) 로만드는것이아닌것은? ( 모두고르 시오 ) a. suspend() b. resume() c. join() d. sleep() e. wait() f. notify() [ 정답] b, f [ 해설] resume() 은 suspend() 의호출로인해일시정지상태가된쓰레드를실행대기상태 로바꿔준다. notify() 역시 wait() 의호출로인해일시정지상태가된쓰레드를다시실 행대기상태로바꿔준다. join() 은현재실행중인쓰레드를멈추고다른쓰레드가실행 되도록한다.

Java의정석定石 393 [13-4] 다음중 interrupt() 에의해서실행대기상태(RUNNABLE) 가되지않는경우는? ( 모두고르시오) a. sleep() 에의해서일시정지상태인쓰레드 b. join() 에의해서일시정지상태인쓰레드 c. wait() 에의해서일시정지상태인쓰레드 d. suspend() 에의해서일시정지상태인쓰레드 [ 정답] d [ 해설] suspend() 를제외한나머지메서드들은 interrupt() 가호출되면 InterruptedExcep tion 이발생하여일시정지상태에서벗어나실행대기상태가된다.(try-catch문으로 InterruptedException 을처리해주어야한다.)

394 Java의정석定石 [13-5] 다음의코드를실행한결과를예측하고, 직접실행한결과와비교하라. 만일예 측한결과와실행한결과의차이가있다면그이유를설명하라. [ 연습문제]/ch13/Exercise13_5.java class Exercise13_5 { public static void main(string[] args) throws Exception { Thread3 th1 = new Thread3(); th1.start(); try { Thread.sleep(5*1000); // main쓰레드를 5 초간정지시킨다. catch(exception e) { throw new Exception(" 꽝~!!!"); class Thread3 extends Thread { public void run() { for(int i=0; i < 10; i++) { System.out.println(i); try { Thread.sleep(1000); catch(exception e) { // run() [ 정답] [ 실행결과] 0 1 2 3 4 5 Exception in thread "main" java.lang.exception: 꽝~!!! at Exercise13_5.main(Exercise13_5.java:12) 6 7 8 9 [ 해설] main과 th1 두개의쓰레드는별도의호출스택(call stack) 에서실행된다. 그래서 main 에서예외가발생하여종료되고호출스택이없어져도, 쓰레드 th1이실행되는호출스 택에는아무런영향을미치지못한다.

Java의정석定石 395 예외가발생하기전 예외가발생한후 main run run

396 Java의정석定石 [13-6] 다음의코드를실행한결과를예측하고, 직접실행한결과와비교하라. 만일예 측한결과와실행한결과의차이가있다면그이유를설명하라. [ 연습문제]/ch13/Exercise13_6.java class Exercise13_6 { public static void main(string[] args) throws Exception { Thread4 th1 = new Thread4(); th1.setdaemon(true); // 쓰레드 th1 을데몬쓰레드로설정한다. th1.start(); try { th1.sleep(5*1000); catch(exception e) { throw new Exception(" 꽝~!!!"); class Thread4 extends Thread { public void run() { for(int i=0; i < 10; i++) { System.out.println(i); try { Thread.sleep(1000); catch(exception e) { // run() [ 정답] [ 실행결과] 0 1 2 3 4 5Exception in thread "main" java.lang.exception: 꽝~!!! at Exercise13_6.main(Exercise13_6.java:13) [ 해설] 문제13-6 에 'th1.setdaemon(true);' 한문장을추가해서쓰레드 th1을데몬쓰레 드로(daemon thread) 설정하였다. 데몬쓰레드는일반쓰레드( 데몬쓰레드가아닌쓰레 드) 가모두종료되면자동종료되므로, main 쓰레드( 일반쓰레드) 가종료됨과동시에자동 종료된다. 그래서문제13-6과는달리쓰레드th1이 main메서드의종료와동시에종료되었 다.

Java의정석定石 397 [13-7] 다음의코드는쓰레드 th1을생성해서실행시킨다음 6초후에정지시키는코드 이다. 그러나실제로실행시켜보면쓰레드를정지시킨다음에도몇초가지난후에서야 멈춘다. 그이유를설명하고, 쓰레드를정지시키면바로정지되도록코드를개선하시오. [ 연습문제]/ch13/Exercise13_7.java class Exercise13_7 { static boolean stopped = false; public static void main(string[] args) { Thread5 th1 = new Thread5(); th1.start(); try { Thread.sleep(6*1000); catch(exception e) { stopped = true; // 쓰레드를정지시킨다. th1.interrupt(); // 일시정지상태에있는쓰레드를깨운다. System.out.println("stopped"); class Thread5 extends Thread { public void run() { // Exercise13_7.stopped의값이 false 인동안반복한다. for(int i=0;!exercise13_7.stopped; i++) { System.out.println(i); try { Thread.sleep(3*1000); catch(exception e) { // run() 실행결과 [ ] 0 1 2 stopped [ 정답] Exercise13_7.stopped의값이바뀌어도 for문내의 Thread.sleep(3*1000); 문장에 의해일시정지상태에있는경우, 시간이지나서일시정지상태를벗어날때까지 for문을 벗어날수없기때문에이런현상이발생한다. 그래서 interrupt() 를호출해서자고있는 (sleep() 에의해일시정지상태에있는) 쓰레드를깨워야즉시정지하게된다. [ 해설] 쓰레드 th1은아래의반복문을수행하다가 main메서드에서 Exercise13_7.stopped 의값을 true 로바꾸면반복문을빠져나와수행을종료하게된다. 반복문안에쓰레드를 3 초동안일시정지상태로하는 Thread.sleep(3*1000) 이있기때문에 Exercise13_7.

398 Java의정석定石 stopped 의값이바뀌었다하더라도일시정지상태에있다면, 반복문을빠져나오게된다. 일시정지상태가끝나야만 public void run() { // Exercise13_7.stopped의값이 false 인동안반복한다. for(int i=0;!exercise13_7.stopped; i++) { System.out.println(i); // run() try { Thread.sleep(3*1000); // 3 초간쉰다. catch(exception e) { 그래서쓰레드의실행을바로종료시키려면 Exercise13_7.stopped의값을 true로바꾸는 것만으로는부족하다. 그외에다른방법이더필요하다. 그것은바로 interrupt() 를호 출하는것이다. stopped = true; // 쓰레드를정지시킨다. stopped = true; // 쓰레드를정지시킨다. th1.interrupt(); // 쓰레드를깨운다. interrupt() 는 InterruptedException을발생시킴으로써 Thread.sleep() 에의해일시정지 상태에있던쓰레드를즉시깨운다. 그래서 Exercise13_7.stopped의값을 true 로바꾸고, interrupt() 를호출하면지연없이 즉시쓰레드를멈추게할수있다.

Java의정석定石 399 [13-8] 다음의코드는텍스트기반의타자연습게임인데 WordGenerator라는쓰레드가 Vector에 2 초마다단어를하나씩추가하고, 사용자가단어를입력하면 Vector에서일치하 는단어를삭제하도록되어있다. WordGenerator의 run() 을완성하시오. [ 연습문제]/ch13/Exercise13_8.java import java.util.*; class Exercise13_8 { Vector words = new Vector(); String[] data = {" 태연"," 유리"," 윤아"," 효연"," 수영"," 서현"," 티파니"," 써니"," 제시카"; int interval = 2 * 1000; // 2 초 WordGenerator wg = new WordGenerator(); public static void main(string args[]) { Exercise13_8 game = new Exercise13_8(); game.wg.start(); // 단어를생성하는쓰레드를실행시킨다. Vector words = game.words; while(true) { System.out.println(words); String prompt = ">>"; System.out.print(prompt); // 화면으로부터라인단위로입력받는다. Scanner s = new Scanner(System.in); String input = s.nextline().trim(); int index = words.indexof(input); // 입력받은단어를 words 에서찾는다. if(index!=-1) { // 찾으면 words.remove(index); // words 에서해당단어를제거한다. // main class WordGenerator extends Thread { public void run() { while(true) { // 초마다배열의값중하나를임의로선택해서 1. interval(2 ) data int rand = (int)(math.random()*data.length); // 2. words 에저장한다. words.add(data[rand]); try { Thread.sleep(interval); // 2 초(interval) 동안쉰다. catch(exception e) {

400 Java의정석定石 // end of run() // class WordGenerator // Exercise13_8 [ 실행결과] [] >> [ 서현] >> 서현 [ 수영, 윤아] >> 수영 [ 윤아, 유리] >> 유리 [ 윤아, 티파니] >> 티파니 [ 윤아, 윤아, 유리] >> 윤아 [ 윤아, 유리] >> 유리 [ 윤아, 효연] >> 효연 [ 윤아, 티파니] >> 윤아 [ 티파니, 윤아] >> 티파니 [ 윤아, 수영, 써니] >> [ 해설] 쉬운문제라서별로설명할것이없다. 쓰레드가그렇게어려운것만은아니라고 느낄수있으면좋겠다. 이예제를발전시켜서 GUI를갖춘타자게임을만들어보면재미 있을것이다.( 카페의 'java1000 제' 게시판에개발단계별로공개되어있음) 혹시라도질문이있으면 http://cafe.naver.com/javachobostudy.cafe 의게시판에올려 주길바란다.

Java의정석定石 401 [13-9] 다음은사용자의입력을출력하고종료하는프로그램을작성한것으로, 10초동 안입력이없으면자동종료되어야한다. 그러나실행결과를보면, 사용자의입력이 10초 안에이루어졌음에도불구하고프로그램이즉시종료되지않는다. 사용자로부터입력받는 즉시프로그램이종료되도록수정하시오. [ 연습문제]/ch13/Exercise13_9.java import javax.swing.joptionpane; class Exercise13_9 { public static void main(string[] args) throws Exception { Exercise13_9_1 th1 = new Exercise13_9_1(); th1.start(); String input = JOptionPane.showInputDialog(" 아무값이나입력하세요."); System.out.println(" 입력하신값은 " + input + " 입니다."); th1.interrupt(); // 쓰레드에게작업을멈추라고요청한다. class Exercise13_9_1 extends Thread { public void run() { int i = 10; while(i!=0 &&!isinterrupted()) { System.out.println(i--); try { Thread.sleep(1000); // 1 초지연 catch(interruptedexception e) { interrupt(); System.out.println(" 카운트가종료되었습니다."); // main [ 실행결과] 10 9 8 입력하신값은 abcd 입니다. 카운트가종료되었습니다. [ 해설] sleep() 에의해쓰레드가잠시멈춰있을때, interrupt() 를호출하면 InterruptedException 이발생되고쓰레드의 interrupted상태는 false 로자동초기화된다.

402 Java의정석定石 try { Thread.sleep(1000); // 1 초지연 catch(interruptedexception e) { try { Thread.sleep(1000); // 1초지연 catch(interruptedexception e) { interrupt(); // 추가 그래서, 위와같이 catch블럭에 interrupt() 를추가로넣어줘서쓰레드의 interrupted상태를 true 로다시바꿔줘야한다. 보다자세한내용은 p.754 를참고하자.

Java의정석定石 403 [ 연습문제 - 모범답안 ] [14-1] 메서드를람다식으로변환하여아래의표를완성하시오. 메서드 int max(int a, int b) { return a > b? a : b; int printvar(string name, int i) { System.out.println(name+"="+i ); int square(int x) { return x * x; int roll() { return (int)(math.random() * 6); int sumarr(int[] arr) { int sum = 0; for(int i : arr) sum += i; return sum; int[] emptyarr() { return new int[]{; 람다식 (int a, int b) -> a > b? a : b (String name, int i) -> { System.out.println(name+"="+i); (name, i) -> { System.out.println(name+"="+i); (name, i) -> System.out.println(name+"="+i) (int x) -> x * x (x) x -> x * x -> x * x () -> { return (int)(math.random()*6); () -> (int)(math.random() * 6) (int[] arr) -> { int sum = 0; for(int i : arr) sum += i; return sum; () -> new int[]{

404 Java의정석定石 [14-2] 람다식을메서드참조로변환하여표를완성하시오. ( 변환이불가능한경우, 변환불가 라고적어야함.) 람다식 메서드참조 (String s) -> s.length() String::length ()-> new int[]{ int[]::new arr -> Arrays.stream(arr) Arrays::stream (String str1, String str2) -> str1.equals(str2) String::equals (a, b) -> Integer.compare(a, b) Integer::compare (String kind, int num) -> new Card(kind, num) Card::new (x) -> System.out.println(x) System.out::println ()-> Math.random() Math::random (str) -> str.touppercase() String::toUpperCase () -> new NullPointerException() NullPointerException::new (Optional opt) -> opt.get() Optional::get (StringBuffer sb, String s) -> sb.append(s) StringBuffer::append (String s) -> System.out.println(s) System.out::println

Java의정석定石 405 [14-3] 아래의괄호안에알맞은함수형인터페이스는? ( ) f; // 함수형인터페이스타입의참조변수 f 를선언. f = (int a, int b) -> a > b? a : b; a. Function b. BiFunction c. Predicate d. IntBinaryOperator e. IntFunction [ 정답] d [ 해설] 참조하려는람다식의매개변수가 int 타입두개이고, 반환값의타입역시 int 이므로, 하나 의매개변수만정의되어있는 Function, Predicate, IntFunction 은적합하지않다. BiFunction 은두개의매개변수를갖지만, int와같은기본형은사용할수없기때문에 IntBinaryOperator 를사용해야한다. package java.util.function; @FunctionalInterface public interface IntBinaryOperator { int applyasint(int left, int right); 만일매개변수의타입을생략했다면, BinaryOperator<Integer> 로다룰수도있다. 아래의 두문장은동일하다. BinaryOperator<Integer> f = (a, b) -> a > b? a : b; BinaryOperator<Integer> f = (Integer a, Integer b) -> a > b? a : b;

406 Java의정석定石 [14-4] 문자열배열 strarr 의모든문자열의길이를더한결과를출력하시오. String[] strarr = { "aaa","bb","c", "dddd" ; [ 실행결과] sum=10 [ 정답] [ 연습문제]/ch14/Exercise14_4.java import java.util.stream.*; class Exercise14_4 { public static void main(string[] args) { String[] strarr = { "aaa","bb","c", "dddd" ; Stream<String> strstream = Stream.of(strArr); // int sum = strstream.maptoint(s-> s.length()).sum(); int sum = strstream.maptoint(string::length).sum(); System.out.println("sum="+sum); [ 해설] 아래와같이 map() 을이용해서 Stream<String> 을 Stream<Integer> 으로변환한다음에 스트림의각요소를더해도되지만, Stream<Integer> integerstream = strstream.map(s -> s.length()); Integer sum = integerstream.reduce(0, (a, b)-> Integer.sum(a, b)); 이럴때는 maptoint() 를사용해서 Stream<String> 을 IntStream 으로변환하는것이좋다. IntStream에는 문이다. sum(), average(), max(), min() 과같이편리한메서드를가지고있기때 IntStream intstream = strstream.maptoint(string::length); int sum = intstream.sum(); 위의두문장을줄이면, 다음과같이더간단해진다. int sum = strstream.maptoint(string::length).sum();

Java의정석定石 407 [14-5] 문자열배열 strarr 의문자열중에서가장긴것의길이를출력하시오. String[] strarr = { "aaa","bb","c", "dddd" ; [ 실행결과] 4 [ 정답] [ 연습문제]/ch14/Exercise14_5.java import java.util.*; import java.util.stream.*; class Exercise14_5 { public static void main(string[] args) { String[] strarr = { "aaa","bb","c", "dddd" ; Stream<String> strstream = Stream.of(strArr); strstream.map(string::length) // strstream.map(s-> s.length()).sorted(comparator.reverseorder()) // 문자열길이로역순정렬.limit(1).forEach(System.out::println); // 제일긴문자열의길이출력 [ 해설] 문제14-5 와유사하지만, sorted() 를사용해서정렬을해야한다. 간단한문제이므로설명 은생략한다. 참고로가장긴문자열자체를출력하려면다음과같이하면된다. String[] strarr = { "aaa","bb","c", "dddd" ; Stream.of(strArr).sorted(Comparator.comparingInt(String::length).reversed()).limit(1).forEach(System.out::println); // dddd 가출력된다.

408 Java의정석定石 [14-6] 임의의로또번호(1~45) 를정렬해서출력하시오. [ 실행결과] 1 20 25 33 35 42 [ 정답] [ 연습문제]/ch14/Exercise14_6.java import java.util.*; import java.util.stream.*; class Exercise14_6 { public static void main(string[] args) { new Random().ints(1,46) // 1~45 사이의정수(46 은포함안됨).distinct() // 중복제거.limit(6) // 6개만.sorted() // 정렬.forEach(System.out::println); // 화면에출력 [ 해설] Random클래스의 ints() 는지정된범위내의임의의정수를요소로하는무한스트림을 반환한다. 무한스트림이므로 limit() 이필요하다. sorted() 로정렬한다음, foreach() 로화 면에출력한다.

Java의정석定石 409 [14-7] 두개의주사위를굴려서나온눈의합이 6 인경우를모두출력하시오. [Hint] 배열을사용하시오. [ 실행결과] [1, 5] [2, 4] [3, 3] [4, 2] [5, 1] [ 정답] [ 연습문제]/ch14/Exercise14_7.java import java.util.*; import java.util.stream.*; class Exercise14_7 { public static void main(string[] args) { Stream<Integer> die = IntStream.rangeClosed(1,6).boxed(); die.flatmap(i-> Stream.of(1,2,3,4,5,6).map(i2 -> new int[]{ i, i2 )).filter(iarr-> iarr[0]+iarr[1]==6).foreach(iarr -> System.out.println(Arrays.toString(iArr))); [ 해설] 아래의붉은색으로표시된람다식은, Stream<Integer> 인 die 의요소, 즉 Integer를 int배 열의스트림(Stream<int[]>) 로변환한다. Integer Stream<int[]> die.flatmap( i-> Stream.of(1,2,3,4,5,6).map(i2 -> new int[]{ i, i2 ) ) Stream<Integer> Stream< int[]> 만일 flatmap을쓰지않고 map() 을사용했다면, 연산결과는 Stream<Stream<int[]> > 가 되었을것이다. Integer Stream<int[]> die.map( i-> Stream.of(1,2,3,4,5,6).map(i2 -> new int[]{ i, i2 ) ) Stream<Integer> Stream< Stream<int[]>> 아직이해가잘안간다면, filter() 를주석처리해서 Stream<int[]> 의모든요소가출력되도 록변경해보자. 이해에도움이될것이다. die.flatmap(i-> Stream.of(1,2,3,4,5,6).map(i2 -> new int[]{ i, i2 )) //.filter(iarr-> iarr[0]+iarr[1]==6).foreach(iarr -> System.out.println(Arrays.toString(iArr))); 자주쓰이지는않겠지만, 알아두면좋은내용이다. 난이도가있기때문에본문에서는제 외하고연습문제에넣게되었다. 이문제를푸느라책을복습하며다방면으로고민했으면 하는바램이다.

410 Java의정석定石 [14-8] 다음은불합격(150 점미만) 한학생의수를남자와여자로구별하여출력하는프 로그램이다. (1) 에알맞은코드를넣어완성하시오. [ 연습문제]/ch14/Exercise14_8.java import java.util.*; import java.util.function.*; import java.util.stream.*; import static java.util.stream.collectors.*; import static java.util.comparator.*; class Student { String name; boolean ismale; // 성별 int hak; // 학년 int ban; // 반 int score; Student(String name, boolean ismale, int hak, int ban, int score) { this.name = name; this.ismale = ismale; this.hak = hak; this.ban = ban; this.score = score; String getname() { return name; boolean ismale() { return ismale; int gethak() { return hak; int getban() { return ban; int getscore() { return score; public String tostring() { return String.format("[%s, %s, %d 학년 %d 반, %3d 점]", name, ismale? " 남":" 여", hak, ban, score); // groupingby() 에서사용 enum Level { HIGH, MID, LOW // 성적을상, 중, 하세단계로분류 class Exercise14_8 { public static void main(string[] args) { Student[] stuarr = { new Student(" 나자바", true, 1, 1, 300), new Student(" 김지미", false, 1, 1, 250), new Student(" 김자바", true, 1, 1, 200), new Student(" 이지미", false, 1, 2, 150), new Student(" 남자바", true, 1, 2, 100), new Student(" 안지미", false, 1, 2, 50), new Student(" 황지미", false, 1, 3, 100), new Student(" 강지미", false, 1, 3, 150), new Student(" 이자바", true, 1, 3, 200), new Student(" 나자바", true, 2, 1, 300), new Student(" 김지미", false, 2, 1, 250), new Student(" 김자바", true, 2, 1, 200), new Student(" 이지미", false, 2, 2, 150),

Java의정석定石 411 ; new Student(" 남자바", true, 2, 2, 100), new Student(" 안지미", false, 2, 2, 50), new Student(" 황지미", false, 2, 3, 100), new Student(" 강지미", false, 2, 3, 150), new Student(" 이자바", true, 2, 3, 200) Map<Boolean, Map<Boolean, Long>> failedstubysex = Stream.of(stuArr).collect( ); partitioningby( ) Student::isMale, partitioningby(s -> s.getscore() < 150, counting()) long failedmalestunum = failedstubysex.get(true).get(true); long failedfemalestunum = failedstubysex.get(false).get(true); System.out.println(" 불합격[ 남자]:"+ failedmalestunum +" 명"); System.out.println(" 불합격[ 여자]:"+ failedfemalestunum +" 명"); [ 실행결과] 불합격[ 남자]:2명불합격[ 여자]:4명 [ 해설] 합격과불합격, 즉 true와 false로나누는것이므로 groupingby() 보다 partitioningby() 가 더적합하다. 그리고는다시남자와여자로나누어야하므로한번더 partitioningby() 를 적용하면된다. 참고로 counting() 은 Collectors클래스의 static 메서드이다.

412 Java의정석定石 [14-9] 다음은각반별총점을학년별로나누어출력하는프로그램이다. (1) 에알맞은 코드를넣어완성하시오. [ 연습문제]/ch14/Exercise14_9.java import java.util.*; import java.util.function.*; import java.util.stream.*; import static java.util.stream.collectors.*; import static java.util.comparator.*; class Student { String name; boolean ismale; // 성별 int hak; // 학년 int ban; // 반 int score; Student(String name, boolean ismale, int hak, int ban, int score) { this.name = name; this.ismale = ismale; this.hak = hak; this.ban = ban; this.score = score; String getname() { return name; boolean ismale() { return ismale; int gethak() { return hak; int getban() { return ban; int getscore() { return score; public String tostring() { return String.format("[%s, %s, %d 학년 %d 반, %3d 점]", name, ismale? " 남":" 여", hak, ban, score); enum Level { HIGH, MID, LOW class Exercise14_9 { public static void main(string[] args) { Student[] stuarr = { new Student(" 나자바", true, 1, 1, 300), new Student(" 김지미", false, 1, 1, 250), new Student(" 김자바", true, 1, 1, 200), new Student(" 이지미", false, 1, 2, 150), new Student(" 남자바", true, 1, 2, 100), new Student(" 안지미", false, 1, 2, 50), new Student(" 황지미", false, 1, 3, 100), new Student(" 강지미", false, 1, 3, 150), new Student(" 이자바", true, 1, 3, 200), new Student(" 나자바", true, 2, 1, 300), new Student(" 김지미", false, 2, 1, 250),

Java의정석定石 413 ; new Student(" 김자바", true, 2, 1, 200), new Student(" 이지미", false, 2, 2, 150), new Student(" 남자바", true, 2, 2, 100), new Student(" 안지미", false, 2, 2, 50), new Student(" 황지미", false, 2, 3, 100), new Student(" 강지미", false, 2, 3, 150), new Student(" 이자바", true, 2, 3, 200) Map<Integer, Map<Integer, Long>> totalscorebyhakandban = Stream.of(stuArr).collect( groupingby( Student::getHak, groupingby( Student::getBan, summinglong(student::getscore) ) ) ); for(object e : totalscorebyhakandban.entryset()) { System.out.println(e); // main 의끝 실행결과 [ ] 1={1=750, 2=300, 3=450 2={1=750, 2=300, 3=450 [ 해설] 여기서는데이터에포함된학년이 2 개뿐이지만, 여러개일수도있으므로 partitioningby() 가아닌 groupingby() 을사용했다. 다시반별로구룹화해야하므로 groupingby() 를한번더적용했다. 간단한 2 중그룹화이므로그리어렵지는않을것이다. counting() 처럼 summinglong() 은 Collectors클래스의 static 메서드이다.

414 Java의정석定石 [ 연습문제 - 모범답안 ] [15-1] 커맨드라인으로부터파일명과숫자를입력받아서, 입력받은파일의내용의처음 부터입력받은숫자만큼의라인을출력하는프로그램(FileHead.java) 을작성하라. [Hint] BufferedReader의 readline() 을사용하라. [ 실행결과] C:\jdk1.8\work\ch15>java FileHead 10 USAGE: java FileHead 10 FILENAME C:\jdk1.8\work\ch15>java FileHead 10 aaa aaa 은/ 는디렉토리이거나, 존재하지않는파일입니다. C:\jdk1.8\work\ch15>java FileHead 10 FileHead.java 1:import java.io.*; 2: 3:class FileHead 4:{ 5: public static void main(string[] args) 6: { 7: try { 8: int line = Integer.parseInt(args[0]); 9: String filename = args[1]; 10: C:\jdk1.8\work\ch15> [ 정답] [ 연습문제]/ch15/FileHead.java import java.io.*; class FileHead { public static void main(string[] args) { try { int linenum = Integer.parseInt(args[0]); String filename = args[1]; File f = new File(fileName); if(f.exists()&&!f.isdirectory()) { BufferedReader br = new BufferedReader(new FileReader(fileName)); String line = ""; int i=1;

Java의정석定石 415 while((line = br.readline())!=null && i <= linenum) { System.out.println(i+":"+line); i++; else { throw new FileNotFoundException(fileName +" 은/ 는디렉토리이거나, 존재하지않는파일입니다."); catch(filenotfoundexception e) { System.out.println(e.getMessage()); catch(exception e) { System.out.println("USAGE: java FileHead 10 FILENAME"); // main [ 해설] 파일을라인단위로읽기위해 BufferedReader의 readline() 를사용했다. 작업을 하기에앞서사용자로부터입력받은이름의파일이존재하는지, 디렉토리는아닌지확인 해야한다. if(f.exists()&&!f.isdirectory()) { BufferedReader br = new BufferedReader(new FileReader(fileName)); 그다음에는반복문을이용해서입력받은라인수만큼만파일의내용을라인화면에출력 한다. while((line = br.readline())!=null && i <= linenum) { System.out.println(i+":"+line); i++; 참고로 while 문에사용된조건식이처리되는순서는다음과같다. (line = br.readline())!=null 1 line = br.readline() // readline() 으로읽은라인( 문자열) 을 line 에저장한다. 2 line!= nulll // line에저장된값이 null 이아닌지비교한다. * readline() 은더이상읽을라인이없으면 null 을반환한다.

416 Java의정석定石 [15-2] 지정된이진파일의내용을실행결과와같이 16진수로보여주는프로그램 (HexaViewer.java) 을작성하라. [Hint] PrintStream과 printf() 를사용하라. [ 실행결과] C:\jdk1.8\work\ch15>java HexaViewer HexaViewer.class CA FE BA BE 00 00 00 31 00 44 0A 00 0C 00 1E 09 00 1F 00 20 08 00 21 0A 00 08 00 22 0A 00 1F 00 23 07 00 24 0A 00 06 00 25 07 00 26 0A 00 08 00 27 0A 00 06 00 28 08 00 29 07 00 2A 0A 00 2B 00 2C 0A 00 08 00 2D 0A 00 08 00 2E 0A 00 06 00 2F 0A 00 08 00 2F 07 00 30 0A 00 12 00 31 07 00 32 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65 01 00 04 6D 61 69 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53... 중간생략 C:\jdk1.8\work\ch15> [ 정답] [ 연습문제]/ch15/HexaViewer.java import java.io.*; class HexaViewer { public static void main(string[] args) throws IOException { if(args.length!=1) { System.out.println("USAGE: java HexaViewer FILENAME"); System.exit(0); String inputfile = args[0]; try { FileInputStream input = new FileInputStream(inputFile); PrintStream output = new PrintStream(System.out); int data = 0; int i=0; while((data = input.read())!=-1) { output.printf("%02x ", data); if(++i%16==0) output.println(); input.close(); output.close(); catch (IOException e) { e.printstacktrace();

Java의정석定石 417 // main [ 해설] 사실 System.out이 PrintStream이기때문에굳이 PrintStream을따로생성해서사 용할필요는없다. 그냥 System.out.printf() 를사용하면된다. 그러나출력대상이화면 이아니라파일로바뀐다면아래의붉은색부분만변경하면다른곳은고치지않아도된 다는장점이있다. FileInputStream input = new FileInputStream(inputFile); PrintStream output = new PrintStream(System.out); data를 16진수로출력하려면 printf의 format 옵션중에서 '%x' 를사용해야한다. 빈자리를 0으로채우는 2자리 16 진수이어야하므로 '%02x' 가된다. while((data = input.read())!=-1) { output.printf("%02x ", data); // data를두자리의 16 진수형태로출력한다. if(i++%16==0) output.println(); format 설명결과 (int i=65) %d 10 진수(decimal integer) 65 %o 8 진수(octal integer) 101 %x 16 진수(hexadecimal integer) 41 %c 문자 A %s 문자열 65 %5d 5 자리숫자. 빈자리는공백으로채운다. 65 %-5d 5 자리숫자. 빈자리는공백으로채운다.( 왼쪽정렬) 65 %05d 5 자리숫자. 빈자리는 0 으로채운다. 00065

418 Java의정석定石 [15-3] 다음은디렉토리의요약정보를보여주는프로그램이다. 파일의개수, 디렉토리의 개수, 파일의총크기를계산하는 countfiles() 를완성하시오. [ 연습문제]/ch15/DirectoryInfoTest.java import java.io.*; class DirectoryInfoTest { static int totalfiles = 0; static int totaldirs = 0; static int totalsize = 0; public static void main(string[] args) { if(args.length!= 1) { System.out.println("USAGE : java DirectoryInfoTest DIRECTORY"); System.exit(0); File dir = new File(args[0]); if(!dir.exists()!dir.isdirectory()) { System.out.println(" 유효하지않은디렉토리입니다."); System.exit(0); countfiles(dir); System.out.println(); System.out.println(" 총 " + totalfiles + " 개의파일"); System.out.println(" 총 " + totaldirs + " 개의디렉토리"); System.out.println(" 크기 " + totalsize + " bytes"); // main public static void countfiles(file dir) { // 1. dir 의파일목록(File[]) 을얻어온다. File[] files = dir.listfiles(); for(int i=0; i < files.length; i++) { // 2. 얻어온파일목록의파일중에서... 디렉토리이면, totaldirs의값을증가시키고 countfiles() 를재귀호출한다. if(files[i].isdirectory()) { totaldirs++; countfiles(files[i]); else { // 3. 파일이면, totalfiles를증가시키고파일의크기를 totalsize 에더한다. totalfiles++; totalsize += files[i].length(); // countfiles [ 실행결과] C:\jdk1.8\work\ch15>java DirectoryInfoTest. 총 786개의파일

Java의정석定石 419 총 27개의디렉토리 크기 2566228 bytes C:\jdk1.8\work\ch15>

420 Java의정석定石 [15-4] 커맨드라인으로부터여러파일의이름을입력받고, 이파일들을순서대로합쳐 서새로운파일을만들어내는프로그램(FileMergeTest.java) 을작성하시오. 단, 합칠파 일의개수에는제한을두지않는다. [ 실행결과] C:\jdk1.8\work\ch15>java FileMergeTest USAGE: java FileMergeTest MERGE_FILENAME FILENAME1 FILENAME2... C:\jdk1.8\work\ch15>java FileMergeTest result.txt 1.txt 2.txt 3.txt C:\jdk1.8\work\ch15>type result.txt 1111111111 2222222222 33333333333333 C:\jdk1.8\work\ch15>java FileMergeTest result.txt 1.txt 2.txt C:\jdk1.8\work\ch15>type result.txt 1111111111 2222222222 C:\jdk1.8\work\ch15>type 1.txt 1111111111 C:\jdk1.8\work\ch15>type 2.txt 2222222222 C:\jdk1.8\work\ch15>type 3.txt 33333333333333 C:\jdk1.8\work\ch15> [ 정답] [ 연습문제]/ch15/FileMergeTest.java import java.io.*; import java.util.*; class FileMergeTest { public static void main(string[] args) { if(args.length < 2) { // 입력값이 2 보다작으면, 메세지를출력하고종료한다. System.out.println("USAGE: java FileMergeTest MERGE_FILENAME FILENAME1 FILENAME2..."); System.exit(0); try { Vector v = new Vector(); for(int i=1; i < args.length;i++) { File f = new File(args[i]); if(f.exists()) { v.add(new FileInputStream(args[i]));

Java의정석定石 421 else { System.out.println(args[i]+ " - 존재하지않는파일입니다."); System.exit(0); SequenceInputStream input = new SequenceInputStream(v.elements()); FileOutputStream output = new FileOutputStream(args[0]); int data = 0; while((data = input.read())!=-1) { output.write(data); catch(ioexception e) { // main [ 해설] 여러개의파일을하나로연결하기위해서는 SequenceInputStream 이적합하다. SequenceInputStream은여러 Stream을하나의 Stream 처럼다룰수있다. 커맨드라인으로입력받은파일을 Vector 에저장하고, 이 Vector로 SequenceInputStream 을생성한다음에읽고쓰면끝이다. 반복되는얘기지만, 사용자로부터입력받은값은 항상유효성체크를해주어야한다. 입력받은파일이존재하지않을수도있기때문이다. 메서드 / 생성자설명 SequenceInputStream(Enumeration e) SequenceInputStream(InputStream s1, InputStream s2) Enumeration 에저장된순서대로입력스트림을하나의 스트림으로연결한다. 두개의입력스트림을하나로연결한다. 다음은 SequenceInputStream의사용예이다 [ 사용예1] Vector files = new Vector(); files.add(new FileInputStream("file.001")); files.add(new FileInputStream("file.002")); SequenceInputStream in = new SequenceInputStream(files.elements()); [ 사용예2] FileInputStream file1 = new FileInputStream("file.001"); FileInputStream file2 = new FileInputStream("file.002"); SequenceInputStream in = new SequenceInputStream(file1, file2);

422 Java의정석定石 [15-5] 다음은 FilterWriter를상속받아서직접구현한 HtmlTagFilterWriter를사용해 서주어진파일에있는태그를모두제거하는프로그램이다. HtmlTagFilterWriter의 write() 가태그를제거하도록코드를완성하시오. [ 연습문제]/ch15/Exercise15_5.java import java.io.*; class Exercise15_5 { public static void main(string[] args) { if(args.length!= 2) { System.out.println("USAGE: java Exercise15_5 TAGET_FILE RESULT_FILE"); System.exit(0); String inputfile = args[0]; String outputfile = args[1]; try { BufferedReader input = new BufferedReader(new FileReader(inputFile)); HtmlTagFilterWriter output = new HtmlTagFilterWriter(new FileWriter(outputFile)); int ch = 0; while((ch=input.read())!=-1) { output.write(ch); input.close(); output.close(); catch(ioexception e) { class HtmlTagFilterWriter extends FilterWriter { StringWriter tmp = new StringWriter(); boolean intag = false; HtmlTagFilterWriter(Writer out) { super(out); public void write(int c) throws IOException { // 1. 출력할문자(c) 가 '<' 이면 intag의값을 true 로한다. if(c=='<') { intag = true; // 2. 출력할문자(c) 가 '>' 이면 intag의값을 false 로한다. else if(c=='>' && intag) { intag = false; // 새로운 StringWriter 를생성한다.( 기존 StringWriter 의내용을버린다.) tmp = new StringWriter();

Java의정석定石 423 return; // 3. intag의값이 true 이면, StringWriter 에문자(c) 를출력하고 if(intag) tmp.write(c); else // intag의값이 false 이면, out 에문자(c) 를출력한다. out.write(c); public void close() throws IOException { out.write(tmp.tostring()); // StringWriter의내용을출력하고 super.close(); // 조상의 close() 를호출해서기반스트림을닫는다. [ 실행결과] C:\jdk1.8\work\ch15>java Exercise15_5 test.html result.txt C:\jdk1.8\work\ch15>type result.txt New Document > 안녕하세요. 태그없애기테스트용파일입니다. < 태그가열린채로끝난것은태그로처리하지마세요. C:\jdk1.8\work\ch15>type test.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <TITLE> New Document </TITLE> </HEAD> <BODY> > 안녕하세요. 태그없애기테스트용파일입니다. </BODY> < 태그가열린채로끝난것은태그로처리하지마세요. [ 해설] 태그가아닐때는기반스트림(out) 에출력하고, 태그가시작되면(c 가 '<' 이면) intag의값을 true 로변경하고, intag의값이 true이면 tmp 에출력한다. // 3. intag의값이 true 이면, StringWriter 에문자(c) 를출력하고 if(intag) tmp.write(c); // StringWriter tmp = new StringWriter(); else // intag의값이 false 이면, out 에문자(c) 를출력한다. out.write(c); 태그가끝나면(c 가 '>' 이면), intag의값을 false 로변경하고, 새로운 StringWriter를생 성해서 tmp 에할당한다. 이렇게하면기존의내용( 태그) 은없어지게된다.

424 Java의정석定石 // 1. 출력할문자(c) 가 '<' 이면 intag의값을 true 로한다. if(c=='<') { intag = true; // 2. 출력할문자(c) 가 '>' 이면 intag의값을 false 로한다. else if(c=='>' && intag) { intag = false; // 새로운 StringWriter 를생성한다.( 기존 StringWriter 의내용을버린다.) tmp = new StringWriter(); return; StringWriter 에내용이남아있을수있으므로, 스트림을닫기전에 StringWriter의내용 을스트림에써주어야한다. public void close() throws IOException { out.write(tmp.tostring()); // StringWriter의내용을출력하고 super.close(); // 조상의 close() 를호출해서기반스트림을닫는다.

Java의정석定石 425 [15-6] 다음은콘솔명령어중에서디렉토리를변경하는 cd 명령을구현한것이다. 알맞 은코드를넣어 cd() 를완성하시오. [ 연습문제]/ch14/Exercise15_6.java import java.io.*; import java.util.*; import java.util.regex.*; class Exercise15_6 { static String[] argarr; // 입력한매개변수를담기위한문자열배열 static File curdir; // 현재디렉토리 static { try { curdir = new File(System.getProperty("user.dir")); catch(exception e) { public static void main(string[] args) { Scanner s = new Scanner(System.in); while(true) { try { String prompt = curdir.getcanonicalpath() + ">>"; System.out.print(prompt); // 화면으로부터라인단위로입력받는다. String input = s.nextline(); input = input.trim(); // 입력받은값에서불필요한앞뒤공백을제거한다. argarr = input.split(" +"); String command = argarr[0].trim(); if("".equals(command)) continue; command = command.tolowercase(); // 명령어를소문자로바꾼다. if(command.equals("q")) { // q 또는 Q 를입력하면실행종료한다. System.exit(0); else if(command.equals("cd")) { cd(); else { for(int i=0; i < argarr.length;i++) { System.out.println(argArr[i]); catch(exception e) { e.printstacktrace(); System.out.println(" 입력오류입니다."); // while(true) // main public static void cd() {

426 Java의정석定石 if(argarr.length==1) { System.out.println(curDir); return; else if(argarr.length > 2) { System.out.println("USAGE : cd directory"); return; String subdir = argarr[1]; // 1. 입력된디렉토리(subDir) 가 ".." 이면, if("..".equals(subdir)) { // 부모디렉토리 // 1.1 현재디렉토리의조상디렉토리를얻어서현재디렉토리로지정한다. File newdir = curdir.getparentfile(); if(newdir==null) { System.out.println(" 유효하지않은디렉토리입니다."); else { curdir = newdir; // 조상디렉토리를현재디렉토리로지정한다. // 2. 입력된디렉토리(subDir) 가 "." 이면, 단순히현재디렉토리의경로를화면에출력한다. else if(".".equals(subdir)) { // 현재디렉토리 System.out.println(curDir); else { // 3. 1 또는 2 의경우가아니면, // 3.1 입력된디렉토리(subDir) 가현재디렉토리의하위디렉토리인지확인한다. File newdir = new File(curDir, subdir); if(newdir.exists() && newdir.isdirectory()) { // 3.2 확인결과가 true 이면, 현재디렉토리(curDir) 을입력된디렉토리(subDir) 로변경한다. curdir = newdir; else { // 3.3 확인결과가 false 이면, " 유효하지않은디렉토리입니다." 고화면에출력한다. System.out.println(" 유효하지않은디렉토리입니다."); // if // cd() [ 실행결과] C:\jdk1.8\work\ch15>java Exercise15_6 C:\jdk1.8\work\ch15>> C:\jdk1.8\work\ch15>>cd ch15 유효하지않은디렉토리입니다. C:\jdk1.8\work\ch15>>cd.. C:\jdk1.8\work>>cd ch15 C:\jdk1.8\work\ch15>> C:\jdk1.8\work\ch15>>cd. C:\jdk1.8\work\ch15 C:\jdk1.8\work\ch15>>q

Java의정석定石 427 C:\jdk1.8\work\ch15> [ 해설] 콘솔(console) 의 cd 명령(change directory) 을직접구현해보는문제이다. cd명령 다음에이동할디렉토리를적어주는데, 현재디렉토리를의미하는. 과조상의디렉토 리를의미하는.. 도처리해주어야하므로 if-else if로 3가지경우에대해처리하였 다. // 1. 입력된디렉토리(subDir) 가 ".." 이면, if("..".equals(subdir)) { // 부모디렉토리... // 2. 입력된디렉토리(subDir) 가 "." 이면, 단순히현재디렉토리의경로를화면에출력한다. else if(".".equals(subdir)) { // 현재디렉토리 System.out.println(curDir); else { // 3. 1 또는 2 의경우가아니면,... // if 니머지는별로어렵지않으니설명을생략하겠다.

428 Java의정석定石 [15-7] 다음의코드는대화내용을파일에저장할수있는채팅프로그램이다. 저장 버튼을누르면대화내용이저장되도록알맞은코드를넣어완성하시오. [ 연습문제]/ch15/ChatWin.java import java.io.*; import java.awt.*; import java.awt.event.*; class ChatWin extends Frame { String nickname = ""; TextArea ta = new TextArea(); Panel p = new Panel(); TextField tf = new TextField(30); Button bsave = new Button(" 저장"); ChatWin(String nickname) { super("chatting"); this.nickname = nickname; setbounds(200, 100, 300, 200); p.setlayout(new FlowLayout()); p.add(tf); p.add(bsave); add(ta, "Center"); add(p, "South"); addwindowlistener(new WindowAdapter(){ public void windowclosing(windowevent e) { System.exit(0); ); bsave.addactionlistener(new ActionListener(){ public void actionperformed(actionevent ae) { FileDialog filesave = new FileDialog(ChatWin.this, " 파일저장", FileDialog.SAVE); filesave.setvisible(true); String filename = filesave.getdirectory() + filesave.getfile(); saveas(filename); ); EventHandler handler = new EventHandler(); ta.addfocuslistener(handler); tf.addfocuslistener(handler); tf.addactionlistener(handler); ta.settext("#" + nickname + " 님즐거운채팅되세요."); ta.seteditable(false); setresizable(false); setvisible(true); tf.requestfocus();

Java의정석定石 429 void saveas(string filename) { FileWriter fw = null; BufferedWriter bw = null; try { fw = new FileWriter(fileName); bw= new BufferedWriter(fw); bw.write(ta.gettext()); // TextArea 의내용을파일에저장한다. catch (IOException ie) { ie.printstacktrace(); finally { try { if(bw!=null) bw.close(); catch(ioexception e) { // try // saveas메서드의끝 public static void main(string[] args) { if(args.length!= 1) { System.out.println("USAGE : java ChatWin NICKNAME"); System.exit(0); new ChatWin(args[0]); // main class EventHandler extends FocusAdapter implements ActionListener { public void actionperformed(actionevent ae) { String msg = tf.gettext(); if("".equals(msg)) return; ta.append("\r\n" + nickname +">"+ msg); tf.settext(""); public void focusgained(focusevent e) { tf.requestfocus(); // class EventHandler // class [ 실행결과]

430 Java의정석定石 [ 해설] 답을보고나니쉬워서허탈할수도있을것같다. BufferedWriter를생성한다음 에, ta.gettext() 로채팅내용을얻어다 write(string str) 을통해출력하면되는것이다. FileWriter fw = null; BufferedWriter bw = null; try { fw = new FileWriter(fileName); bw= new BufferedWriter(fw); bw.write(ta.gettext()); // TextArea 의내용을파일에저장한다. 아래와같이코드를작성하면 write() 에서예외가발생하면 bw.close() 가수행되지않기 때문에예외가발생해도수행되는 finally블럭에서 bw.close() 가호출되도록하는것이 좋다. try { fw = new FileWriter(fileName); bw= new BufferedWriter(fw); bw.write(ta.gettext()); // TextArea 의내용을파일에저장한다. bw.close(); // 윗줄 bw.write() 에서예외가발생하면이문장은수행되지않는다. catch (IOException ie) { ie.printstacktrace(); // try 이전의코드를변경하여 finally블럭에서 bw.close() 를호출하도록했다. bw.close() 역 시예외가발생할수있으므로 try-catch 문으로감싸주었다. try { fw = new FileWriter(fileName); bw= new BufferedWriter(fw); bw.write(ta.gettext()); // TextArea 의내용을파일에저장한다. catch (IOException ie) { ie.printstacktrace(); finally { try { if(bw!=null) bw.close(); catch(ioexception e) { // try

Java의정석定石 431 [15-8] 다음의코드는파일로부터한줄씩데이터를읽어서보여주는프로그램이다. 버 튼을이용해서첫줄, 다음줄, 이전줄, 마지막줄로이동할수있으며, 각줄의개행문 자는 를사용한다. (1)~(2) 에알맞은코드를넣어완성하시오. [ 연습문제]/ch15/WordStudy.java import java.util.*; import java.io.*; import java.awt.*; import java.awt.event.*; class WordStudy extends Frame { Button first = new Button("<<"); Button prev = new Button("<"); Button next = new Button(">"); Button last = new Button(">>"); Panel buttons = new Panel(); TextArea ta = new TextArea(); ArrayList wordlist = new ArrayList(); final String WORD_FILE = "word_data.txt"; final String CR_LF = System.getProperty("line.separator"); // 개행문자 int pos = 0; WordStudy(String title) { super(title); buttons.add(first); buttons.add(prev); buttons.add(next); buttons.add(last); add("south", buttons); add("center", ta); EventHandler handler = new EventHandler(); addwindowlistener(handler); first.addactionlistener(handler); prev.addactionlistener(handler); next.addactionlistener(handler); last.addactionlistener(handler); loadfile(word_file); setbackground(color.black); setsize(300, 200); setlocation(200, 200); setresizable(true); setvisible(true); showfirst(); void showfirst() { pos = 0; display(pos);

432 Java의정석定石 void showprevious() { pos = (pos > 0)? --pos : 0; display(pos); void shownext() { int size = wordlist.size(); pos = (pos < size-1)? ++pos : size-1; display(pos); void showlast() { pos = wordlist.size()-1; display(pos); void display(int pos) { // pos 위치에있는라인의내용을보여준다. // 1. wordlist에서 pos 번째의위치에있는데이터를읽어온다. String tmp = (String)wordList.get(pos); StringBuffer sb = new StringBuffer(tmp.length()); // 2. StringTokenizer 를이용해서 를구분자로자른다. StringTokenizer st = new StringTokenizer(tmp, " "); // 3. 잘라진 Token 에개행문자(CR_LF) 를붙여서 StringBuffer 에붙인다.(append) while(st.hasmoretokens()) { sb.append(st.nexttoken()).append(cr_lf); // 4. StringBuffer의내용을뽑아서 TextArea 에보여준다. ta.settext(sb.tostring()); void loadfile(string filename) { try { BufferedReader br = new BufferedReader(new FileReader(fileName)); String line = ""; // 1. BuffredReader와 FileReader 를이용해서파일의내용을라인단위로읽는다. while((line = br.readline())!=null) { // 2. 읽어온라인을 wordlist 에저장한다. wordlist.add(line); catch (IOException e) { // 3. 만일예외가발생하면프로그램을종료한다. System.out.println(" 데이터파일을읽을수없습니다."); System.exit(1); public static void main(string args[]) { WordStudy mainwin = new WordStudy("Word Study"); class EventHandler extends WindowAdapter implements ActionListener { public void actionperformed(actionevent ae) {

Java의정석定石 433 Button b = (Button)ae.getSource(); if(b==first) { showfirst(); else if(b==prev) { showprevious(); else if(b==next) { shownext(); else if(b==last) { showlast(); public void windowclosing(windowevent e) { System.exit(0); // class EventHandler [ 실행결과] [word_data.txt] mandatory 1. 명령의 2. 통치를위임받은 3. 강제의, 의무의(obli-gatory); 필수의 preliminary 1. 사전준비 2. 예비시험 3. 주경기이전에펼쳐지는개막경기 commitment 1. 위탁, 위임; 위원회회부 2. 인도; 투옥, 구류, 수감 3. 언질[ 공약] 을주기 prominent 1. 현저한, 두드러진 2. 돌기한, 양각된 3. 탁월한, 걸출한, 유명한; 중요한 Tell me the reason for coming here. 여기에온이유를내게말해라. There is something different about you today. 너오늘평소와좀다르구나. He jumped up and down when he got the news. 그는뉴스를듣고펄쩍뛰었다. When I opened it, I found a surprise. 그것을열었을때, 나는놀라운것을발견했다. I have known him since he was a child. 나는그를어려서부터알고있다.