반응형
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 + ") 공격");
}
}
반응형
'자바스프링웹공부(2024) > 자바' 카테고리의 다른 글
2024.09.20. 추상클래스, 추상메서드, final, block (1) | 2024.09.23 |
---|---|
2024.09.13. ref casting 참조형변환 (0) | 2024.09.16 |
2024.09.13. super (0) | 2024.09.16 |
2024.09.10. 상속, 오버라이드,접근제한자 (0) | 2024.09.10 |
2024.09.09.조건문 반복문 연습 (0) | 2024.09.09 |