본문 바로가기

Java의 정석 : 3rd Edition

[Java의 정석 - 연습문제] Chapter06. 객체지향 프로그래밍 I(OOP)

Java의 정석 : 3rd Edition, 2016을 개인 학습용으로 정리한 내용입니다.
"ppt 파일 자료, 연습문제"를 학습 용도로 배포할 수 있음을 고지하셨습니다.
저자님께 감사드립니다.

 

 

 

 

[6-1] 다음과 같은 멤버변수를 갖는 SutdaCard클래스를 정의하시오.

타입 변수명 설명
int num 카드의 숫자(1~10사이의 정수)
boolean isKwang 광(光)이면 true, 아니면 false

 

나의 답 : 

class SutdaCard {
	int num;
	boolean isKwang;
}

 

 

 

 

[6-2] 문제6-1에서 정의한 SutdaCard클래스에 두 개의 생성자와 info()를 추가해서 실행결과와 같은 결과를 얻도록 하시오.

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

 

나의 답(오답) :

① 기본 생성자를 호출할 땐 num 변수에 임의의 값을 넣는 줄 알았는데, 그냥 1을 넣는거였다.

② String.valueOf()를 이용하여 int 타입의 변수 num을 문자열로 변환 후 반환했다.

생성자 호출 this()를 적극 활용해야겠다.

(문제에 Math.random()를 사용하라는 말이 없긴 했다..)

class SutdaCard {
	int num;
	boolean isKwang;

	// 1
	SutdaCard() {
		this.num = (int) ((Math.random() * 10) + 1);
		this.isKwang = true;
	}

	SutdaCard(int num, boolean isKwang) {
		this.num = num;
		this.isKwang = isKwang;
	}

	// 2
	String info() {
		if (this.isKwang) {
			return String.valueOf(this.num) + "K";
		}
		return String.valueOf(this.num);
	}
}

 

해설 : 

객체를 생성할 때 두 개의 생성자를 사용했으므로 두 개의 생성자를 정의해야한다.

- 매개변수가 있는 생성자 : 카드의 num과 isKwang의 값을 매개변수로 받는다.

- 매개변수가 없는 기본 생성자 : 실행결과의 "1K"로 num과 isKwang의 값을 각각 1과 true로 했음을 알 수 있다.

 

① 기존의 코드를 호출하는 게 더 좋은 코드이다. (재사용성, 코드 수정 유리)

② 변수 num은 int 타입이지만 문자열의 덧셈연산으로 인해 문자열로 변환된다. (삼항연산자 사용)

class SutdaCard {
	int num;
	boolean isKwang;

	// 1
	SutdaCard() {
		this(1, true); // SutdaCard(int num, boolean isKwang) 호출
		// this.num = 1;
		// this.isKwang = true;
	}

	SutdaCard(int num, boolean isKwang) {
		this.num = num;
		this.isKwang = isKwang;
	}

	// 2
	String info() { // 숫자를 문자열로 반환. 광(光)인 경우 K를 덧붙인다.
		return num + (isKwang? "K" : "");
	}
}

 

 

 

 

[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;
}

 

 

 

 

[6-4] 문제6-3에서 정의한 Student클래스에 다음과 같이 정의된 두 개의 메서드 getTotal()과 getAverage()를 추가하시오.

1. 메서드명  : getTotal

    기능         : 국어(kor), 영어(eng), 수학(math)의 점수를 모두 더해서 반환한다.

    반환타입  : int

    매개변수  : 없음

 

2. 메서드명  : getAverage

    기능         : 총점(국어점수+영어점수+수학점수)을 과목수로 나눈 평균을 구한다.

                      소수점 둘째자리에서 반올림할 것.

    반환타입 : float

    매개변수 : 없음

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

 

나의 답 :

① this를 무조건 붙였는데, 지역변수랑 헷갈릴일이 없다면 붙이지 않아도 되니 필수는 아닌가보다.

