본문 바로가기
Programming Language/Java

[국비] Java 내용정리 Day12

by tpleehan 2021. 11. 21.

다형성(Polymorphism)

  • 다형성이란 객체들이 여러 가지 형태, 즉 타입을 이용할 수 있는 성질을 말한다.
  • 자바는 다형성을 위해 객체들의 부모타입변환을 허용하고 있다. 부모타입에 모든 자식 객체를 대입할 수 있다.
  • 다형성을 이용하면 객체의 부품화를 할 수 있다.

  • 자바에선 하나의 클래스 파일에 여러 개의 클래스를 선언할 수 있고, 밀접한 연관이 있는 클래스를 모아 놓기 위해 사용한다.
  • 파일명과 동일한 클래스가 반드시 존재해야 하고 해당 클래스만 public으로 선언할 수 있다.
  • 다형성이란 자식 객체가 모든 부모의 타입을 가질 수 있다는 것을 의미한다.
  • 부모 타입 변수에 자식 객체의 주소값을 얼마든지 저장할 수 있는 것을 의미한다.
  • 상속관계가 없다면 다형성 적용이 불가능하다.
  •  다형성은 무조건 상속 관계에서만 발생한다.
  •  Object는 자바의 최상위 클래스로 모든 클래스는 Object를 상속 받고 있고, Object 타입의 변수는 어떠한 객체도 들어올 수 있다.
package poly.basic;

class A {
}

class B extends A {
}

class C extends A {
}

class D extends B {
}

class E extends C {
}

public class Basic {
	
	A a = new A();
	B b = new B();
	C c = new C();
	D d = new D();
	E e = new E();

	A v1 = new B(); // 클래스타입 B -> A타입으로 자동 형 변환(promotion)
	A v2 = new C();
	A v3 = new D();
	A v4 = new E();
	A v5 = b;

	B v6 = new D();
	C v7 = new E();

//	B v8 = new E(); (x)
//	C v9 = new D(); (x)
//	B v10 = new C(); (x)
//	D v11 = new E(); (x)

	Object o1 = new A();
	Object o2 = new B();
	Object o3 = new C();
	Object o4 = new D();
	Object o5 = new E();
	Object o6 = new String("안녕하세요.");
	Object o7 = new Basic();

}
package poly.car;

public class Car {

	Tire frontLeft;
	Tire frontRight;
	Tire rearLeft;
	Tire rearRight;
	
	void run() {
		System.out.println("자동차가 달립니다.");
	}
	
}
package poly.car;

public class Tesla extends Car {

	@Override
	void run() {
		System.out.println("테슬라가 달립니다.");
	}
	
	void enterMembership() {
		System.out.println("테슬라 멤버쉽에 가입합니다.");
	}
	
}
package poly.car;

public class Sonata extends Car {

	@Override
	void run() {
		System.out.println("소나타가 달립니다.");
	}
	
}
package poly.car;

public class Benz extends Car {

	@Override
	void run() {
		System.out.println("벤츠가 달립니다.");
	}
	
}
package poly.car;

public class MainClass {

	public static void main(String[] args) {
		
		Sonata s1 = new Sonata();
		Sonata s2 = new Sonata();
		Car s3 = new Sonata();
		
		Car b1 = new Benz();
		Benz b2 = new Benz();
		Benz b3 = new Benz();

		Tesla t1 = new Tesla();
		Tesla t2 = new Tesla();
		Car t3 = new Tesla();
		Tesla t4 = new Tesla();
		
//		s1.run();
//		s2.run();
//		s3.run();
//		b1.run();
//		b2.run();
//		b3.run();
//		t1.run();
//		t2.run();
//		t3.run();
//		t4.run();
		
//		Sonata[] sonatas = {s1, s2, s3};
//		for (Sonata s : sonatas) {
//			s.run();
//		}
		
		Car[] cars = {
			s1, s2, s3, b1, b2, b3, t1, t2, t3, t4
		};
		
		for (Car c : cars) {
			c.run();
		}
		
		System.out.println("--------------");
		
		Driver kim = new Driver();
		kim.drive(b2);
		kim.drive(s1);
		kim.drive(t2);
		
		Tesla t5 = (Tesla) kim.buyCar("테슬라");
		t5.run();
		t5.enterMembership();
//		c.run();
//		Tesla t5 = (Tesla) c;
//		t5.enterMembership();
		
		System.out.println("--------------");
		
		s1.frontLeft = new Ntire();
		s1.frontRight = new Ntire();
		s1.rearLeft = new Htire();
		s1.rearRight = new Htire();
		
		CarShop shop = new CarShop();
		shop.carPrice(s1);
		shop.carPrice(new Benz());
		shop.carPrice(kim.buyCar("테슬라"));

	}

}
package poly.car;

public class Driver {

	public void drive(Car c) {
		System.out.println("운전을 시작합니다.");
		c.run();
	}
	
