섯다카드 20장을 포함하는 섯다카드 한 벌(SutdaDeck클래스)을 정의한 것이다.
- 섯다카드 20장을 담는 SutdaCard배열을 초기화하시오.
- 단, 섯다카드는 1부터 10까지의 숫자 가 적힌 카드가 한 쌍씩 있고, 숫자가 1, 3, 8인 경우에는 둘 중의 한 장은 광(Kwang)이 어야 한다.
- 즉, SutdaCard의 인스턴스변수 isKwang의 값이 true이어야 한다.
--- 문제 코드 ---
class SutdaDeck {
final int CARD_NUM = 20;
SutdaCard[] cards = new SutdaCard[CARD_NUM];
SutdaDeck() {
// (구현) 배열 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,
--- 정답 코드 ---
SutdaDeck() {
// (구현) 배열 SutdaCard를 적절히 초기화 하시오.
// 1. 카드배열 각 인덱스에 값을 넣어줘야 했기에 배열 크기 만큼 반복문 실행.
for (int i=0; i<cards.length; i++) {
// 2-1. 1~10까지 숫자 한 쌍 이기에 각 인덱스의 값을 저장할 지역변수 no를 만들고 (i%10+1)로 1~10 두번 저장.
// 2-2. 각 인덱스 값마다 Kwang의 조건도 저장.
int no = i%10 + 1;
boolean Kwang = i < 10 && (no == 1 || no == 3 || no == 8);
// 3. 아래 SutdaCard 클래스에서 num 과 isKwang을 매개변수로 받고 있으니
// cards 배열의 각 인덱스마다 for문 안에서 생성한 변수를 넘겨주며 인스턴스 생성.
cards[i] = new SutdaCard(no, Kwang);
}
}
- 이번 문제를 보고 어떻게 시작해야 할지 정말 어려웠다. 카드 20장을 담는다는 지문을 보고 반복문을 써야 하는 건 아닐까 생각했지만 SutdaDeck (){}를 보고 생성자 면 this를 써야 하는 건 아닌지 이런 부분에서 많이 헷갈린 듯하다. 위의 정답을 구간마다 나눠 해석하며 조금은 이해할 수 있었다.
- 카드배열 각 인덱스에 값을 넣어줘야 했기에 배열 크기 만큼 반복문 실행.
- 1 ~ 10까지 숫자 한 쌍 이기에 각 인덱스의 값을 저장할 지역변수 no를 만들고 (i%10+1)로 1~10 두번 저장.
- 각 인덱스 값마다 Kwang의 조건도 저장.
- 아래 SutdaCard 클래스에서 num 과 isKwang을 매개변수로 받고 있으니 cards 배열의 각 인덱스마다 for문 안에서 생성한 변수를 넘겨주며 인스턴스 생성.
위의 SutdaDeck클래스에 다음에 정의된 새로운 메서드를 추가하고 테스트 하시오.
메서드명 : shuffle
- 기능 : 배열 cards에 담긴 카드의 위치를 뒤섞는다.(Math.random()사용)
- 반환타입 : 없음
- 매개변수 : 없음
메서드명 : pick
- 기능 : 배열 cards에서 지정된 위치의 SutdaCard를 반환한다.
- 반환타입 : SutdaCard
- 매개변수 : int index - 위치
메서드명 : pick
- 기능 : 배열 cards에서 임의의 위치의 SutdaCard를 반환한다.(Math.random()사용)
- 반환타입 : SutdaCard
- 매개변수 : 없음
--- 문제 코드 ---
class SutdaDeck {
final int CARD_NUM = 20;
SutdaCard[] cards = new SutdaCard[CARD_NUM];
SutdaDeck() {
// 연습문제 7-1 의 답이므로 내용생략
}
void shuffle() {
// (구현)
}
SutdaCard pick(int index) {
// (구현)
}
SutdaCard pick() {
// (구현)
}
} // 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
--- 정답 코드 ---
void shuffle () {
// cards 배열 안에 SutdaCard객체가 들어간다.
for (int i=0; i<cards.length; i++) {
// 1. 반복문을 통해 랜덤 숫자를 변수j에 저장
int j = (int)(Math.random()* cards.length);
// 2. SutdaCard tmp 객체에 cards배열의 i번째를 할당.
SutdaCard tmp = cards[i];
// 3. cards배열의 i번째를 cards배열의 랜덤수j번째로 변경
cards[i] = cards[j];
// 4. cards배열의 랜덤수j번째에 1번에서 저장된 cards배열의 i번째를 할당.(tmp객체)
cards[j] = tmp;
// 5. i값이 증가하면서 배열 각 자리의 값들이 바뀐다.
}
}
SutdaCard pick (int index) {
// 바로 return을 해줘도 되지만 유효성 검사를 거쳐주는게 가장 좋다.
if (index < 0 || index > cards.length) {
return null;
}
return cards[index];
// 처음에 풀었던 방식이지만 굳이 반복문을 쓸 필요가 없었다.
// SutdaCard idx = null;
// for (int i=0; i< cards.length; i++) {
// idx = cards[index];
// }
// return idx;
}
SutdaCard pick () {
// 임의의 위치를 반환하기 위해 랜덤 숫자 j생성
int j = (int)(Math.random()*cards.length);
return cards[j];
}
- shuffle 메서드에서 배열의 순서를 바꾸며 과정의 순서에 헷갈림이 있었다. 언제든 순서나 방향에 어려움이 있다면 어떤 동작을 하는지 파악하고 순서를 생각해 보는 것이 좋을 것 같다.
- 반복문을 통해 랜덤 숫자를 변수j에 저장
- SutdaCard tmp 객체에 cards배열의 i번째를 할당.
- cards배열의 i번째를 cards배열의 랜덤수j번째로 변경
- cards배열의 랜덤수j번째에 1번에서 저장된 cards배열의 i번째를 할당.(tmp객체)
- i값이 증가하면서 배열 각 자리의 값들이 바뀐다.
다음의 코드는 컴파일하면 에러가 발생한다. 그 이유를 설명하고 에러를 수정하기 위해서는 코드를 어떻게 바꾸어야 하는가?
--- 문제 코드 ---
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_3 {
public static void main(String[] args) {
Tv t = new Tv();
}
}
--- 정답 코드 ---
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_3 {
public static void main(String[] args) {
Tv t = new Tv();
}
}
- 이 문제는 단순히 기본 생성자가 없었기에 오류가 발생했던 것이다.
MyTv클래스의 멤버변수 isPowerOn, channel, volume을 클래스 외부에서 접근할 수 없도록 제어자를 붙이고 대신 이 멤버변수들의 값을 어디서나 읽고 변경할 수 있도록 getter와 setter메서드를 추가하라.
--- 문제 코드 ---
class MyTv {
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;
// (구현)
}
class Exercise7_4 {
public static void main(String args[]) {
MyTv t = new MyTv();
t.setChannel(10);
System.out.println("CH:" + t.getChannel());
t.setVolume(20);
System.out.println("VOL:" + t.getVolume());
}
}
//예상결과) CH:10 VOL:20
--- 정답 코드 ---
class MyTv {
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 int setChannel (int channel) {
// 1. 항상 유효성 검사를 먼저 하자 !
if (channel > MAX_CHANNEL || channel < MIN_CHANNEL) {
return;
}
this.channel = channel;
}
public void getChannel() {
return channel;
}
public int setVolum (int volume) {
if (volume > MAX_VOLUME || volume < MIN_VOLUME) {
return;
}
this.volume = volume;
}
public void getVolume() {
return volume;
}
}
class Exercise7_4 {
public static void main(String args[]) {
MyTv t = new MyTv();
t.setChannel(10);
System.out.println("CH:" + t.getChannel());
t.setVolume(20);
System.out.println("VOL:" + t.getVolume());
}
}
- 처음에 set get(캡슐화)을 쓰는 이유는 외부의 해킹을 막기 위함인 줄 알았다. 하지만 set get(캡슐화)은 외부에서 직집적으로 데이터에 접근하는 것을 보호하기 위함이다.
- 유효성 검사.
위 문제에서 작성한 MyTv클래스에 이전 채널(previous channel)로 이동하는 기능 의 메서드를 추가해서 실행결과와 같은 결과를 얻도록 하시오.
--- 문제 코드 ---
class MyTv {
private boolean isPowerOn;
private int channel;
private int volume;
// (구현)
private int prevChannel;
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_5 {
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
--- 정답 코드 ---
class MyTv {
private boolean isPowerOn;
private int channel;
private int volume;
// 구현
// 이전 채널 저장 변수
private int prevChannel;
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;
// (구현)
// 2. 채널 설정하는 setChannel 메서드의 이전채널 변수에 현재채널 저장.
prevChannel = this.channel;
this.channel = channel;
}
public int getChannel() {
return channel;
}
// (구현)
public void gotoPrevChannel() {
// prevChannel = getChannel();
// 3. 이전 채널을 매개변수로 setChannel 메서드에 넘긴다.
setChannel(prevChannel);
}
}
class Exercise7_4 {
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());
}
}
- 이전 채널을 저장할 변수 선언.
- 현재 채널을 설정하는 setChannel 메서드의 이전채널 변수에 현재채널 저장..
- 새로운 메서드에서 setChannel메서드에 매개변수로 이전 채널을넘겨준다.
'TIL' 카테고리의 다른 글
Usecase - 유스케이스 다이어그램 (0) | 2023.02.27 |
---|---|
자바 - 약한 결합 및 약한 의존성 (0) | 2023.02.25 |
자바 - 상속 (0) | 2023.02.22 |
자바 - 객체지향 (0) | 2023.02.21 |
Java - 조건문 그리고 반복문. (0) | 2023.02.14 |