09009

[Java] 다형성, 오버라이딩 (1) 본문

Back-End/JAVA
[Java] 다형성, 오버라이딩 (1)
09009

다형성

• 하나의 인터페이스를 사용하여 다양한 구현 방법을 제공

하나의 클래스나 함수가 다양하게 동작하는 것

하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것

  -   조상클래스 타입의 참조변수로 자손 클래스의 인스턴스 참조 가능

 


오버라이딩

조상클래스로부터 상속받은 메서드의 내용을 상속받는 클래스에 맞게 변경하는 것

 

 

 


오버라이딩의 조건

•  선언부(이름, 매개변수, 반환타입)가 같아야 한다.

•  조상 클래스를 오버라이딩하는 자손 클래스의 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.

   - 조상 클래스에 있는 메서드의 접근 제어자가 protected라면,

    이를 오버라이딩하는 자손 클래스에 정의된 메서드의 접근 제어자는 범위가 같거나 넓은 protected이거나 public이어야 한다.

• 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.

 

 

오버라이딩의 예시

✍ Shape.java

package ch08;
public class Shape {
	void draw() {
		System.out.println("그린다");
	}
}

class Rectangle extends Shape {
	void draw() {
		System.out.println("사각형을 그린다");
	}	
}

class Triangle extends Shape {
	void draw() {
		System.out.println("삼각형을 그린다");
	}	
}

class Circle extends Shape {
	void draw() {
		System.out.println("원을 그린다");
	}	
}

✍ ShapeEx.java

package ch08;
//  !!!  중요  !!!
//오버로딩: 같은 클래스, 생성자/메서드, 매개변수의 갯수가 다르거나 데이터형이 달라야 한다
//오버라이딩: 상속 관계, 메서드, 반환형, 매개변수 갯수, 이름, 데이터형이 일치
//		   부모보다 접근지정자의 범위가 같거나 넓어야 한다 -> 다형성 

public class ShapeEx {
	public static void main(String[] args) {
		Shape[] sh = new Shape[3];
		sh[0] = new Rectangle();
		sh[1] = new Triangle();
		sh[2] = new Circle();
//		draw()라는 메서드를 원/사각형/삼각형 그린다로 다양하게 표현하는 것을 다형성
		for(int i = 0 ; i < sh.length; i++) {
			sh[i].draw();
		}
	}
}

💻 출력 결과

사각형을 그린다
삼각형을 그린다
원을 그린다

 

위의 소스코드에서 확인할 수 있듯이 draw()라는 메서드를 원/사각형/삼각형 그린다로 다양하게 표현하는 것을 다형성이라고한다.

 


!!! (중요) 오버로딩과 오버라이딩 !!!

오버로딩

기존에 없는 새로운 메서드를 정의하는 것

같은 클래스에서 생성자, 메서드, 매개변수의 개수가 다르거나 데이터형이 달라야한다.

 

오버라이딩

• 상속받은 메서드의 내용을 변경하는 것

 (상속 관계) 메서드명, 반환형, 매개변수 개수, 이름, 데이터형이 일치한다.

자식은 부모보다 접근지정자의 범위가 같거나 넓어야 한다.

 

 


class 앞에 final을 붙일 경우

 final을 class 앞에 작성하면 상속을 안하겠다는 것으로 간주한다.

final을 메서드 앞에 작성하면 오버라이딩이 금지된다.

 

아래에 작성된 코드는 작성 시 빨간 줄이 그어지는 에러가 발생한다.

  • 에러 발생 소스코드

위의 소스코드를 참고하면 Over2 클래스가 상속받으려는 Over1 클래스 이름 앞에 final이 작성되어 있기 때문에 상속이 금지되어 에러가 발생한다.

메서드도 마찬가지로 Over2 클래스가 오버라이딩하려는 Over1 클래스에 있는 m1() 메서드도 앞에 final이 작성되어 있기 때문에 오버라이딩이 금지되어 에러가 발생한다.

 

 