	public Car buyCar(String name) {
		if (name.equals("소나타")) {
			System.out.println("소나타를 구입합니다.");
			return new Sonata();
			
		} else if (name.equals("벤츠")) {
			System.out.println("벤츠를 구입합니다.");
			return new Benz();
			
		} else if (name.equals("테슬라")) {
			System.out.println("테슬라를 구입합니다.");
			return new Tesla();
			
		} else {
			return null;
		}
	}
	
	
//	public void drive(Sonata s) {
//		System.out.println("운전을 시작합니다.");
//		s.run();
//	}
//	
//	public void drive(Benz b) {
//		System.out.println("운전을 시작합니다.");
//		b.run();
//	}
//	
//	public void drive(Tesla t) {
//		System.out.println("운전을 시작합니다.");
//		t.run();
//	}
	
}
package poly.car;

public class CarShop {

	public void carPrice(Car c) {
		
		if (c instanceof Sonata) {
			System.out.println("소나타의 가격은 2500만원 입니다.");
		} else if (c instanceof Benz) {
			System.out.println("벤츠의 가격은 5000만원 입니다.");
		} else {
			System.out.println("테슬라의 가격은 7500만원 입니다.");
		} 
		
	}
	
}
package poly.car;

public class Htire extends Tire {

}
package poly.car;

public class Ntire extends Tire {

}

강제 타입 변환(Casting)

  • 강제 타입 변환은 부모 타입을 자식 타입으로 변환하는 것을 말한다. 그러나 상속관계에서 모든 부모 타입을 자식 타입으로 바꿀 수 있는 것은 아니다.
  • 반드시 자식타입이 부모타입으로 한번 변환된 객체에 대해서만 강제 타입 변환을 사용할 수 있다.
  • 다형성 적용을 위해 자식객체가 부모타입을 갖게 되면 부모클래스에서 선언된 필드와 메서드, 그리고 자식 클래스가 오버라이딩한 메서드만 사용할 수 있는 제약사항이 생긴다.
  • 해당 문제를 해결하기 위해선 다시 자식타입으로 돌려놓는 강제 타입 변환이 꼭 필요하다.
package poly.casting;

public class Parent {

	public int n1;
	
	public void method1() {
		System.out.println("부모의 1번 메서드 호출");
	}
	
	public void method2() {
		System.out.println("부모의 2번 메서드 호출");
	}

}
package poly.casting;

public class Child extends Parent {

	public int n2; // 자식 고유의 멤버 변수
	
	
	@Override
	public void method1() {
		System.out.println("재정의한 1번 메서드 호출");
	}
	
	public void method3() {
		System.out.println("자식 고유의 3번 메서드 호출");
	}
	
}
package poly.casting;

public class MainClass {

	public static void main(String[] args) {
		
		Parent p = new Parent();
		p.n1 = 1;
//		p.n2 = 2; (x) 상속의 특징으로 부모가 자식의 내용을 참조 또는 내용을 확인 할 수 없다.
		
		p.method1();
		p.method2();
//		p.method3(); (x)
		
		System.out.println("---------------------------");
		
		Child c = new Child();
		c.n1 = 1; // 부모에게 물려받은 속성
		c.n2 = 2; // 자식 고유의 속성
		
		c.method1();
		c.method2();
		c.method3();
		
		System.out.println("---------------------------");
		
		// 다형성 적용(promotion)
		Parent p2 = new Child();
		p2.n1 = 1;
//		p2.n2 = 2; (x)
		
		p2.method1();
		p2.method2();
//		p2.method3(); (x)
		
		System.out.println("---------------------------");
				
		Child c2 = (Child) p2;
		c2.n2 = 2;
		c2.method1();
		c2.method3();
		System.out.println("p2의 주소값: " + p2);
		System.out.println("c2의 주소값: " + c2);
		
		Object o = new Parent();
//		o.method1(); (x)
//		o.n1 = 1; (x)
		
		//다형성이 한 번도 발생하지 않은 경우에는 강제 형 변환을 사용할 수 없다.
//		Parent ppp = new Parent(); (x)
//		Child c3 = (Child) ppp; (x)
		
	}

}

 

객체 타입 체크 연산자

  • 강제 타입 변환의 전제조건은 자식 타입이 부모 타입으로 변환된 경우에만 가능한데, 해당 조건을 만족하지 않은 상태로 강제타입변환을 시도하면 에러가 발생한다.
  • 부모타입을 가지고 있는 객체가 자식 객체인지 확인하는 방법은 instatnceof 연산자를 사용한다.
  • instanceof 연산자는 좌항에 객체를 우항에 타입을 지정하고 좌항의 객체가 우항의 타입인지 체크해서 맞으면 true, 틀리면 false를 리턴한다.
Warrior 변경 요구사항
1. rush라는 기술을 사용하는 사람의 이름을 적절한 키워드를 사용하여 출력
2. 이 기술을 맞는 사람의 피해량을 출력 전사는 10의 피해, 마법사는 20의 피해, 사냥꾼은 15의 피해를 각각 입는다.
3. 직업별로 다른 피해량을 instanceof 키워드를 사용하여 구분해서 출력
4. 남은 체력들도 마찬가지로 출력