② 평균을 구한 후 소수점 둘째자리에서 반올림한다.

 2-1. 총점을 과목 수(kor, eng, math = 3)으로 나눴다.

 2-2. average(78.666664)의 값을 소수점 둘째자리에서 반올림해야 하므로 Math.round()를 사용했다.

  2-2-1. (float) Math.round(average * 10)         // 787.0 (78.6...의 자리에서 반올림 * 10) (* : 오른쪽 이동)

  2-2-2. (float) Math.round(average * 10)/10;   // 78.7   (소수점 둘째자리여야 하므로 / 10) (/ : 왼쪽 이동)

class Student {
	String name;
	int ban;
	int no;
	int kor;
	int eng;
	int math;

	// 1
	int getTotal() {
		return this.kor + this.eng + this.math;
	}

	// 2
	float getAverage() {
		float average = (float) getTotal() / 3;      // 2-1 : 78.666664
		return (float) Math.round(average * 10)/10;  // 2-2 : 787.0 > 78.7
	}
}

 

해설 :

3으로 나누면 int와 int간의 연산이므로 소수점 이하의 값은 버려지게 된다.

3f(f : float타입 리터럴)로 나눠야 소수점 이하의 값들을 얻을 수 있다.

소수점 둘째자리에서 반올림하려면 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
float getAverage() {
	return (int)(getTotal() / 3f * 10 + 0.5f) / 10f;
}

 

 

 

 

[6-5] 다음과 같은 실행결과를 얻도록 Student클래스에 생성자와 info()를 추가하시오.

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

 

나의 답 :

① 학생이름, 반, 번호, 국어점수, 영어점수, 수학점수를 매개변수로 받는 생성자

② 학생의 정보를 출력하는 메서드

class Student {
	String name;
	int ban;
	int no;
	int kor;
	int eng;
	int math;

	// 1
	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 this.kor + this.eng + this.math;
    }

    float getAverage() {
        float average = (float) getTotal() / 3;
        return (float) Math.round(average * 10)/10;
    }

    // 2
    String info() {
        return this.name + "," + this.ban + "," + this.no + ","
            + this.kor + "," + this.eng + "," + this.math + ","
            + getTotal() + "," + getAverage();
    }
}

 

 

 

 

[6-6] 두 점의 거리를 계산하는 getDistance()를 완성하시오.

[Hint] 제곱근 계산은 Math.sqrt(double a)를 사용하면 된다.

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

 

나의 답 : 

(x-x1)^{2}, (y-y1)^{2} 2제곱해야 하므로 곱셈연산자를 사용했다.

두 점 (x, y)와 (x1, y1)의 거리를 구하는 공식 : \sqrt{(x-x1)^{2}+(y-y1)^{2}}
return Math.sqrt((x-x1)*(x-x1) + (y-y1)*(y-y1)); // x, y는 지역변수

 

해설 : 

제곱은 Math.pow(double a, double b)를 사용하면 된다.

※ 메서드를 호출하는 건 곱셈연산보다 비용이 많이 드는 작업이다.

// Math.pow(double a, double b)를 사용한 코드
return Math.sqrt(Math.pow(x-x1, 2) + Math.pow(y-y1, 2)); // x, y는 지역변수

 

 

 

 

[6-7] 문제6-6에서 작성한 클래스메서드 getDistance()를 MyPoint클래스의 인스턴스메서드로 정의하시오.

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

 

나의 답 : 

// 인스턴스 메서드
double getDistance(int x1, int y1) {
	return Math.sqrt((this.x-x1)*(this.x-x1) + (this.y-y1)*(this.y-y1)); // x, y는 인스턴스 변수
}

 

해설 : 

① 매개변수(지역변수)로 작업에 필요한 값을 제공받는다.

(인스턴스 변수 사용 X : 인스턴스와 관계 없으므로 static 메서드로 선언 가능)

② 인스턴스 변수를 사용해서 작업하므로 매개변수로 x1과 y1만을 제공받으면 된다.

(인스턴스 변수 사용 O : 인스턴스와 관계 있으므로 static 메서드로 선언 불가)

 

