열심히 끝까지

디바이스 융합 자바(Java) day11 - toString,instanceof,포켓몬 본문

디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(수업내용)

디바이스 융합 자바(Java) day11 - toString,instanceof,포켓몬

노유림 2022. 6. 21. 17:09

[지난 수업] + 과제
강사님 방법
누적금액의 제한 = limit

package class01;
// 1. 요구사항(조건)을 파악
class Card{ // extends Object
	String name; // 이름
	int money;
	boolean flag;
	int limit;
	void pay(int money) {
		if(this.flag && this.money + money > this.limit) { // 뉘양스 차이 + 이렇게 표현해주는 것이 좋다.
			// 제한금액이 있고 제한 금액을 넘길 경우
			this.alert();
			return; // 함수 즉시 종료
		}
		// A만큼 결제해야하고,
		// 총 누적 사용량(B)에 더해서 새로 저장
		// B = B + A => B += A
		this.money += money; // 기본 로직
		System.out.println(this.name + "님 결제완료. 누적 사용금액 : " + this.money);
	}
	void alert() {
		System.out.println(this.name + "님, 제한금액을 초과하여 사용할 수 없습니다!");
	}
	Card(String name){
		this(name, 0); 
		// 구분을 하고 싶다면 -1로 주면 된다. -> 학생부에서도 쓰인다
		this.flag = false; // 나중에 놔두어야 한다.
	}
	Card(String name, int limit){
		this.name = name;
		this.flag = true;
		this.money = 0; // 안해도 괜찮지만 가독성이 떨어지기 때문에 작성(거의 99% 쓴다)
		// 쓰는 것을 권장!!!
		this.limit = limit;
	}
	@Override
	public String toString() { // 유지보수에는 좋은 코드
		String msg = this.name + "님 현재까지 사용한 금액은 ";
		msg += this.money + "원입니다. 제한금액 ";
		if(flag) {
			msg += "O : " + this.limit + "원";
		}
		else {
			msg += "X";
		}
		return msg;
	}
}
class CreditCard extends Card{ // 부모에게 기본생성자가 없으면 및줄이 그어짐
	// 기본생성자를 추가해주면 되지만 다 짜놓은 코드를 다시 짜기에는 효율성 떨어짐
	int cnt;
	@Override // 이 것을 넣어주는 것이 오버라이딩 됬다는 것을 알 수 있게 되는 계기
	// 넣을 것을 추천
	void alert() {
		super.alert();
		this.cnt++;
		System.out.println("총 [" + this.cnt + "회 경고]");
	}
	CreditCard(String name, int limit){ 
		// 위에 있었던 문제가 알고보니 생성자 문자였다!! 라는 뜻
		// 빨간줄이 아래로 내려왔기 때문에!
		super(name, limit); // 부모클래스에게 기본생성자가 없으니까,
		// 가지고 있는 생성자를 호출하여 사용할 예정!
		this.cnt = 0;
	}	
}
class BusCard extends Card{
	int age;
	int check() {
		int fare = 0;
		if(12 < this.age && this.age < 20) {
			fare = 1000;
		}
		else if(19 < this.age && this.age < 66) {
			fare = 2000;
		}
		return fare;
	}
	// 오버라이딩 : 상속관계 / 메서드 시그니쳐가 같을 때 / 함수 재정의
	// 오버로딩 : 상속관계도 아니고 / 메서드 시그니쳐가 다를 때 / 함수명 중복정의 허용
	void pay() { 
		this.pay(this.check()); // 주어가 있어야 한다!! 
		// 본인이 수행하기 때문에 this.로 지정!!!
		// 나이에 맞게 교통요금을 결제
		// 근데 기존의 결제는 pay(???)로 진행
	}
	BusCard(String name, int age){
		this(name, age, 0);
		this.flag = false;
	}
	BusCard(String name, int age, int limit){
		super(name, limit);
		this.age = age; // 이상한 값
		if(this.age < 0 || 200 < this.age) { // 여기서는 이상한 값이 저장될 수도 있다!
			// age가 여기서 멀쩡해진다
			age = 20; // t
		}
		this.age = age; // 사용자를 위해서는 if문 안이 아닌 밖에서 정의해주는 것이 좋다. 
	}
}
public class Test01 {
	public static void main(String[] args) {
		Card c1 = new Card("아무무");
		Card c2 = new Card("아리", 5000);
		c1.pay(100000);
		c2.pay(3000);
		c2.pay(4000);
		System.out.println(c1);
		System.out.println(c2);
		System.out.println();
		CreditCard cc = new CreditCard("티모", 2000);
		cc.pay(1000);
		System.out.println(cc);
		System.out.println();
		BusCard bc1 = new BusCard("나르", 13, 500);
		BusCard bc2 = new BusCard("가렌", 250);
		bc1.pay();
		bc2.pay();
		System.out.println(bc1);
		System.out.println(bc2);
	}
}

