0621
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | class Card{ String name; int money; boolean flag; int limit; void pay(int money) { if(this.flag && this.money+money>this.limit) { this.alert(); return; } this.money+=money; System.out.println(this.name+"님 결제완료. 누적사용금액: "+this.money); } void alert() { System.out.println(this.name+"님, 제한금액을 초과하여 사용할수없습니다!"); } Card(String name){ this(name,0); this.flag=false; } Card(String name,int limit){ this.name=name; this.flag=true; this.money=0; this.limit=limit; } } 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()); } BusCard(String name,int age){ this(name,age,0); this.flag=false; } BusCard(String name,int age,int limit){ super(name,limit); if(age<0||200<age) { age=20; } this.age=age; } } | cs |
해당 코드는
Card (부모)
CreditCard (자식)
BusCard (자식) 으로 만들어진 코드이다
그중에서 현재의 사용금액 및 금액제한이있는 카드인지
확인할 출력문구를 만들기 위하여 toString을 오버라이딩하여 사용해보겠다
toString() 의 오버라이딩
1 2 3 4 5 6 7 8 9 10 11 12 | @Override public String toString() { String msg=this.name+"님"; msg+="현재까지 사용한 금액은 "+this.money+"원입니다"; if(this.flag) { msg+="제한금액 O: "+this.limit+"원"; } else { msg+="제한금액 X"; } return msg; } | cs |
해당코드는 부모클래스인 Card클래스 안에 넣을 코드이다
단축키 Alt + Shift + S 를 이용하여 Override를 활용했으며
Object 안에있는 toString ( )을 오버라이딩했다
toString을 오버라이딩하는 이유
- 출력하기위한 메소드인 System.out.println(); 의 괄호안에는
.toString()이 기본적으로 자동입력이 생략되어 있기 때문이다. - 항상 .toString() 이라는 메소드가 사용되어있던것이다
즉, 객체명을 syso(); 괄호안에 넣게되면 자동적으로
객체명.toString() 을 하고있었던 것이다 - showInfo의 메소드를 만드는 수고를 덜고 출력하기 간편해지기 때문
그래서 toString() 를 Card안에서 오버라이딩하여
내용을 내가 원하는 출력물로서 만들어주게 된다면
Card의 객체는 객체이름만 System.out.println(); 괄호안에 넣어주면
toString을 오버라이딩한 내용이 나오게 할 수 있기때문이다
기본적으로 카드사용자의 이름과 사용한 금액을 출력하고 싶기때문에
String msg = this.name+"님"; - 이름부분
msg+="현재까지 사용한 금액은 "+this.money+"원입니다"; - 결제부분
이후 if의 조건으로 this.flag를 사용하여 제한있는카드인지 - 금액제한부분
flag변수에 맞는 출력문구 변화를 주었다
처음엔 String msg = 안에 전부 때려박았지만
"가독성"의 중요성 때문에 msg+= 를 이용하여 **
이름부분, 사용금액부분, 제한카드부분을 나눠서 표현을 하도록 하자
equals() 의 오버라이딩
1 2 3 4 5 6 7 8 9 10 | @Override public boolean equals(Object obj) { if (obj instanceof Card) { Card card =(Card)obj; if(this.name.equals(card.name) ) { return true; } } return false; } | cs |
해당코드는 부모클래스인 Card클래스 안에 넣을 코드이다
단축키 Alt + Shift + S 를 이용하여 Override를 활용했으며
Object 안에있는 equals ( ) 을 오버라이딩했다
if ( obj instanceof Card )
일단 instanceof를 사용하는 목적을 알아야한다!
객체와 객체를 비교하기위해서 사용하는 것이기때문에
클래스객체(호출한 주어객체)와 비교할수있는 대상인지를 확인하기위해 사용함
instanceof 사용법
객체 instanceof 클래스
- 객체가 해당 클래스를 표현가능한 객체라면 true
객체가 해당 클래스를 표현불가능한 객체라면 false - 객체가 클래스의 자식이라면 해당 클래스도 true가 나온다!
해당 클래스를 모두 가지고 있기때문이다
Card card = (Card)obj;
동일한 타입의 객체가 맞다면 해당 클래스로 형변환 하여 사용
형변환 이후 입력한객체.name을 찾을 수 있기 때문
- 입력받은 Object 클래스안에 있는 obj 라는 객체이름은
.equals 앞에 적은 Card의 객체안의 이름을 비교하기위한
input값으로 입력한 Card.name을 가지고 있지않다
한마디로 Object obj 는 Card와 동일객체타입이 아니라는 뜻
- Card클래스의 name이 동일한지 비교하기 위한 오버라이딩이다
- Card 클래스에서 사용할 메소드이기에 동일하게 비교하기위하여
Card 클래스로 자료형을 맞춰주기 위해 "다운 캐스팅" 해주는 작업이다
오브젝트 (최상위 부모) 클래스가 ㅡ> Card (자식) 으로 캐스팅
- Card클래스의 name이 동일한지 비교하기 위한 오버라이딩이다
- 그렇게 캐스팅된 (Card)obj를 Card클래스의 객체 card에 넣을 것이다
- 이 변형된 card라는 객체는 input 으로 입력받은 Card의 객체를 담을 수 있게 된다
if ( this.name .equals (card.name) )
- this.name은 메소드를 사용할 객체의 이름을 가져오고
즉, bc1.equals() ;이라면 bc1 의 this.name을 가져올것이다 - .equals 는 Object의 String값을 비교해주는 .equals 이다
- card.name은 비교할 객체를 Object obj로 담아와서
다운캐스팅을 하여 Card클래스의 객체 card에 변형한 obj 객체를 넣어
input에 입력한 객체의 name을 가져올 것이다.
그 이후 this.name(String) . equals( card.name(String) )의 비교로
이때 사용된 .equals는 Object의 String 끼리 같은지 확인하는 메소드이다
true가 나온다면 return true;
false가 나온다면 return false; 로 output을 줄것이다
결과적으로 Card 클래스에서 오버라이드한 .equals의 뜻은
같은클래스인 Card (자식포함) 의 주어객체끼리의 this.name이 같은지?
같다면 true 다르다면 false를 주는 메소드로 재정의 한것이다
toString과 equals는 오버라이딩 되면앞에 public이 붙어야 사용할 수 있다
그 이유는, 부모의 공개범위를 줄일 수 없기때문이다public을 쓰지않으면 default가 기본값이기에 더 줄이는 코드가 된다그렇기 때문에 public을 넣어주어야 된다!
심화문제
포켓몬문제 코드
강사님의 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | package class02; 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; } this.level--; } Pokemon(String name) { this.name = name; Random rand = new Random(); this.level = rand.nextInt(5) + 5; this.exp = 0; } @Override public String toString() { // toString을 오버라이딩 (재정의) // showInfo메소드처럼 사용하기 위해 String msg = "당신의 포켓몬 이름은 "+this.name+" 입니다\n"; msg += this.name+"의 현재 레벨은 : "+this.level+" 입니다\n"; msg += this.name+"의 현재 경험치는 : "+this.exp+" 입니다\n"; return msg; } } class Pika extends Pokemon { @Override void action() { System.out.println(this.name + "이(가) 백만볼트공격!"); if (this.check()) { this.success(); } else { this.fail(); } } Pika() { super("피카츄"); } } class Fai extends Pokemon { Fai() { super("파이리"); } @Override void action() { System.out.println(this.name + "이(가) 불꽃공격!"); if (this.check()) { this.success(); } else { this.fail(); } } } | cs |
나의 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | package class02; import java.util.Random; class Poketmon { static Random r = new Random(); String name; int level; int exp; Poketmon(String name) { this.name = name; this.level = r.nextInt(5) + 5; // 5~9중 랜덤대입 this.exp = 0; // 0으로 시작 } boolean persentage() { int percentage = r.nextInt(5);// 성공 80% 실패 20% if (percentage == 0) { // 실패경우 20% return false; // 실패 } else { return true; // 성공 } } void action() { System.out.println(this.name + "가 일반공격합니다"); this.attack(); } void attack() { // 전투상황 성공시, 실패시 if (persentage()) { // 성공이라면 true System.out.println("공격에 성공하셨습니다"); int expUp = r.nextInt(201) + 10; // 10~210을 나타내줄 랜덤수 System.out.println("exe : " + expUp + "만큼 상승하셨습니다"); this.exp += expUp; while (this.exp >= 100) { // 100단위로 레벨을++ 해주는 반복문 this.exp -= 100; level++; System.out.println("레벨이 1 상승하였습니다!"); } System.out.println("현재레벨은 : " + this.level + "입니다"); } else { // 실패라면 false System.out.println("공격에 실패하셨습니다"); if (level > 1) { level--; System.out.println("현재레벨 : Lv." + this.level + " 입니다"); return; } System.out.println("레벨이 1 입니다 더이상 내려가지 않습니다"); } } } class Pikachu extends Poketmon { Pikachu() { super("피카츄"); } void action() { System.out.println(this.name + "가 백만볼트 공격!"); this.attack(); } } class Charmander extends Poketmon { Charmander() { super("파이리"); } void action() { System.out.println(this.name + "가 불꽃 공격!"); this.attack(); } } } } | cs |
나와 다르게 생각한점 및 강사님의 센스차이
ㅡ> 위에서 부터 보이는대로 느낀점 및 정보를 적어내림
- 보편적으로 클래스의 생성자는 아래에 메소드는 위에 정리한다
- 성공 80% 실패 20%를 boolean값으로 돌려주는 메소드
- 랜덤수를 나는 2/10 으로 표현했지만 강사님은 1/5로 표현
- 그리고 조건문을 나는 ( num < 8 ) 이라면 true 이런식이였는데
강사님은 (num == 0) 이라면 return false;
else 안쓰고 바로 return true; 로 쓰셨다
ㅡ> else 사용시에 유의해야한다
다른 조건이 있나? 로 볼수 있기 때문이다
- 랜덤수를 나는 2/10 으로 표현했지만 강사님은 1/5로 표현
- 모듈화를 하여 메소드들을 나눠주는 센스
- 나는 attack()이라는 메소드로 성공, 실패를 한꺼번에 넣음
강사님은 succecss()시, fail()를 나눠놓고 사용하셨다
성공과 실패를 나눠놓으므로서 "가독성" 및 "수정"이 유리
- 나는 attack()이라는 메소드로 성공, 실패를 한꺼번에 넣음
- 성공시 경험치를 랜덤으로 획득하고 100단위로 넘어갔을경우 레벨업
- 나는 .. exp*1.0/100 을 double lv의 변수로 담아서
this.level += (int) lv - 소수점은 날아가니까
this.exp = (int)( lv - (int) lv)*100 - 소수 *100 해서 다시대입
간단하게 강사님은
while ( exp >= 100 )
this.exp -= 100; this.level++; 로 가볍게 돌리셨다
이러한 생각을 할수 있는 센스를 갖도록 하자
- 나는 .. exp*1.0/100 을 double lv의 변수로 담아서
- void action()을 오버라이딩 할때
- 나는 코드작성해서 사용했지만 이제 이런부분은
도구를 이용하여 만들고 작성하도록하자
ㅡ> 시간절약 및 도구사용 익숙해지기
- 나는 코드작성해서 사용했지만 이제 이런부분은
- toString을 내용을 쓸때의 센스
- 줄줄이 "당신의 ~ 뭐는~ "을 적어서 대입했지만
강사님은 필요한부분만 잘라서 야무지게 대입하셨다
나도 야무지게 잘라서 msg += 대입하도록 하자
- 줄줄이 "당신의 ~ 뭐는~ "을 적어서 대입했지만
끝나고 과제 풀이 (심화)
사용자에게 포켓몬이름을 받고 (String)
해당 포켓몬이 포켓몬배열안에 몇마리 있는지 출력하기
(.equals 오버라이딩을 이용하시라고 하셨음)
메인메소드 안
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Pokemon[] data=new Pokemon[3]; data[0]=new Pika(); data[1]=new Pika(); data[2]=new Fai(); System.out.println("궁금하신 포켓몬의 이름은 : "); String name = sc.nextLine(); int a = 0; for(int i = 0; i<data.length; i++) { if(data[i].equals(name)){ a++; } } System.out.println(name+"포켓몬은 "+a+"마리 있습니다!"); | cs |
포켓몬 클래스 안
1 2 3 4 5 6 7 8 9 | @Override public boolean equals(Object name) { String pokemon = (String)name; if(this.name.equals(pokemon)) { return true; } return false; } | cs |
사용자에게 입력을 받아야기에 스캐너를 만들어놓고
입력값을 name 변수에 담아 두었다
이제 equals를 이용하여 비교하고 true라면을 출력해보자
오버라이딩을 해야하므로 오른클릭에서 equals를 오버라이드
( 도구사용에 익숙해지기 )
오버라이딩은 인풋값이 바뀌면안된다
바뀌게 되면 그것은 오버라이딩이 아닌 오버로딩이 되어버린다
인풋값을 Object 클래스로 유지해야하므로 Object name으로 담아둔다
객체 instanceof 클래스
꼭 쓸필요는없다!
사용하지 않는 이유를 확실히 알아야하는데 이번 equals 에선
해당객체가 클래스를 넣을수있는 객체인지
확인할 이유가없기때문에 사용하지 않은것이다!
객체 . equals ( String ) 이기 때문에
String pokemon = (String)name 으로 타입캐스팅하여
name은 지금 Object name
String pokemon라는 변수에 담아두고
형변환까지 거치고 만들어진 pokemon (String)을
주어 this.name (해당 메소드를 사용한 객체의 이름)와 비교하는 것이다
라고 생각했는데 굳이 타입캐스팅해주지 않고
this.name.equals(name.toString) 으로 toString의 의미인
name을 String으로 바꿔서 바로 사용가능했다!
게다가 toStirng은 생략되어있기때문에 적지않아도 가능하다!
println(), .equals() 에는 괄호안에 "객체"가 들어오면
뒤에 .toString을 자동 호출해준다 (변수는 당연히 안됨)
this.name.equals(name)
this.name = 사용한 객체의 name값이기에
ex) "피카츄".name.equals(name)
느낌이 되겠고 입력한 String값과 동일하다면
return true를 해주고 동일하지않다면
return false를 해주면 될 것이다.
이제 pokemon클래스의 객체를 주어로 .equals를 사용하면
오버라이딩된 .equals가 사용이 될텐데
이를 배열객체와 입력값을 비교하여 사용하면되기에
배열을 이용하기 좋은 for문을 이용하여
배열객체들을 모두 .equals로 비교하고
마리수를 저장해줄 변수int a = 0; 만들고
true라면 a++; 하고
false라면 지나가는 조건문을 완성시킨다면
이후 출력으로 "name 포켓몬은 a 마리 입니다"로 표현할수 있을것이다
name = "사용자에게 입력받은 포켓몬 이름"
더 나아가 0마리일경우엔 다른출력문을 넘길수도 있겠다!
- 이때, main에서 사용할 메소드로 static int pokemon( 배열 , 이름 ) 을 받아
포켓몬은 몇마리있는지 표현해주는 메소드를 만들었었는데
실무에서는 크게 쓰이진않을것이라 하셨고 하지만, 칭찬은 받았고
결국 굳이 그렇게 만들필요는 없는 메소드였다
'자바(JAVA)' 카테고리의 다른 글
(12) 인터페이스 (0) | 2022.06.22 |
---|---|
(11) 클래스의 다형성, 추상클래스 (0) | 2022.06.22 |
(9) 접근 제어자(캡슐), 상속 (0) | 2022.06.20 |
(8) 퀵정렬 (0) | 2022.06.19 |
(7) 클래스 (0) | 2022.06.15 |