MyPoint클래스에 두 점간의 거리를 계산하는 메서드 getDistance()를 넣는다면,

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));

 

 

 

 

[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 변수(클래스 변수)

지역변수 : 나머지 그 외 모두

선언위치 별 변수의 종류
선언 위치 별 변수의 종류와 생성시기
선언 위치 별 변수의 종류와 생성시기

 

 

 

 

[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;
	}
}

 

나의 답 : 너무 쉬운문제잖아~ 했는데, 메서드를 깜빡했다.

weapon, armor, weaponUp(), armorUp()
① weapon, armor : 모든 병사의 공격력과 방어력은 같아야 하기 때문(공통 속성)

                               모든 Marine 인스턴스에 대해 동일한 값이어야 하므로.

② weaponUp(), armorUp() : static 변수에 대한 작업을 하는 메서드이므로.

 

+) 병사(marin)의 위치는 모든 병사가 서로 다른 위치에 있어야 하므로 개별적인 값이어야 함.

+) 병사들마다 부상의 정도가 다를 것이므로 병사들의 체력(hp) 역시 개별적인 값이어야 함.

 

 

 

 

[6-10] 다음 중 생성자에 대한 설명으로 옳지 않은 것은? (모두 고르시오)

a. 모든 생성자의 이름은 클래스의 이름과 동일해야한다.

b. 생성자는 객체를 생성하기 위한 것이다.

c. 클래스에는 생성자가 반드시 하나 이상 있어야 한다.

d. 생성자가 없는 클래스는 컴파일러가 기본 생성자를 추가한다.

e. 생성자는 오버로딩 할 수 없다.

 

나의 답 : b, e

- b : 객체 생성보다는 iv 초기화 작업을 위함.

       (객체를 생성할 때 사용되지만, 객체를 초기화할 목적으로 사용. 객체를 생성하는 건 new 연산자이다.) 
- e : 생성자도 오버로딩 가능

       (하나의 클래스에 여러 개의 생성자 정의 가능)

 

 

 

 

[6-11] 다음 중 this에 대한 설명으로 맞지 않은 것은? (모두 고르시오)

a. 객체 자신을 가리키는 참조변수이다.

b. 클래스 내에서라면 어디서든 사용할 수 있다.

c. 지역변수와 인스턴스변수를 구별할 때 사용한다.

d. 클래스 메서드 내에서는 사용할 수 없다.

 

나의 답 : b

- b : 클래스 멤버(static이 붙은 변수나 메서드)에는 사용할 수 없다.

 

 

 

 

[6-12] 다음 중 오버로딩이 성립하기 위한 조건이 아닌 것은? (모두 고르시오)

a. 메서드의 이름이 같아야 한다.

b. 매개변수의 개수나 타입이 달라야 한다.

c. 리턴타입이 달라야 한다.

d. 매개변수의 이름이 달라야 한다.

 

나의 답 : c, d

 

 

 

 

