본문 바로가기

자바스프링웹공부(2024)/자바

2024.09.19. 형변환 polymorphism

반응형
class A {}
class B extends A {}
class C extends A {}
class D extends B {}
class E extends B {}
class F extends C {}
class G extends C {}
class H extends F {}
...
public static void main(String[] args) {
		A a =  (A)new D();
		B b = (B)a; // O 
		D d = (D)b; // O 
//		E e = (E)d; // 같은 레벨은 아예 안됨.
}

 

 

* 동적 바인딩

- 컴파일(번역) 시점에서 실행될 것으로 예상되는 코드와  실제 실행 시점에서 해당 객체의 타입 기준으로 메서드가 달라지는 것.

- 동적 바인딩 현상은 메서드에만 일어남.

	public static void main(String[] args) {
		Parent p = new Child();
		Parent p2 = new Parent();
		
		System.out.println(p instanceof Child);	// true
		System.out.println(p2 instanceof Child); // false 
		
		Child c = (Child)p;
		//Child c = (Child)p2; // (X)
		p.parentPrn();	// 결과:Override P,  parent 클래스의 메서드가 아니고 child에서 오버라이딩 된 것이 호출됨. => 동적 바인딩
		p2.parentPrn(); // 결과: P
	}
class Parent {
	public void parentPrn() {
		System.out.println("P");
	}
}
class Child  extends Parent{
	@Override
	public void parentPrn() {
		System.out.println("Override P");
	}
	public void childPrn() {
		System.out.println("C");
	}
}

 

* 동적 바인딩을 하는 이유?
- code에 통일성이 있어야 for문 돌릴 수 있따. 업캐스팅해서 배열에 넣고 for문 돌려서 출력한다.

public class Ex1 {
	public static void main(String[] args) {
//		Employee e = new Employee("홍길동", 1100);
//		System.out.println(e.getEmployee());
//		
//		Manager m = new Manager("매니저부서", "이순신", 2200);
//		System.out.println(m.getEmployee());
//		
//		Engineer eg = new Engineer("엔진기술", "강감찬", 3300);
//		System.out.println(eg.getEmployee());
		
		Employee[] emps= {
				new Employee("홍길동", 1100),
				new Manager("매니저팀", "이순신", 2200),
				new Engineer("기술팀", "강감찬", 3300)
		};
		
		for (Employee e : emps) {
			System.out.println(e.getEmployee());
		}
	}
}
class Employee {
	String name;
	int salary;
	String result;
	
	public Employee() {}
	public Employee(String name, int salary) {
		this.name = name;
		this.salary = salary;
	}
	public String getEmployee() {
		result = name  + ", " + salary;
		return result;
	}
}
class Manager extends Employee {
	String depart;
	public Manager(String depart, String name, int salary) { // 부모의 멤버변수 가지고 올때 그냥 이름만 같게 적어주면 됨. 
		super(name, salary);
		this.depart = depart;
	}
	@Override
	public String getEmployee() {
//		result = name + ", " + salary+ ", " +  this.depart; 이것도 반복해서 적을 필요가 없고 super 클래스에서 기능을 만든것을 가져오면된다.
		// super는 생성자는 상속 안받음 왜냐면 클래스 이름이 다르니까
		result = super.getEmployee()+ ", " +  this.depart ;
		return result;
	}
}
class Engineer extends Employee {
	String skill;
	public Engineer(String skill, String name, int salary) {
		super(name, salary);
		this.skill = skill;
	}
	@Override
	public String getEmployee() {
		// result = name + ", " + salary+ ", " +  this.skill ; 이것도 반복해서 적을 필요가 없고 super 클래스에서 기능을 만든것을 가져오면된다.
		result = super.getEmployee() + ", " +  this.skill ;
		return result;
	}
}

 


 

* 다형성 (Polymorphism)

- 하나의 클래스 타입 참조변수로 여러 인스턴스를 참조할 수 있는 특성 ( Employee 배열에 Manager, Engineer 다 넣음.
- 서브클래스 타입 인스턴스 들을 슈퍼클래스 타입으로 업캐스팅 하여 공통된 방법으로 여러 인스턴스의 멤버에 접근.
  ex) Employee 타입 변수로 Manager와 Engineer 인스턴스를 참조하여 각 객체 내의 메서드 (getEmployee() 등)를 공통으로 다루는 것.
- 슈퍼 클래스 타입 배열에 서브클래스 타입 인스턴스를 저장하거나   메서드 정의시 매개변수 하나에 여러타입의 인스턴스를 파라미터로 전달할 때 활용함.

