티스토리 뷰

 

목차

1.   동적 바인딩


2.   다형성

    EX1 )   오버라이딩

    EX2 )   업캐스팅

    EX3 )   배열에 다형성 적용하기


3.   메서드에 다형성 활용


4.   총정리

 

 

 

 

 

 

 

 

 

 

📍   동적 바인딩

–   상속 관계에서 업캐스팅 후 메서드를 호출할 때,  
     컴파일(번역) 단계에서의 실행 대상과 실제 실행 단계에서의 실행 대상이 달라진 것.
–   참조변수의 타입과 무관하게 '실제 인스턴스'의 메서드를 실행하게 됨.

–   업캐스팅 시 일어나는 동적바인딩은 ctrl + click으로 해당 메서드의 출처를 알기가 힘듬.
     원래라면 참조하고 있던 메모리가 없어졌으므로 에러가 나야하는데 Java가 에러 안나게끔 길을 바꿔준 것.


EX   )

 

•   클래스 생성하기

class Parent{
public void parentPrn() {
System.out.println("슈퍼클래스의 parentPrn()");
}
}
class Child extends Parent{
public void childCrn() {
System.out.println("서브클래스의 childCrn()");
}
@Override
public void parentPrn() {
System.out.println("서브클래스에서 오버라이딩 된 parentPrn()");
}
}

–   슈퍼클래스 Parent와 이를 상속받는 Child클래스를 생성하고  각각 parentPrn(),  childCrn() 메서드를 정의함.

–   서브클래스에 슈퍼클래스의 parentPrn() 메서드를 오버라이딩 함.

 

 

•   슈퍼클래스 타입 인스턴스 생성

public static void main(String[] args) {
Parent p = new Parent();
p.parentPrn();

   실행 결과

더보기

슈퍼클래스의 parentPrn( )

 

 

•   서브클래스 타입 인스턴스 생성

Child c = new Child();
c.childCrn(); // 서브클래스에서 정의한 메서드
c.parentPrn(); // 슈퍼클래스로부터 상속받은 메서드

–   슈퍼클래스로부터 상속받은 메서드를 서브클래스에서 재정의 (오버라이딩)하면
     기본 슈퍼클래스의 메서드와 동일하게 생긴 메서드를 정의하게 되므로,
     서브클래스에서는 더 이상 슈퍼클래스의 메서드가 보이지 않음.
     →   슈퍼클래스의 메서드를 덮어쓰기 때문에 자신의 메서드만 보이게 됨. (슈퍼클래스 메서드는 은닉됨)
     →   따라서 슈퍼클래스에서 정의한 parentPrn() 메서드가 호출되지 않고, 

           서브클래스에서 오버라이딩한 parentPrn()이 호출되어 해당 출력문이 출력됨.

   실행 결과

더보기

서브클래스의 childCrn( )

서브클래스에서 오버라이딩 된 parentPrn( )

 

 

•   업캐스팅

    p = c;		// Parent p = new Child();

–   서브클래스 타입 인스턴스   →   슈퍼클래스 타입으로 업캐스팅 (Child → Parent)

      →   자식클래스 타입에서 부모클래스 타입으로 가는 것
–   Parent p가 Child c를 참조하므로 p가 참조하던 Heap영역의 인스턴스는 GC(Garbeage Collection)에 의해 제거됨.

 

p.parentPrn();
} // main() 메서드

–   Child 인스턴스의 오버라이딩 된 메서드가 호출됨.
–   메서드 호출 코드를 작성하는 시점 (컴파일 시점)에서는

     참조변수 타입인 Parent 클래스의 parentPrn() 메서드를 호출하는 코드지만,
     실제 실행하는 시점에서 참조변수에 저장된 인스턴스가 Child의 인스턴스이므로,
     실제 호출되는 메서드는 Child 타입의 오버라이딩 된 메서드가 호출됨.
     →   즉,  컴파일 단계에서의 실행 대상과 실행 단계에서의 실행 대상이 다를 수 있음.

   실행 결과

더보기

서브클래스에서 오버라이딩 된 parentPrn()

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

📍    다형성 (polymorphism)

–   하나의 데이터타입 (참조변수)로 여러 인스턴스를 참조하는 특성.
–   어떤 인스턴스를 업캐스팅하여 슈퍼클래스 타입 변수로 다루면,
     하나의 슈퍼클래스 타입으로 여러 서브클래스 타입 인스턴스를 다룰 수 있음.


 EX   )

 