[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, d

- b : 매개변수의 타입(int, int > long, long) 다르므로 오버로딩 성립.

- c : 매개변수의 타입(int, int > byte, byte) 다르므로 오버로딩 성립.

(메서드 호출 시 어떤 메서드를 호출한 건지 모호하지 않나? 하지만 매개변수 타입 다르니 성립)

- d : 매개변수의 타입(int, int > long, int) 다르므로 오버로딩 성립.

 

 

 

 

[6-14] 다음 중 초기화에 대한 설명으로 옳지 않은 것은? (모두 고르시오)

a. 멤버변수는 자동 초기화되므로 초기화하지 않고도 값을 참조할 수 있다.

b. 지역변수는 사용하기 전에 반드시 초기화해야 한다.

c. 초기화 블럭보다 생성자가 먼저 수행된다.

d. 명시적 초기화를 제일 우선적으로 고려해야 한다.

e. 클래스변수보다 인스턴스변수가 먼저 초기화된다.

 

나의 답 : c, e

- c : 생성자 보다 초기화 블럭이 먼저 수행된다.

- e : 인스턴스변수보다 클래스변수가 먼저 초기화된다.

 

 

 

 

[6-15] 다음중 인스턴스변수의 초기화 순서가 올바른 것은?

a. 기본값-명시적초기화-초기화블럭-생성자

b. 기본값-명시적초기화-생성자-초기화블럭

c. 기본값-초기화블럭-명시적초기화-생성자

d. 기본값-초기화블럭-생성자-명시적초기화

 

나의 답 : a

- 클래스 변수의 초기화 순서 : 기본값 → 명시적 초기화 → 클래스 초기화 블럭

- 인스턴스 변수의 초기화 순서 : 기본값 → 명시적 초기화 → 인스턴스 초기화 블럭 → 생성자

 

 

 

 

[6-16] 다음 중 지역 변수에 대한 설명으로 옳지 않은 것은? (모두 고르시오)

a. 자동 초기화되므로 별도의 초기화가 필요없다.

b. 지역변수가 선언된 메서드가 종료되면 지역변수도 함께 소멸된다.

c. 메서드의 매개변수로 선언된 변수도 지역변수이다.

d. 클래스 변수나 인스턴스 변수보다 메모리 부담이 적다.

e. 힙(heap) 영역에 생성되며 가비지 컬렉터에 의해 소멸된다.

 

나의 답 : a, e

- a : 지역 변수는 자동 초기화 되지 않으므로 사용 전 반드시 직접(수동) 초기화해야 함. 

- e : 힙(heap) 영역에는 인스턴스가 생성되고, 지역 변수는 호출스택(call stack)에 생성된다.

지역변수는 자신이 선언된 블럭이나 메서드가 종료되면 소멸되므로 메모리 부담이 적다.

 

 

 

 

[6-17] 호출스택이 다음과 같은 상황일 때 옳지 않은 설명은? (모두 고르시오)

문제6-17 호출스택 그림
문제6-17 호출스택 그림

a. 제일 먼저 호출스택에 저장된 것은 main메서드이다.

b. println메서드를 제외한 나머지 메서드들은 모두 종료된 상태이다.

c. method2메서드를 호출한 것은 main메서드이다.

d. println메서드가 종료되면 method1메서드가 수행을 재개한다.

e. main-method2-method1-println의 순서로 호출되었다.

f. 현재 실행중인 메서드는 println 뿐이다.

 

나의 답 : b

- b : 나머지 메서드들은 모두 대기 상태가 된다.

 

 

 

 

[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();         // 라인 E
		instanceMethod1();
	}
}

 

나의 답 : 

- 라인 A : 클래스 변수에 인스턴스 변수 저장할 수 없음. (객체 생성 후 저장 가능, 권장 X)
- 라인 B : 클래스 메서드에서 인스턴스 변수 참조할 수 없음. (객체 생성 후 참조 가능, 권장 X)
- 라인 D : 클래스 메서드에서 인스턴스 메서드 호출할 수 없음. (객체 생성 후 호출 가능, 권장 X)

 

 

 

 

[6-19] 다음 코드의 실행 결과를 예측하여 적으시오.

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:ABC123456

 

해설 :

ABC123

After change:ABC123

 

많은 사람들이 매개변수가 참조형이라는 것만 보고 main메서드의 문자열 str이 변경될 것이라고 쉽게 생각한다.

 

① 처음에 문자열을 참조변수 str에 저장하면 아래와 같은 그림이 된다.

String str = "ABC123";

main()의 참조변수 str
main()의 참조변수 str

 

② change()를 호출하면서 참조 변수 str을 넘겨주면, change()의 지역 변수 str에 주소값 0x100이 저장된다.

 2-1. change()의 지역 변수 str도 문자열 "ABC123"을 참조하게 된다.

 2-2. 두 참조변수는 이름은 동일하지만 엄연히 다른 변수이다.

 2-3. 서로 다른 영역에 존재하기 때문에 이름이 같아도 상관없는 것이다.

change(str); // change를 호출하면서 문자열 str을 넘겨준다.