아래와 같이 상속과 오버라이딩이 올바르게 된 코드를 살펴보자.

 

✍ 입력

class Over1 { 
	void m1() {
		System.out.println("부모 메서드입니다.");
	}
}

class Over2 extends Over1 {
	@Override // 오버라이딩: 자식 클래스에서 부모의 메서드를 재정의한다.
	void m1() {
		System.out.println("자식 메서드입니다.");
	}
}

public class Over1Ex {
	public static void main(String[] args) {
		Over1 o1 = new Over1();
		Over1 o2 = new Over2(); // 부모(Over1) 선언, 자식(Over2) 생성
		
		o1.m1(); o2.m1();
	}

}

💻 출력 결과

부모 메서드입니다.
자식 메서드입니다.

 


실습 예제

총 5명에 대하여 급여 계산, 보너스 계산
-----출력형식-----

xxx의 급여명세서
급여: xx
보너스 : xx

 

✍ Employee.java

public class Employee {
	public final static double INCENTIVE_RATE = 0.1; // final: 바꾸지 않겠다는 뜻, 인센티브는 10%로 고정
	private String name;
	Employee() {
		
	}
	
	public String getName() {
		return name;
	}

	Employee(String name) {
		this.name = name;
	}
	int computePay() {   // 재정의해서 사용할 예정
		return 0;
	}
	final int computeIncentive() { // final : 재정의 (overriding) 금지
		int result = 0;
		int pay = computePay();
		if (pay >= 10000) result = (int) (pay * INCENTIVE_RATE);
		return result;
	}
}

SalaryMan.java 

public class SalaryMan extends Employee {
    private int annualSalary;
    SalaryMan(String name, int annualSalary) {
        super(name); this.annualSalary = annualSalary;
    }
    int computePay() {
        return annualSalary / 12;
    }
    //	computeIncentive() { // 재정의(overriding) 금지 final은 재정의 금지
}

✍ HourlyEmployee.java

public class HourlyEmployee extends Employee {
    private int hourWorked;
    private int moneyPerHour;
    HourlyEmployee(String name, int hourWorked, int moneyPerHour) {
        super(name); this.hourWorked = hourWorked; this.moneyPerHour = moneyPerHour;
    }
    int computePay() {
        return hourWorked * moneyPerHour;
    }
}

✍ EmployeeEx.java

public class EmployeeEx {
    public static void main(String[] args) {
        Employee[] emps = new Employee[5];
        emps[0] = new SalaryMan("홀란드", 2000000);
        emps[1] = new SalaryMan("음바페", 3000000);
        emps[2] = new HourlyEmployee("외데고르", 100, 800);
        emps[3] = new HourlyEmployee("비니시우스", 200, 20000);
        emps[4] = new HourlyEmployee("그릴리쉬", 300, 10000);

        for(Employee emp : emps) {
            int sal = emp.computePay();
            int bonus = emp.computeIncentive();
            System.out.println("***** " + emp.getName() + "의 급여명세서 *****");
            System.out.println("급여 : " + sal);
            System.out.println("보너스 : " + bonus);
        }
    }
}

💻 출력 

***** 홀란드의 급여명세서 *****
급여 : 166666
보너스 : 16666
***** 음바페의 급여명세서 *****
급여 : 250000
보너스 : 25000
***** 외데고르의 급여명세서 *****
급여 : 80000
보너스 : 8000
***** 비니시우스의 급여명세서 *****
급여 : 4000000
보너스 : 400000
***** 그릴리쉬의 급여명세서 *****
급여 : 3000000
보너스 : 300000

 

 

//

'Back-End > JAVA' 카테고리의 다른 글

[Java] collection  (0) 2023.03.11
[Java] Object 클래스, equals(), toString()  (2) 2023.03.11
[Java] 클래스 간의 관계 - 포함관계  (0) 2023.03.11
[Java] 상속  (0) 2023.03.11
[Java] 메서드  (0) 2023.03.10