그림

 

BusCard if문으로 짜게 되면 나는 예시..

사람이 돈을 벌었는데 쓸 시간이 없었다...
=> 과금을 하시는 편이다..
아이템 : 100보석
100 : 1000원
250 : 2000원
500 : 3000원

3000원 -> 500보석
               400보석 -> 아이템

 

[오늘 수업]

최상위 클래스
toString()
.equals()
클래스
@Override ~ ***오늘의 수업 부분***~
- Object 부분을 Card로 바꾸는건 안된다!
- 부모가 가지는 거랑 메서드 시그니쳐가 같아야 하는데 시그니쳐를 바꿔서
- 문제발생!(오버라이딩이 큰 힌트!)
  public boolean equals(Object obj) {

   1. 매개변수에 name 변수가 없는 타입을 input으로 받으면??
             Card card에 에러 발생!
             그렇기에 질문을 해야 한다!
                  >> 비교대상 너, Card가 될 수 있는 객체니?
                        Card가 될수 없다면... 넌 무조건 false야!
           if(obj instanceof Card) { => object가 Card가 될 수 있는가?만 생각
                      >>> 객체 instanceof 클래스
                             의미 >> 앞의 객체가 클래스가 될 수 있니?

  2. name에 빨간줄??
          >> object에 name을 가지고 있긴 한데 숨겨져있어서 쓸 수 없다!
          >> 멤버변수가 없기 때문!
               Card card = (Card)obj; => 형변환(타입캐스팅 -> 다운캐스팅)
               if(this.name.equals(card.name)) { => 내 이름과 비교대상의 이름이 같다면
                      return true;
               }
       }
       return false;
}
main 문
Card c3 = new Card("아무무");
Card c1 = new Card("아무무");

     ***오늘의 수업 부분***
  == : 연산자 -> 원시타입에 활용
  .equals() : Object가 제공하는 메서드
  원래 제공하는 메서드가 주소값을 봐버리는 로직을 가지고 있다
          >> 객체가 실제로 저장된 주소값을 비교하는 로직
               내 입맛에 맞게 재정의!
              객체비교 -> Object 비교
         if(c1.equals(c3)) { // 객체 비교 -> object 비교 -> 
                 System.out.println("같다!");
          }
          else {
                System.out.println("다르다!");
          }
--------

1. 오전내용 정리
2. equals()
3. "???" >> (진행 전에)예제 폭넓게 많이 쓰이는 예제(웹개발에서도 쓰임)

>> 2차원 배열 혹은 3차원 배열은 로직에서 잘 쓰이지 않는다.
           - 복잡하다고한다.

상황 이해
Mon[ o  o  o  o  o  o ]
o <- 피카츄, 파이리, 꼬부기, 치코리타, 리자몽,..

포켓몬 - 상위 클래스

피카츄 파이리 꼬부기 치코리타 ...
피카츄[] data = new 피카츄[3]; X
포켓몬[] data = new 포켓몬[3]; O
data[0] = new 피카츄();
data[1] = new 파이리();
피카츄와 파이리는 포켓몬의 상위클래스로 구성되어 있다.

포켓몬
String name => 고민해서 알아서
int level -> 5~9중에서 랜덤으로 생성
int exp = 0
void action()
     -> ㅁㅁ가 ㅁㅁ공격!
     -> 공격에 성공률 80% 실패 20%
     -> 공격 성공시 경험치를 10~210 랜덤으로 상승
          공격 실패시 level--
     -> 경험치는 100될때마다 1 level
     -> level 1미만 불가능 
     공격 성공실패 여부 / 성공시 획득 경험치 출력
=> 모듈화

피카츄
"피카츄"
void action()
     -> 피카츄가 백만공격!

파이리
"파이리"
void action()
     -> 파이리가 불꽃공격!

피카츄 p1 = new 피카츄();
파이리 p2 = new 파이리();

포켓몬에 생성자에 이름을 설정했다면 피카츄에 피카츄 설정
ex ) Pokemon(){
            this.name = "포켓몬스터";
      }
      Pikachu(){
            this.name = "피카츄";
      }
      

구조(요구상황)을 보고
1. 생성자를 결정할 수 있었어야 한다. 틀린건 아니지만 비효율적
2. 모듈화할 수 있는가?
3. 오버라이딩이라는 것을 인지하고 우클릭 소스(source)를 만들 수 있는가?