main()와 change()의 참조변수 str
main()와 change()의 참조변수 str

 

③ change()에서 넘겨받은 문자열의 뒤에 "456"을 붙인다.

 3-1. 문자열은 내용을 변경할 수 없기 때문에 덧셈연산을 하면 새로운 문자열이 생성된다.

 3-2. 생성된 새로운 문자열의 주소가 변수(lv) str에 저장된다.

public static void change(String str) {
	str += "456"; // 기존의 문자열에 "456"을 붙인다.
}

 

change()의 참조변수 str(새로운 문자열의 주소 저장)
change()의 참조변수 str(새로운 문자열의 주소 저장)

 

④ change()가 종료되면서 작업에 사용하던 메모리를 반환한다.

 4-1. change()의 지역 변수인 str 역시 메모리에서 제거된다.

 

⑤ main()로 돌아와서 문자열 str의 값을 출력하면 처음의 값과 동일한 값이 출력된다.

 5-1. 문자열 "ABC123456"은 참조하는 변수가 하나도 없으므로 적절한 시기에 GC에 의해 제거된다.

System.out.println("After change:" + str);

main()의 참조변수 str
main()의 참조변수 str

 

 

 

 

[6-20] 다음과 같이 정의된 메서드를 작성하고 테스트하시오.

[주의] Math.random()을 사용하는 경우 실행결과와 다를 수 있음.

메서드명 : shuffle

기능        : 주어진 배열에 담긴 값의 위치를 바꾸는 작업을 반복하여 뒤섞이게 한다.

                 처리한 배열을 반환한다.

반환타입 : int[]

매개변수 : int[] arr - 정수값이 담긴 배열

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]

 

나의 답 : 

static int[] shuffle(int[] arr) {
	for (int i = 0; i < arr.length; i++) {
		int n = (int)(Math.random() * arr.length);

		int temp = arr[i];
		arr[i] = arr[n];
		arr[n] = temp;
	}
	return arr;
}

 

해설 :

① 매개변수로 어떤 값이 넘어올지 모르기 때문에 작업을 시작하기 전 값의 유효성체크는 반드시 해야 한다.

 1-1. 넘겨받은 배열이 null이거나 크기가 0이면 그대로 반환한다.

② 반복문을 이용해서 배열 요소의 값을 배열 임의의 요소의 값과 바꾼다.

public static int[] shuffle(int[] arr) {
	// 1
	if(arr == null || arr.length == 0)
		return arr;

	// 2
	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;
}

 

 

 

 

[6-21] Tv클래스를 주어진 로직대로 완성하시오. 완성한 후에 실행해서 주어진 실행결과와 일치하는지 확인하라.

[참고] 코드를 단순히 하기 위해서 유효성검사는 로직에서 제외했다.

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로 바꾼다.
	}

	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

 

나의 답 :

// (1) isPowerOn의 값이 true면 false로, false면 true로 바꾼다.
if (isPowerOn) {
	isPowerOn = false;
} else {
	isPowerOn = true;
}
// 해설 : isPowerOn = !isPowerOn;

// (2) volume의 값이 MAX_VOLUME 보다 작을 때만 값을 1증가시킨다.
if (volume < MAX_VOLUME) {
	volume++;
}

// (3) volume의 값이 MIN_VOLUME 보다 클 때만 값을 1감소시킨다.
if (volume > MIN_VOLUME) {
	volume--;
}

// (4) channel의 값을 1증가시킨다.
// 만일 channel이 MAX_CHANNEL이면, channel의 값을 MIN_CHANNEL로 바꾼다.
if (channel == MAX_CHANNEL) {
	channel = MIN_CHANNEL;
} else {
	channel++;
}

// (5) channel의 값을 1감소시킨다.
// 만일 channel이 MIN_CHANNEL이면, channel의 값을 MAX_CHANNEL로 바꾼다.
if (channel == MIN_CHANNEL) {
	channel = MAX_CHANNEL;
} else {
	channel--;
}

 

 

 

 

