Some Memos/Java
자바 객체지향프로그래밍의 이해 오버라이딩
Flashpacker
2023. 3. 2. 17:53
오버라이딩에 대해서 배워보자!
오버라이딩을 통해서 오버로딩의 한계를 극복해보자!
package ch05;
class 질럿 {
String name = "질럿";
}
class 드라군 {
String name = "드라군";
}
class 다크템플러 {
String name = "다크템플러";
}
public class OOPEx06 {
public static void main(String[] args) {
질럿 u1 = new 질럿();
드라군 u2 = new 드라군();
다크템플러 u3 = new 다크템플러();
}
}
디폴트 생성자다. 안보여도 있는 상황이다.
package ch05;
class 질럿 {
String name = "질럿";
}
class 드라군 {
String name = "드라군";
}
class 다크템플러 {
String name = "다크템플러";
}
public class OOPEx06 {
public static void main(String[] args) {
질럿 u1 = new 질럿();
드라군 u2 = new 드라군();
다크템플러 u3 = new 다크템플러();
}
}
질럿이 다크템플러를 공격할것인데 이떄 또 복사해서 사용하면서하면 오버로딩이다.
package ch05;
class 질럿 {
String name = "질럿";
void 기본공격(드라군 e1) {
System.out.println("질럿이 "+e1.name + "을 공격합니다.");
}
void 기본공격(다크템플러 e1) {
System.out.println("다크템플러 "+e1.name + "을 공격합니다.");
}
}
오버로딩이 단점이 있었다. 유닛이 많으면 많을 수록 메서드를 만들어야해서 힘들다.
그래서 저 기본공격 메서드를 통해서
드라군 과 다크템플러도 받을 수 있도록 짜면 된다.
그럴때는 다형성을 이용하면 된다.
질럿이 있고 드라군이 있고 다크템플러가 있는데!
질럿이면 질럿이니? 드라군에게 드라군이니? 다크템플러에게 다크템플러이니? 물어보면 다 네라고 하는데애네들을 추상화를 하려고한다. 추상화를 시켜서 프로토스 유닛이라고 추상화를 시켜준다.
상속(Extends)를 한다는것이다. 이 세개다 프로토스 유닛이다. 추상화를 시키면
이 세개 타입이 프로토스 유닛 타입으로 바뀐다.
그러면 new질럿을 하면 heap 메모리에 질럿 프로토스 유닛 이렇게 뜬다는것이다.
띄어보자!
package ch05;
class 프로토스유닛{
}
class 질럿 extends 프로토스유닛{
String name = "질럿";
void 기본공격(드라군 e1) {
System.out.println("질럿이 "+e1.name + "을 공격합니다.");
}
}
class 드라군 extends 프로토스유닛 {
String name = "드라군";
}
class 다크템플러 extends 프로토스유닛{
String name = "다크템플러";
}
public class OOPEx06 {
public static void main(String[] args) {
질럿 u1 = new 질럿(); // (질럿과 프로토스 유닛)
드라군 u2 = new 드라군(); // ( 드라군과 프로토스유닛)
다크템플러 u3 = new 다크템플러(); // (다크템플러와 프로토스유닛)
u1.기본공격(u2);
}
}
근데 앞에 타입이 질럿 이라고 되어있으니까 타입을 바꿔보자 다형성이니까 프로토스 유닛으로 변경할 수 있다.
그러면 주소가 바라보는것도 프로토스유닛을 바라보게 될것이다,
package ch05;
class 프로토스유닛{
}
class 질럿 extends 프로토스유닛{
String name = "질럿";
void 기본공격(드라군 e1) {
System.out.println("질럿이 "+e1.name + "을 공격합니다.");
}
}
class 드라군 extends 프로토스유닛 {
String name = "드라군";
}
class 다크템플러 extends 프로토스유닛{
String name = "다크템플러";
}
public class OOPEx06 {
public static void main(String[] args) {
프로토스유닛 u1 = new 질럿(); // (질럿과 프로토스 유닛V)
프로토스유닛 u2 = new 드라군(); // ( 드라군과 프로토스유닛V)
프로토스유닛 u3 = new 다크템플러(); // (다크템플러와 프로토스유닛V)
}
}
내가 new질럿을 하면 앞에 타입이 프로토스 유닛이면 프로토스 유닛을 바라보고 있는 것이다.
이렇게 되니까 오류가 난다.
오류가 나는 이유는 프로토스유닛은 기본공격 함수를 들고 있지 않기 떄문이다.
애는 기본공격 메소드를 가지고 있지 않다.
지금 문제가 타입을 다 일치를 시켰는데 u1은
애를 가리키고 있는데 프로토스 유닛은 아무것도 안가지고 있다.
프로토스 유닛이 기본공격이라는 메서드를 안가지고 있었는데 가지고 있다면
package ch05;
class 프로토스유닛{
void 기본공격(프로토스유닛 e1) {
System.out.println("프로토스유닛 메서드");
}
}
class 질럿 extends 프로토스유닛{
String name = "질럿";
void 기본공격(프로토스유닛 e1) {
System.out.println("질럿 메서드");
// System.out.println("질럿이 "+e1.name + "을 공격합니다.");
}
}
class 드라군 extends 프로토스유닛 {
String name = "드라군";
}
class 다크템플러 extends 프로토스유닛{
String name = "다크템플러";
}
public class OOPEx06 {
public static void main(String[] args) {
프로토스유닛 u1 = new 질럿(); // (질럿과 프로토스 유닛V)
프로토스유닛 u2 = new 드라군(); // ( 드라군과 프로토스유닛V)
프로토스유닛 u3 = new 다크템플러(); // (다크템플러와 프로토스유닛V)
}
}
그다음에 기본공격 메서드는 질럿도 가지고 있고 드라군도 가지고 있고 다크템플러도 가지고 있다.
동일한 메서드가 양쪽으로 다 있다.
부모도 들고 있고 자식도 들고 있다.
u1.기본공격(u2); 이렇게 실행을 하면 이상한 일이 일어난다?!
머가 실행이 되는가? u1은 프로토스 유닛의 기본공격을 실행하지 않고
class 질럿 extends 프로토스유닛{
String name = "질럿";
void 기본공격(프로토스유닛 e1) {
System.out.println("질럿 메서드");
// System.out.println("질럿이 "+e1.name + "을 공격합니다.");
}
애가 실행이 되었다. 이게 무엇인가? 잘기억해야한다.
부모가 들고 있는 메소드를 동일하게 자식이 적게 되면 이것을 오버라이딩이라고 한다.
오버라이드는 무효화다라는 뜻을 가지고 있는데 무엇을 무효화 하는가?
부모의 메서드를 무효화하는것이다.
오버라이드라는것은 무효화하다라는 뜻을 가지고 있다.
부모가 기본공격이라는 메서드를 가지고 있는데 자식이 똑같은 이름으로 기본공격을 가지고 있으면
부모의 메서드를 무효화 시켜버린다. 없는것 취급을 해버린다.
이것이 오버라이딩이라는 것이다.
둘다 들고 있으면 부모께 무효화 된다.
그러면 이 내부는 이제 의미가 없다.
어차피 내부가 실행될 일이 없기 떄문이다.
오류가 뜨는데 e1이 name이라는 애를 안들고 있다. 그리하여
메서드는 동일한 이름을 만들게되면 오버라이딩이 되어서 부모의 메서드를 무효화 시키지만
변수는 그렇지 않다. 변수는 자식 과 부모도 name 변수를 가지고 있으면 부모의 이름을 써버린다!
그러면 원하는 프로그램이 아니다 e1.name을 쓸떄 질럿이 나와야한다.
빈 껍데기 함수를 만들고 밑에 e1.name이 아니라 e1.이름확인
package ch05;
class 프로토스유닛{
String name = "프로토스유닛";
void 기본공격(프로토스유닛 e1) {}
String 이름확인() {
return "?";
}
}
class 질럿 extends 프로토스유닛{
String name = "질럿";
// 오버라이드 = 무효화 하다
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println("질럿이 "+e1.이름확인() + "을 공격합니다.");
}
}
class 드라군 extends 프로토스유닛 {
String name = "드라군";
}
class 다크템플러 extends 프로토스유닛{
String name = "다크템플러";
}
public class OOPEx06 {
public static void main(String[] args) {
프로토스유닛 u1 = new 질럿(); // (질럿과 프로토스 유닛V)
프로토스유닛 u2 = new 드라군(); // ( 드라군과 프로토스유닛V)
프로토스유닛 u3 = new 다크템플러(); // (다크템플러와 프로토스유닛V)
u1.기본공격(u3);
}
}
그러면 부모의 이름확인이라는 행위가 있는데 자식도 똑같은 메서드를 만들어보자
그러면 똑같은 함수가 있다면 부모의 메서드가 무효화된다.
package ch05;
class 프로토스유닛{
String name = "프로토스유닛";
void 기본공격(프로토스유닛 e1) {}
String 이름확인() {
return "?";
}
}
class 질럿 extends 프로토스유닛{
String name = "질럿";
// 오버라이드 = 무효화 하다
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println("질럿이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
class 드라군 extends 프로토스유닛 {
String name = "드라군";
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
class 다크템플러 extends 프로토스유닛{
String name = "다크템 플러";
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
public class OOPEx06 {
public static void main(String[] args) {
프로토스유닛 u1 = new 질럿(); // (질럿과 프로토스 유닛V)
프로토스유닛 u2 = new 드라군(); // ( 드라군과 프로토스유닛V)
프로토스유닛 u3 = new 다크템플러(); // (다크템플러와 프로토스유닛V)
u1.기본공격(u1);
}
}
이렇게 프로그램을 짜니까 기본공격이라는 메서드 하나로
이 사이에 추상화된 타입 프로토스 유닛을 넣기만 하면 된다.
그러면 나머지도 만들어보자
package ch05;
class 프로토스유닛{
String name = "프로토스유닛";
void 기본공격(프로토스유닛 e1) {}
String 이름확인() {
return "?";
}
}
class 질럿 extends 프로토스유닛{
String name = "질럿";
// 오버라이드 = 무효화 하다
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
class 드라군 extends 프로토스유닛 {
String name = "드라군";
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
class 다크템플러 extends 프로토스유닛{
String name = "다크템 플러";
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
public class OOPEx06 {
public static void main(String[] args) {
프로토스유닛 u1 = new 질럿(); // (질럿과 프로토스 유닛V)
프로토스유닛 u2 = new 드라군(); // ( 드라군과 프로토스유닛V)
프로토스유닛 u3 = new 다크템플러(); // (다크템플러와 프로토스유닛V)
u1.기본공격(u1);
}
}
이제 오버라이드가 되었다. 오버라이드가 되었다는 것은?
부모가 들고 있는 메서드를 자식이 똑같은것을 가지고 있다면 부모가 들고 있는 메서드를 무효화 한다.
그다음에 이상태에서 신입한테 리버라는 유닛을 하나 만들어봐(오버라이드 해서 만들어!!)
그래서 리버라는 클래스를 만들고 무엇을 오버라이드 하라는거지 하고 팀장에게 물어본다.
무엇을 오버라이드 해야하는거에요? 물어보면 리버를 프로토스 유닛으로 상속을해봐 라고하면
상속을 하여 어떤 메서드를 만들어야하나요? 라고 물어보면
공격하는 메서드와 이름을 확인하는 메서드가 필요해! 라고 이야기를 하면서
name이라는 변수를 하나 만들어서 리버를 넣으라고 하면
class 리버 extends 프로토스유닛{
String name = "리버";
void 공격 () {
}
void 이름체크() {
}
}
이렇게 만들고
이름을 확인하는거니까 String으로 해서 return name
공격은 누구를 공격하라는거지? 팀장님에게 누구를 공격하는거냐고 물어보면
전체를 공격하고 프로토스 유닛 타입을 받으라고 이야기를 들으면?
class 리버 extends 프로토스유닛{
String name = "리버";
void 공격 (프로토스유닛 e1) {
System.out.println(this.name +"이" + e1.이름확인()+"을 공격합니다.");
}
String 이름체크() {
return name;
}
}
이렇게 만들고 팀장님에게 보고를 하면?!
\
package ch05;
class 프로토스유닛{
String name = "프로토스유닛";
void 기본공격(프로토스유닛 e1) {} // 무효화됨
String 이름확인() { // 무효화됨
return "?";
}
}
class 질럿 extends 프로토스유닛{
String name = "질럿";
// 오버라이드 = 무효화 하다
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
class 드라군 extends 프로토스유닛 {
String name = "드라군";
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
class 다크템플러 extends 프로토스유닛{
String name = "다크템 플러";
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
// 신입 -> 리버라는 유닛을 하나 만들어봐(오버라이드 해서 만들어!!)
// 팀장 -> 프로토스 유닛으로 상속 ( 공격메서드 , 이름을 확인하는 메서드 필요해)
// -> name이라는 변수를 하나 만들어!! 거기에 이름을 리버라고 적어
// 누구를 공격하라는거죠? -> 프로토스 유닛 타입으로 받으면되
// 테스트해봐 -> 질럿으로 리버를 공격해봐
class 리버 extends 프로토스유닛{
String name = "리버";
void 공격 (프로토스유닛 e1) {
System.out.println(this.name +"이" + e1.이름확인()+"을 공격합니다.");
}
String 이름체크() {
return name;
}
}
public class OOPEx06 {
public static void main(String[] args) {
프로토스유닛 u1 = new 질럿(); // (질럿과 프로토스 유닛V)
프로토스유닛 u2 = new 드라군(); // ( 드라군과 프로토스유닛V)
프로토스유닛 u3 = new 다크템플러(); // (다크템플러와 프로토스유닛V)
프로토스유닛 u4 = new 리버();
u1.기본공격(u1);
u2.기본공격(u1);
u2.기본공격(u3);
u1.기본공격(u4);
}
}
그리고 결과도 질럿이 ?를 공격한다고 잘못나온다!
그래서 팀장님에게 ?가 뜬다고 말을하면?
그거 메서드 이름 머라고 적었어?
메서드 이름을 자식쪽에서 잘못 적어서 지금 오버라이드가 안된것이다.
그리하여 메서드 이름을 통일 하면
package ch05;
class 프로토스유닛{
String name = "프로토스유닛";
void 기본공격(프로토스유닛 e1) {} // 무효화됨
String 이름확인() { // 무효화됨
return "?";
}
}
class 질럿 extends 프로토스유닛{
String name = "질럿";
// 오버라이드 = 무효화 하다
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
class 드라군 extends 프로토스유닛 {
String name = "드라군";
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
class 다크템플러 extends 프로토스유닛{
String name = "다크템 플러";
void 기본공격(프로토스유닛 e1) {
//System.out.println("질럿 메서드");
System.out.println(this.name + "이 "+e1.이름확인() + "을 공격합니다.");
}
// 오버라이드 = 부모의 메서드를 무효화하다.
String 이름확인() {
return name;
}
}
// 신입 -> 리버라는 유닛을 하나 만들어봐(오버라이드 해서 만들어!!)
// 팀장 -> 프로토스 유닛으로 상속 ( 공격메서드 , 이름을 확인하는 메서드 필요해)
// -> name이라는 변수를 하나 만들어!! 거기에 이름을 리버라고 적어
// 누구를 공격하라는거죠? -> 프로토스 유닛 타입으로 받으면되
// 테스트해봐 -> 질럿으로 리버를 공격해봐
// 팀장님 ? 가 뜨는데요?
// 아 그거 너 메서드 이름 머라고 적었어? -> 이름체크
class 리버 extends 프로토스유닛{
String name = "리버";
void 공격 (프로토스유닛 e1) {
System.out.println(this.name +"이" + e1.이름확인()+"을 공격합니다.");
}
// 오버라이딩이 안됐네 -> 무효화가 안됨
String 이름확인() {
return name;
}
}
public class OOPEx06 {
public static void main(String[] args) {
프로토스유닛 u1 = new 질럿(); // (질럿과 프로토스 유닛V)
프로토스유닛 u2 = new 드라군(); // ( 드라군과 프로토스유닛V)
프로토스유닛 u3 = new 다크템플러(); // (다크템플러와 프로토스유닛V)
프로토스유닛 u4 = new 리버();
u1.기본공격(u1);
u2.기본공격(u1);
u2.기본공격(u3);
u1.기본공격(u4);
}
}