본문 바로가기

Java

[Java] 객체지향(4) 다형성 정리

 

다형성(Polymorphism)

 

하나의 레퍼런스 타입 객체가 여러 다른 타입을 수용할 수 있도록 하는 것을 다형성이라고 한다.

다형성은 상속관계과 인터페이스에서 주로 사용되고 효율적으로 프로그램을 만들 수 있도록 도움을 주면서 자바에서 매우 중요한 개념 중 하나이다.

 

자바 데이터타입 분류 체계

레퍼런스 타입 -> 변수에 객체를 가리키는 참조(주소)값이 저장

  • 다형성은 상속(인터페이스) 관계에서 상위타입의 참조변수로 하위타입의 객체를 다룰 수 있도록 한다.
  • 만약 상위 타입으로 형변환 했을 경우 하위에서 생성한 메서드는 사용이 불가하다. (오버라이딩한 메서드는 가능)
  • 하위클래스를 상위클래스로 형변환 할 경우 자동으로 캐스팅된다.
  • 반대로 상위클래스에서 하위클래스로 형변환 할 경우 강제로 캐스팅 해주어야 한다.

캐스팅 연산이 가능한지 판단하고자 할 때에는 instanceof 키워드는 사용한다.

obj2(타입을 검사할 객체) instanceof obj1(타입명)

 

  • 예제코드

전화번호부 만들기

PhoneInfo.java

public class PhoneInfo {
    private String name;
    private String phoneNo;
    private String birth;

    public PhoneInfo() {}

    public PhoneInfo(String name, String phoneNo, String birth) {
        super();
        this.name = name;
        this.phoneNo = phoneNo;
        this.birth = birth;
    }    

    public PhoneInfo(String name) {
        this.name = name;
    }

    //기능 : 1명의 전화내역 출력
    public void show() {
        System.out.println("이름 : " + name);
        System.out.println("전화번호 : " + phoneNo);
        System.out.println("생년월일 : " + birth);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhoneNo() {
        return phoneNo;
    }

    public void setPhoneNo(String phoneNo) {
        this.phoneNo = phoneNo;
    }

    public String getBirth() {
        return birth;
    }

    public void setBirth(String birth) {
        this.birth = birth;
    }
}

 

Universe.java

public class Universe extends PhoneInfo {
    private String major;
    private String year;
    public Universe() {}

    public Universe(String name, String phoneNo, String birth, String major, String year) {
        super(name, phoneNo, birth);
        this.major = major;
        this.year = year;
    }

    @Override
    public void show() {        
        super.show();
        System.out.println("학과 : " + major);
        System.out.println("학년 : " + year);
    }

    public void show2() {
        System.out.println(major + " : " + year);
    }

    public String getMajor() {
        return major;
    }

    public void setMajor(String major) {
        this.major = major;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }
}

Universe클래스는 PhoneInfo를 상속하고 있다.

 

company.java

public class Company extends PhoneInfo {
    private String dept;
    private String position;

    public Company() {}

    public Company(String name, String phoneNo, String birth, String dept, String position) {
        super(name, phoneNo, birth);
        this.dept = dept;
        this.position = position;
    }

    @Override
    public void show() {        
        super.show();
        System.out.println("부서 : " + dept);
        System.out.println("직책 : " + position);
    }

    public String getDept() {
        return dept;
    }

    public void setDept(String dept) {
        this.dept = dept;
    }

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }
  }

Company클래스는 PhoneInfo클래스를 상속하고 있다.

 

Manager.java

public class Manager {
    PhoneInfo arr[];
    Scanner sc = new Scanner(System.in);

    private int count = 0;

    public Manager() {
        arr = new PhoneInfo[10]; // 객체생성과 동시에 배열 초기화
    }

    public void addPhoneInfo() {
        // 이름, 전화번호, 생년월일 입력
        // 1.일반 2.동창(major, year) 3.직장(dept, position)

        System.out.println("메뉴를 선택해 주세요.");
        System.out.println("1.일반  2.동창  3.직장");
        String menu = sc.nextLine();

        System.out.println("이름 : ");
        String name = sc.nextLine();
        System.out.println("전화번호 : ");
        String phoneNo = sc.nextLine();
        System.out.println("생년월일 : ");
        String birth = sc.nextLine();
        switch (menu) {
        case "1":
            arr[count++] = new PhoneInfo(name, phoneNo, birth);
            break;
        case "2":
            System.out.println("학과 : ");
            String major = sc.nextLine();
            System.out.println("학번 : ");
            String year = sc.nextLine();
            arr[count++] = new Universe(name, phoneNo, birth, major, year);
            break;
        case "3":
            System.out.println("부서 : ");
            String dept = sc.nextLine();
            System.out.println("직책 : ");
            String position = sc.nextLine();
            arr[count++] = new Company(name, phoneNo, birth, dept, position);
            break;
        }
    }

    public void listPhoneInfo() {
        // 배열에 있는 모든 PhoneInfo 객체를 출력
        // show()
        System.out.println("메뉴를 선택해 주세요.");
        System.out.println("1.전체  2.동창  3.직장");
        String menu = sc.nextLine();

        switch (menu) {
        case "1":
            System.out.println("======전체======");
            for (int i = 0; i < count; i++) {
                arr[i].show();
            }
            break;
        case "2":
            System.out.println("======동창======");
            for (int i = 0; i < count; i++) {
                if (arr[i] instanceof Universe) {
                    arr[i].show();
                    Universe uni = (Universe) arr[i];
                    uni.show2();
                }
            }
            break;
        case "3":
            System.out.println("======직장======");
            for (int i = 0; i < count; i++) {
                if (arr[i] instanceof Company) {
                    arr[i].show();
                }
            }
            break;
        }

    }

    public void searchPhoneInfo() {
        // 이름의 전화번호 내역을 검색되도록 한다.
        System.out.println("이름 : ");
        String name = sc.nextLine();
        int idx = -1;

        for (int i = 0; i < count; i++) {
            PhoneInfo info = arr[i];
            if (name.equals(info.getName())) {
                info.show();
                idx = i;
            }
        }
        if (idx == -1) {
            System.out.println("찾을 수 없습니다.");
        }
      }
    }

addPhoneInfo 메서드를 보면 정보를 추가할 때 일반, 동창, 직장 서로 다른 객체를 하나의 배열안에 넣으려고 하고 있다. 하지만 자바의 다형성으로 Universe와 Company가 PhoneInfo를 상속하고 있기 때문에 PhoneInfo 상위클래스로 자동 형변환 되어 서로 공존할 수 있게 된다.

listPhoneInfo 메서드를 보면 조건문에서 instanceof 키워드를 통해 타입을 검사하고 동창이면 동창만 직장이면 직장만 출력될 수 있도록 하였다.

Main.java

import java.util.Scanner;
  public class Main {
  public static void main(String[] args) {
      // 1.추가 2.출력 3.종료
      Scanner sc = new Scanner(System.in);
      Manager m = new Manager();

      while (true) {
          System.out.println("1.추가  2.출력  3.검색  4.종료");
          System.out.println("선택 : ");
          String menu = sc.nextLine();

          switch (menu) {
          case "1":
              m.addPhoneInfo();
              break;
          case "2":
              m.listPhoneInfo();
              break;
          case "3":
              m.searchPhoneInfo();
              break;
          case "4":
              System.out.println("프로그램 종료");
              return;
          } //end switch
      } // end while
  } //end main()
}