[6-22] 다음과 같이 정의된 메서드를 작성하고 테스트하시오.

[Hint] String클래스의 charAt(int i)메서드를 사용하면 문자열의 i번째 위치한 문자를 얻을 수 있다.

메서드명 : isNumber

기능        : 주어진 문자열이 모두 숫자로만 이루어져있는지 확인한다.

                 모두 숫자로만 이루어져 있으면 true를 반환하고, 그렇지 않으면 false를 반환한다.

                 만일 주어진 문자열이 null이거나 빈문자열 ""이라면 false를 반환한다.

반환타입 : boolean

매개변수 : String str - 검사할 문자열

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

 

나의 답 : 논리 부정 연산자(!)를 사용하여 숫자('0'~'9')가 아닐 시 바로 false를 반환하도록 구현했다.

static boolean isNumber(String str) {
	if (str == null || str.equals("")) {
		return false;
	}

	for (int i = 0; i < str.length(); i++) {
		if (!('0' <= str.charAt(i) && str.charAt(i) <= '9')) { // 숫자('0'~'9')인지 확인
			return false;
		}
	}
	return true;
}

 

해설 : 

① 반복문과 charAt(int i)로 문자열에서 한 문자씩 차례대로 읽어와 char타입의 변수 ch에 저장한다.

② 읽어온 문자(ch)가 숫자가 아니면 false를 반환한다.

public static boolean isNumber(String str) {
	if(str == null || str.equals(""))
		return false;

	// 1
	for(int i = 0; i < str.length(); i++) {
		char ch = str.charAt(i);
		
		// 2
		if(ch < '0' || ch > '9') { // if(!('0' <= ch && ch <= '9'))와 동일
			return false;
		}
	} // for
	return true;
}

 

 

 

 

[6-23] 다음과 같이 정의된 메서드를 작성하고 테스트하시오.

메서드명 : max

기능        : 주어진 int형 배열의 값 중에서 제일 큰 값을 반환한다.

                 만일 주어진 배열이 null이거나 크기가 0인 경우, -999999를 반환한다.

반환타입 : int

매개변수 : int[] arr - 최대값을 구할 배열

class Exercise6_23 {
	/*
		(1) 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

 

나의 답 : 결과값을 0으로 초기화 한 후 배열 각 요소와 비교하여 가장 큰 값으로 저장하여 반환한다.

static int max(int[] arr) {
	if (arr == null || arr.length == 0) {
		return -999999;
	}

	int result = 0;
	for (int i = 0; i < arr.length; i++) {
		if (result < arr[i]) {
			result = arr[i];
		}
    }
	return result;
}

 

해설 : 

① 배열의 첫 번째 요소(arr[0])로 최대값(max)을 초기화 한다.

② 최대값 max를 배열의 첫 번째 값으로 초기화 했으므로 첫 번째값은 비교할 필요가 없다.

 2-1. 두 번째 값(arr[1])부터 비교한다.

 2-2. 비교해서 최대값보다 크면 그 값을 변수 max에 저장한다.

 2-3. 반복문을 다 돌고 나면, max에는 배열의 요소 중 가장 큰 값이 저장되며, 이 값을 반환한다.

public static int max(int[] arr) {
	// 동일

	// 1
	int max = arr[0];  // 배열의 첫 번째 값으로 최대값을 초기화 한다.

	// 2
	for(int i = 1; i < arr.length; i++) {  // 배열의 두 번째 값부터 비교한다.
		if(arr[i] > max)
			max = arr[i];
	}
	return max;
}

 

 

 

 

[6-24] 다음과 같이 정의된 메서드를 작성하고 테스트하시오.

메서드명 : abs

       기능 : 주어진 값의 절대값을 반환한다.

반환타입 : int

매개변수 : int value

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

 

나의 답 : value의 값이 양수이면 그대로 반환하고, 음수이면 부호를 바꿔서 반환한다.

static int abs(int value) {
	if (value < 0) {
		return -value;
	}
	return value;
    // return value >= 0 ? value : -value; // 삼항 연산자
}