•  슈퍼클래스 Shape 정의

class Shape{
public void draw() {
System.out.println("도형 그리기");
}
}

–   여러 도형의 공통점인 '그리다' 기능을 수행하는 drwa() 메서드 정의.

 

 

 

•   서브클래스 정의

class Circle extends Shape{
@Override // alt + shift + s + v
public void draw() {
System.out.println("원 그리기");
}
public void CirclePaint() {
System.out.println("원 그리기");
}
}

–   draw() 메서드를 오버라이딩 하여 "원 그리기" 출력.
     →   하나하나 메서드를 따로 지정하면 유지보수도 안좋고 나중에 내가 어떤걸 써야 할 지 헷갈림.

class Rectangle extends Shape{
@Override
public void draw() {
System.out.println("사각형 그리기");
}
public void rDraw() {
System.out.println("사각형 그리기");
}
}
class Triangle extends Shape{
@Override
public void draw() {
System.out.println("삼각형 그리기");
}
public void design() {
System.out.println("삼각형 그리기");
}
}

–   Shape 클래스를 상속받는 Circle,  Rectangle,  Triangle 서브 클래스를 정의하고,

     Shpae  클래스의  draw() 메서드를 각 서브클래스에서 오버라이딩 함.

      →   코드의 유지보수와 통일성이 향상됨.

 

 

 

•   메서드 오버라이딩 하지 않았을 경우

public static void main(String[] args) {
// Circle 인스턴스 생성
Circle c = new Circle();
c.CirclePaint();
// Rectangle 인스턴스 생성
Rectangle r = new Rectangle();
r.rDraw();
// Triangle 인스턴스 생성
Triangle t = new Triangle();
t.design();

–   클래스별로 똑같은 기능을 하는 메서드라도 이름이 다르므로 일일이 기억해야하는 번거로움이 있음.

   실행 결과

더보기

원 그리기
사각형 그리기
삼각형 그리기

 

 

 

•   슈퍼클래스의 메서드를 상속받아 오버라이딩 하는 경우

c.draw();
r.draw();
t.draw();

–   각 참조변수에 같은 이름과 기능을 하는 오버라이딩 된 메서드 하나만 호출하면 되므로 코드의 통일성이 향상됨.

   실행 결과

더보기

원 그리기
사각형 그리기
삼각형 그리기

 

 

 

•   업캐스팅

–   업캐스팅을 활용하면 코드의 통일성을 더욱 더 향상시킬 수 있음.
–   Circle,  Rectangle,  Triangle의 공통 슈퍼클래스인 Shape타입 (s)으로 세 인스턴스를 컨트롤 가능함.

// Circle → Shape 업캐스팅
Shape s = new Circle();
s.draw();

–   Circle 인스턴스를 Shape타입의 참조변수 s에 저장 (업캐스팅)하여 Circle 인스턴스의 draw() 메서드를 호출함.

// Rectangle → Shape 업캐스팅
s = new Rectangle();
s.draw();
// Triangle → Shape 업캐스팅
s = new Triangle();
s.draw();

–   마찬가지로 Shape타입의 참조변수 s에 Rectangle 인스턴스와 Triangle 인스턴스를 각각 저장 (업캐스팅)하여,

     해당 인스턴스들의 draw() 메서드를 호출함.  
   실행 결과

더보기

원 그리기
사각형 그리기
삼각형 그리기

 

 

 

•   배열에 다형성 적용하기

 

1.   저장

방법1 )   하나씩 저장하기

// Shape타입 배열 3개 생성
Shape[] sArr = new Shape[3];

–   다형성을 배열에 적용시키는 경우.
–   슈퍼클래스 타입으로 배열을 생성하여,  배열의 인덱스에 각각의 서브클래스 인스턴스 저장 가능.

    sArr[0] = new Circle();

–   Circle → Shape 으로 업캐스팅.
–   0번 인덱스에 Circle 인스턴스 생성하여 저장함.

	sArr[1] = new Rectangle();

–   Rectangle → Shape 으로 업캐스팅.
–   1번 인덱스에 Rectangle 인스턴스 생성하여 저장함.

    sArr[2] = new Triangle();

–   Triangle → Shape 으로 업캐스팅.
–   2번 인덱스에 Triangle 인스턴스 생성하여 저장함.

 

방법2 )   한번에 저장하기

	Shape[] sArr = {new Circle(), new Rectangle(), new Triangle()};