Mage 변경 요구사항
1. Mage는 blizzard라는 광역 기술(메서드)을 가지고 있다.
2. Mage 클래스에 blizzard라는 메서드를 완성시킨다.
3. 메서드 호출부에 들어갈 매개값으로 알맞은 매개변수를 선언하고 광역 마법이기 때문에 타겟이 여러 명이어야 한다. 매개변수는 하나이다.
    ex) m1.blizzard(???); (배열)
4. blizzard라는 기술을 시전 하는 캐릭터의 이름을 적절한 키워드를 사용하여 출력
5. 피해량(데미지)은 10 ~ 15사이의 난수를 발생시켜서 타겟들에게 각각 적용
6. 기본 객체의 hp는 50입니다. hp에서 피해량을 뺀 남은 체력을 출력.
package poly.player;

public class Player {
	String name;
	int level;
	int atk;
	int hp;
	
	Player() {
		this.level = 1;
		this.atk = 3;
		this.hp = 50;
	}
	
	Player(String name) {
		this(); 
		this.name = name;
	}
	
	Player(String name, int hp) {
		this(name);
		this.hp = hp;
	}

	void characterInfo() {
		System.out.println("*** 캐릭터의 정보 ***");
		System.out.println("# 아이디: " + name);
		System.out.println("# 레벨: " + level);
		System.out.println("# 공격력: " + atk);
		System.out.println("# 체력: " + hp);
	}

}​
package poly.player;
	
public class Warrior extends Player {

	int rage;
	
	Warrior(String name) {
		super(name);
		this.rage = 60;
	}
	
	public void rush(Player p) {		
		System.out.println(this.name + "님이 " + p.name + "님에게 돌진을 시전 했습니다.");

		if (p instanceof Warrior) {
			p.hp -= 10;
			System.out.println(p.name + "(전사)님이 10의 피해를 입었습니다.");

		} else if (p instanceof Mage) {
			p.hp -= 20;
			System.out.println(p.name + "(마법사)님이 20의 피해를 입었습니다.");
			
		} else if (p instanceof Hunter){
			p.hp -= 15;
			System.out.println(p.name + "(사냥꾼)님이 15의 피해를 입었습니다.");
		} 
		System.out.println(p.name + "님의 남은 체력: " + p.hp);
		System.out.println("--------------------------------");
		
		/*
		String job = null;
		int damage = 0;
		if (p instanceof Warrior) {
			damage = 10;
			job = "전사";

		} else if (p instanceof Mage) {
			damage = 20;
			job = "마법사";
		
		} else if (p instanceof Hunter) {
			damage = 150;
			job = "사냥꾼";
		}
		
		p.hp -= damage;
		System.out.printf("%s(%s)님이 %d의 피해를 입었습니다.\n", p.name, job, damage);
		 */
	}
	
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 분노: " + rage);
	}
	
}​
package poly.player;

public class Mage extends Player {

	int mana;
	
	Mage(String name) {
		super(name);
		this.mana = 100;
	}
	
	Player p = new Player();
	
	public void blizzard(Player[] target) {
		System.out.println(this.name + "님이 눈보라 시전" );
		System.out.println("--------------------------------");
		
		for (Player p : target) {
			int damege = (int) ((Math.random() * 6) + 10);
			p.hp -= damege;
			
			System.out.println(p.name + "님이 " + damege + "의 피해를 입었습니다."
					+  "(남은 체력: " + p.hp + ")");
		}
	}
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 정신력: " + mana);
	}
	
}​
package poly.player;

public class Hunter extends Player {

	String pet;
	
	Hunter(String name) {
		super(name);
		this.pet = "댕댕이";
	}
	
	@Override
	void characterInfo() {
		super.characterInfo();
		System.out.println("# 펫 이름: " + pet);
	}
	
}​
package poly.player;

public class MainClass {

	public static void main(String[] args) {
		
		Warrior w1 = new Warrior("전사1");
		Warrior w2 = new Warrior("전사2");
		
		Mage m1 = new Mage("마법사1");
		Mage m2 = new Mage("마법사2");
		
		Hunter h1 = new Hunter("사냥꾼1");
		Hunter h2 = new Hunter("사냥꾼2");
		
		Player[] target = {
				w1, w2, m2, h1, h2
		};
		
		m1.blizzard(target);
	
		System.out.println("--------------------------------");
		
		w1.rush(w2);
		w1.rush(m1);
		w1.rush(h1);
		
	}

}​

 

'Programming Language > Java' 카테고리의 다른 글

[국비] Java 내용정리 Day14  (0) 2021.11.24
[국비] Java 내용정리 Day13  (0) 2021.11.23
[국비] Java 내용정리 Day11  (0) 2021.11.20
[국비] Java 내용정리 Day10  (0) 2021.11.10
[국비] Java 내용정리 Day09  (0) 2021.11.06

댓글