public class Ex2 {

	public static void main(String[] args) {
		
		// 다형성을 최대한 활용한 PolyHero 생성
		PolyHero p = new PolyHero(200, "전사");
		Sword s1 = new Sword(200);
		p.setWeapon(s1); // 무기장착
		p.attack();
		
		Bow b1 = new Bow(1000);
		p.setWeapon(b1);
		p.attack(); // 동적바인딩으로 바꿈.
		
		p.setWeapon(new Gun(2000));
		p.attack();
		
		// 새로운 wizard 아이템이 추가되었지ㅁㄴ PolyHero 클래스를 수정할 필요가 없음.
		p.setWeapon(new Wizard(3000));
		p.attack();
		
		// Weapon의 attack() 메서드는 사용되면 안된다. 무기가 떨어지면 안되고 무기의 종류만 떨어져야한다. attack() 메서드는 있기는 있어야한다. 
		//p.setWeapon(new Weapon(100000)); // abstract 클래스 만드는 바람에 사용이 안됨.
		//p.attack();
	}
}

 class PolyHero {
	int hp;
	String nickname;
	Weapon w; 
	
	public PolyHero(int hp, String nickname) {
		this.hp = hp;
		this.nickname = nickname;
	}
	
	public void setWeapon (Weapon w) { 
		this.w = w;
	}
 
	public void attack() {
		w.attack(); 
	}
}

// Bow, Sword, Gun을 추상화한 Weapon 클래스 설계
 abstract class Weapon {
	int demage;

	public Weapon(int demage) { // 데미지 없는 것은 무기가 아니니까 무조건 damege 있어야 함.
		this.demage = demage;
	}
	/*
	 * 	// Weapon의 attack() 메서드는 사용되면 안된다. 무기가 떨어지면 안되고 무기의 종류만 떨어져야한다. attack() 메서드는 있기는 있어야한다.
	public void attack () {
		System.out.println("무기(" + demage +  ")공격"); // 동적바인딩이 되므로 무기로 공격은 아예 안나올 것이다. Weapon에 들어가는 그대로 공격이 만들어 질 것이다. 
	} 
	*/
	// 내가 원하는 attack() 메서드는 정의가 안된 attack() 메서드이다.
	public abstract void attack(); // => 추상메서드이고 abstract 를 넣으면 중괄호가 없어도 된다.
}

class Hero {
	int hp;
	String nickname;
	Bow bow;
	Sword sword;
	
	// Gun 클래스 추가후에 해야 할 일 5개
	// 1. 멤버변수 Gun 추가!
	Gun gun;
	// 
	
	// 2. setGun 추가
	public void setGun(Gun gun) {
		this.gun = gun;
		this.bow = null;
		this.sword = null;
	}
 
	public Hero(int hp, String nickname) {
		this.hp = hp;
		this.nickname = nickname;
		
	}
	public void setBow(Bow bow) { 
		this.bow = bow;
		this.sword = null;
		this.gun = null; // 3. 무기1개만 장착하니까 gun null처리
	}
	public void setSword(Sword sword) { 
		this.sword = sword;
		this.bow = null; 
		this.gun = null; // 3. 무기1개만 장착하니까 gun null처리
	}
	public void attack() {
		if(bow != null) {
			bow.attack();
		} 
		if (sword != null) {
			sword.attack(); 
		}
		// 4. attack() 메서드에 Gun 처리해야함.
		if (gun != null) {
			gun.attack(); 
		}
	}
	
	
}
class Bow extends Weapon {
/* 부모를 생성할 방법이 없으므로 에러가 난ㄷ다.
	public Bow(int demage) { 
		this.demage = demage;
	}
*/
	public Bow(int demage) {
		super(demage);
	}

	@Override
	public void attack() {
		System.out.println("활(" + demage +  ") 공격");
	}
}
class Sword extends Weapon {
	public Sword(int demage) {
		super(demage);
	}

	@Override
	public void attack() {
		System.out.println("검(" + demage +  ") 공격");
	}
}

class Gun extends Weapon{
	public Gun(int demage) {
		super(demage);
	}

	@Override
	public void attack() {
		System.out.println("총(" + demage +  ") 공격");
	}
}

// 업데이트로 지팡이 (Wizard) 추가
class Wizard extends Weapon {
	// 상속 받자마자 오류나는 거는 생성자때문이다.
	public Wizard(int demage) {
		super(demage);
	}
	@Override
	public void attack() {
		System.out.println("지팽이(" + demage +  ") 공격");
	}
}

 

반응형