–   슈퍼클래스 타입으로 배열을 생성하여 문법에 맞게 데이터를 입력해야 할 곳에 각 서브클래스의 인스턴스를 입력함.

 

 

2.   배열 호출

방법1 )   인덱스 사용

sArr[0].draw();
sArr[1].draw();
sArr[2].draw();

–   배열의 각 인덱스에는 인스턴스 주소가 저장되므로,
     참조변수와 마찬가지로 배열명[인덱스].메서드명() 형태로 호출 가능함.

   실행 결과

더보기

원 그리기
사각형 그리기
삼각형 그리기

 

방법2 )   반복문 사용

for(int i=0; i<sArr.length; i++) {
sArr[i].draw();
}

–   반복문을 사용하여 Shape 배열 크기만큼 반복하면서 각 인덱스에 저장된 인스턴스의 draw() 메서드 호출.

   실행 결과

더보기

원 그리기
사각형 그리기
삼각형 그리기

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

📍    메서드에 다형성 활용

1.   이미 다형성이 적용된 배열을 메서드 파라미터로 전달

2.   메서드 파라미터로 인스턴스를 전달


EX   )

 

•    static 메서드 정의하기

} // main 메서드 끝
public static void polymorphismDraw(Shape[] sArr) {
for(int i=0; i < sArr.length; i++) {
sArr[i].draw();
}
}
public static void polymorphismDraw2(Shape s) {
s.draw();
}
} // Ex2 클래스 끝

–   main 메서드 아래 부분에 static 메서드를 정의함.

–   이미 다형성이 적용된 배열 (Shape s)을 polymorphismDraw() 메서드의 파라미터로 전달.

      →    Shape 배열 타입으로 줘야하므로 해당 메서드 파라미터 부분에 'Shape[] Arr'를 입력함.

–   polymorphismDraw2() 메서드에는 어떤 인스턴스가 전달되더라도 draw() 메서드는 공통으로 호출 가능함.

      →    파라미터로 정의된 Shape타입의 참조변수 s에 Circle,  Rectangle,  Triangle타입의 인스턴스를 각각 전달하면

              s에 해당 인스턴스가 저장되고,  각 서브클래스에서 오버라이딩 된 draw() 메서드가 호출됨.

              

 

•   main 메서드에서 호출하기

// 이미 다형성이 적용된 배열을 메서드 파라미터로 전달
polymorphismDraw(sArr);
// 메서드 파라미터로 각 인스턴스를 전달
polymorphismDraw2(new Circle());
polymorphismDraw2(new Rectangle());
polymorphismDraw2(new Triangle());

   실행 결과

더보기

원 그리기
사각형 그리기
삼각형 그리기

원 그리기
사각형 그리기
삼각형 그리기

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

📍   총정리

 

 

•   직원(Employee) 클래스 정의

class Employee{
String name;
int salary;
// 파라미터 생성자 정의
// alt + shift + s + o
public Employee(String name, int salary) {
super(); // Object
this.name = name;
this.salary = salary;
}
// getEmployee() 메서드 정의
public String getEmployee() {
return name + ", " + salary;
}
// 일반 직원의 연봉 계산
public void salaryCalculation() {
System.out.println("연봉 : " + salary);
}

 

 

 

•   관리자(Manager) 클래스 정의 — Employee 상속

class Manager extends Employee{
String depart; // 부서명
int manageEmployeeCount; // 관리하는 직원 수
// 기본 생성자
// public Manager() {
// super();
// }

–   기본 생성자는 이러한 형태로 생략되어 있는데,  부모클래스에 기본 생성자 정의가 되어 있지 않아 에러 발생.
      →   서브클래스가 부모클래스를 상속받기 때문에 부모클래스의 생성자가 있어야 서브 클래스도 생성 가능.