package class04;
import java.util.Random;
class Pokemon{
	String name; // => ☆
	int level;
	int exp;
	void action() {
		System.out.println(this.name + "이(가) ㅁㅁ공격!");
		if(this.check()) {
			this.success();
		}
		else {
			this.fail();
		}
	}
	boolean check() {
		Random rand = new Random();
		int num = rand.nextInt(5);
		if(num == 0) {
			return false;
		}
		return true;
	}
	void success() {
		Random rand = new Random();
		int num = rand.nextInt(201) + 10; // 10 ~ 210
		int exp = rand.nextInt();
		this.exp += exp;
		while(this.exp >= 100) {
			this.exp -= 100;
			this.level++;
			System.out.println(this.name + ", 레벨 업!");
		}
		System.out.println(this.name + " 공격 성공! 획득 경험치 " + exp);
	}
	void fail() {
		System.out.println(this.name + "공격 실패");
		if(this.level == 1) {
			System.out.println("레벨은 1미만이 불가능합니다.");
			return;
		}
		level--;
	}
	Pokemon(String name){
		this.name = name;
		Random rand = new Random();
		this.level = rand.nextInt(5)+5;
		this.exp = 0;
	}
}
class Pikachu extends Pokemon{
	@Override
	void action() { // 오버라이딩
		System.out.println(this.name + "이(가) 백만볼트!");
		if(this.check()) {
			this.success();
		}
		else {
			this.fail();
		}
	}
	Pikachu(){
		super("피카츄");
	}
}
class Pieri extends Pokemon{
	@Override
	void action() {
		System.out.println(this.name + "이(가) 불꽃공격!");
		if(this.check()) {
			this.success();
		}
		else {
			this.fail();
		}
	}
	Pieri(){
		super("파이리");
	}
}
public class Test02 {
	public static void main(String[] args) {
		Pikachu pika = new Pikachu();
		System.out.println(pika);
	}
}

 

다음 요구 사항

1. 파이리 완성

2. syso(객체);

package class04;
import java.util.Random;
class Pokemon{
	String name; // => ☆
	int level;
	int exp;
	void action() {
		System.out.println(this.name + "이(가) ㅁㅁ공격!");
		if(this.check()) {
			this.success();
		}
		else {
			this.fail();
		}
	}
	boolean check() {
		Random rand = new Random();
		int num = rand.nextInt(5); // 성공 80%, 실패 20%
		if(num == 0) {
			return false;
		}
		return true;
	}
	void success() {
		Random rand = new Random();
		int exp = rand.nextInt(201) + 10; // 10 ~ 210
		this.exp += exp;
		while(this.exp >= 100) {
			this.exp -= 100;
			this.level++;
			System.out.println(this.name + ", 레벨 업!");
		}
		System.out.println(this.name + " 공격 성공! 획득 경험치 " + exp);
	}
	void fail() {
		System.out.println(this.name + "공격 실패");
		if(this.level == 1) {
			System.out.println("레벨은 1미만이 불가능합니다.");
			return;
		}
		level--;
	}
	Pokemon(String name){
		this.name = name;
		Random rand = new Random();
		this.level = rand.nextInt(5)+5;
		this.exp = 0;
	}
	@Override
	public String toString() {
		String msg = this.name + " ";
		msg += "Lv." +this.level + " ";
		msg += "[" + this.exp + "/100]";
		return msg;
	}
}
class Pikachu extends Pokemon{
	@Override
	void action() { // 오버라이딩
		System.out.println(this.name + "이(가) 백만볼트!");
		if(this.check()) {
			this.success();
		}
		else {
			this.fail();
		}
	}
	Pikachu(){
		super("피카츄");
	}
}
class Pieri extends Pokemon{
	@Override
	void action() {
		System.out.println(this.name + "이(가) 불꽃공격!");
		if(this.check()) {
			this.success();
		}
		else {
			this.fail();
		}
	}
	Pieri(){
		super("파이리");
	}
}
public class Test02 {
	public static void main(String[] args) {
		Pikachu pika = new Pikachu();
		pika.action();
		pika.action();
		pika.action();
		pika.action();
		pika.action();
		System.out.println(pika);
	}
}

- 접근제어자
   public은 어느 누구나 볼 수 있다.(부모보다 좁은 공개범위를 갖는 것이 문법 오류)
   private는 공개범위가 작아지면 같이 작아져서..(캡슐화할 때만 빼고 이때는 private)
   public을 안 건거는 디폴트상태, 이후에 사라질 예정
   현업에서는 public을 걸 상태 지금은 구조를 볼 것