      →   바로 밑에서 파라미터 생성자로 해결하기.

 

// 파라미터 생성자
// alt + shift + s + o
public Manager(String name, int salary, String depart, int manageEmployeeCount) {
super(name, salary);
this.depart = depart;
this.manageEmployeeCount = manageEmployeeCount;
}

–   슈퍼클래스 기본 생성자가 없으므로 슈퍼클래스의 파라미터 생성자를 호출하도록 하고,
     서브클래스의 파라미터 생성자도 정의함.
–   단축키를 활용하면 슈퍼클래스의 생성자 호출과 동시에 해당 변수 초기화도 맡김. (super 패키지 설명 참조)
      →   서브클래스에서는 자기꺼만 초기화 함.

 

// getManager() 메서드 정의
public String getManager() {
return getEmployee() + ", " + depart + ", " + manageEmployeeCount;
}

–   return에 중복되는 코드를 위에 같은 코드가 리턴되는 getEmployee() 메서드로 처리함.

 

// salaryCalculation() 메서드 오버라이딩 (관리자 연봉)
// alt + shift + s + v
@Override
public void salaryCalculation() {
int salaryResult = salary + (manageEmployeeCount * 10);
System.out.println("연봉 : " + salaryResult);
}
}

–   매니저 연봉 = 기본연봉 + (관리직원 수 * 10만원) 이므로,  연봉계산 메서드를 매니저의 연봉에 맞게끔 오버라이딩 함.

 

 

 

•   엔지니어(Engineer) 클래스 정의 — Employee 상속

class Engineer extends Employee{
int numOfCertificate; // 자격증 개수
// 파라미터 생성자 정의
public Engineer(String name, int salary, int numOfCertificate) {
super(name, salary);
this.numOfCertificate = numOfCertificate;
}

–   슈퍼클래스 기본 생성자가 없으므로,

     슈퍼클래스의 파라미터 생성자를 호출하도록 하고 서브클래스의 파라미터 생성자도 정의함.

 

// getEngineer() 메서드 정의
public String getEngineer() {
return getEmployee() + ", " + numOfCertificate + "개";
}
// salaryCalculation() 메서드 오버라이딩 (엔지니어 연봉)
// alt + shift + s + v
@Override
public void salaryCalculation() {
int salaryResult = salary + (numOfCertificate * 20);
System.out.println("연봉 : " + salaryResult);
}
}

–   엔지니어 연봉 = 기본연봉 + (자격증 수 * 20만원),  연봉계산 메서드를 엔지니어의 연봉에 맞게끔 오버라이딩 함.

 

 

 

•   직원 클래스 호출하기

Employee emp = new Employee("홍길동", 3000);
System.out.println("Employee 정보 : " + emp.getEmployee());
emp.salaryCalculation();

–   Employee 클래스의 인스턴스를 생성,  파라미터 생성자에 알맞은 데이터를 입력함.

–   직원 정보를 알기 위해 참조변수명으로 해당 인스턴스에 접근하여 getEmployee() 메서드를 호출하고,

     직원의 연봉을 알기 위해 salaryCalculation() 메서드도 호출함.

   실행 결과

더보기

Employee 정보 : 홍길동, 3000
연봉 : 3000

 

 

 

•   관리자 클래스 호출하기

Manager man = new Manager("이순신", 4000, "개발팀", 3);
System.out.println("Manager 정보 : " + man.getManager());
man.salaryCalculation();

–   Manager 클래스의 인스턴스를 생성하고,  해당 파라미터 생성자에 알맞은 데이터를 입력함.

–   Manager의 정보를 알기 위해 참조변수명으로 해당 인스턴스에 접근하여 getManager() 메서드를 호출하고,

     연봉을 알기 위해 Manager의 연봉 조건에 알맞게 오버라이딩 된 salaryCalculation() 메서드도 호출함.

   실행 결과

더보기

Manager 정보 : 이순신, 4000, 개발팀, 3
연봉 : 4030

 

 

 

•   엔지니어 클래스 호출하기

Engineer eng = new Engineer("강감찬", 5000, 5);
System.out.println("Engineer 정보 : " + eng.getEngineer());
eng.salaryCalculation();

–   Engineer 클래스의 인스턴스를 생성하고,  해당 파라미터 생성자에 알맞은 데이터를 입력함.

–   Engineer의 정보를 알기 위해 참조변수명으로 해당 인스턴스에 접근하여 getEngineer() 메서드를 호출하고,

     연봉을 알기 위해 Engineer의 연봉 조건에 알맞게 오버라이딩 된 salaryCalculation() 메서드도 호출함.

   실행 결과

더보기

Engineer 정보 : 강감찬, 5000, 5개
연봉 : 5100

 

 

 

•   업캐스팅

Employee emp2 = new Engineer("박보검", 10000, 5);
System.out.println("Engineer 정보 : " + emp2.getEmployee());
emp2.salaryCalculation();

–   Engineer타입의 인스턴스를 Employee 타입의 emp2에 저장함 → 업캐스팅

–   업캐스팅이 되면서 참조변수의 범위가 좁아졌으므로,   서브클래스의 getEngineer() 메서드를 사용하지 못함.

      →   슈퍼클래스로 부터 상속받은 생성자와 메서드만 사용 가능.

   실행 결과

더보기

Engineer 정보 : 박보검, 10000
연봉 : 10100

 

 

 

•   다형성 활용

–   전 직원의 연봉을 슈퍼클래스인 Employee 클래스에서 모두 계산
      →   Employee,  Manager,  Engineer 인스턴스 모두 처리해야 하므로 다형성 필요.
      →   메서드 파라미터로 다형성을 적용한(서브클래스의 인스턴스를 모두 참조하는)
Employee타입의 레퍼런스가 필요.

      →   메서드 호출시 파라미터에 해당 서브클래스의 인스턴스를 입력하면 '업캐스팅' 됨.

class Employee{
// salaryCalculationAll() 메서드 정의
public void salaryCalculationAll(Employee emp) { // 업캐스팅 됨
int salaryResult = 0; // 연봉 계산 결과를 저장할 변수

–   참조영역의 축소로 인해 각 서브클래스 타입의 멤버변수는 보이지 않음.
     →   Employee를 제외한 Manager,  Engineer의 경우 다시 다운캐스팅을 통해 서브클래스의 멤버에 접근해야 함.
–   단,  무작정 다운캐스팅을 수행할 경우 오류가 발생할 수 있으므로

     반드시 instanceof 연산자를 통해 타입 판별 후 다운캐스팅 필요.
     →   오류가 발생하면 프로그램이 중단되므로 instanceof 연산자로 안전장치를 거는 것.

 

if(emp instanceof Manager) {
System.out.println("Employee → Manager로 다운캐스팅 가능");
Manager man = (Manager)emp;
salaryResult = man.salary + (man.manageEmployeeCount * 10);

–   emp 인스턴스는 Manager타입인가?  조건이 참이라면 다운캐스팅 가능.
–   자동형변환 불가하므로 강제형변환 필수.

–   업캐스팅으로 축소됐던 참조영역이 다운캐스팅으로 확대되었으므로,

     다운캐스팅 된 Manager 타입 인스턴스를 통해 모든 멤버 접근 가능.
      →   기본 연봉과 관리 인원 수에 따른 인센티브를 더해서 계산 가능.

 

}else if(emp instanceof Engineer) {
System.out.println("Employee → Engineer로 다운캐스팅 가능");
Engineer eng = (Engineer)emp;
salaryResult = eng.salary + (eng.numOfCertificate * 20);

–   emp 인스턴스는 Engineer타입인가?  조건이 참이라면 다운캐스팅 가능.
–   자동형변환 불가하므로 강제형변환 필수.

–   업캐스팅으로 축소됐던 참조영역이 다운캐스팅으로 확대되었으므로,
     다운캐스팅 된 Engineer 타입 인스턴스를 통해 모든 멤버에 접근 가능.
–   기본 연봉과 자격증 수에 따른 인센티브를 더해서 계산.

 

}else if(emp instanceof Employee) {
System.out.println("Employee 그대로 사용");
salaryResult = salary;
}

–   emp 인스턴스는 Employee타입인가? 조건이 참이라면 다운캐스팅 가능. 
     →   Employee 그대로 사용.
–   주의!  반드시 하위타입부터 판별을 수행해야 함.
     →   범위가 제일 큰 타입부터 조건으로 설정하면,  첫번째 if문이 무조건 참이 되므로 아래의 조건에 접근이 아예 안됨.

 

// 각 직원의 계산된 연봉 출력
System.out.println("연봉 : " + salaryResult + "만원 입니다.");
}
}

 

 

 

•   메서드 파라미터로 인스턴스 전달

emp.salaryCalculationAll(emp); // new Employee("홍길동", 3000);
emp.salaryCalculationAll(man); // new Manager("이순신", 4000, "개발팀", 3);
emp.salaryCalculationAll(eng); // new Engineer("강감찬", 5000, 5);

–   위에서 인스턴스 생성 시 파라미터 생성자에 입력한 데이터들이 인스턴스(참조변수)에 저장되었으므로

     메서드 파라미터에 해당 인스턴스를 전달해줌.

   실행 결과

더보기

Employee 그대로 사용
연봉 : 3000만원 입니다.
Employee → Manager로 다운캐스팅 가능
연봉 : 4030만원 입니다.
Employee Engineer로 다운캐스팅 가능
연봉 : 5100만원 입니다.

 

 

 

 

 

 

 

 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
글 보관함