다형성 (Polymorphism)
다형성이란 | 어떤 객체가 | 다양한 형태 | 로 변할 수 있는 것 |
↘ 부모 클래스형의 변수 로 참조 중인 개체 ( 무늬 ) |
↘ 실제 개체에 구현된 메서드 ( 실체 ) |
사람들이 OOP의 핵심이라 여기는 특징이다.
객체들에게 같은 지시를 내렸는데 다른 종류의 객체가 동작을 달리하는 것을 말한다.
다형성의 혜택을 받으려면 상속 관계가 필요하다.
부모 객체에서 함수 시그내처를 선언하고
자식 객체에서 그 함수를 다르게 구현하는 것이다.
이를 오버라이딩 이라고 한다.
오버라이딩
부모 클래스로부터 상속받은 메서드의 내용을 상속받는 클래스에 맞게 변경하는 것을 오버라이딩 이라고 한다.
(부모 클래스에서 메서드의 시그내처를 정해주고, 자식 클래스에서 그 메서드의 구현을 덮어씀)
그렇지 않으면 부모 클래스형 변수에서 호출 불가
class animal{
private String name;
private int age;
public String getName(){
return this.name;
}
private String sex;
public void walk() { }
public void eat() { }
public void shout() {
System.out.println("동물의 울음소리");
}
public animal(String name, int age, String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
}
class dog extends animal{
public void shout() {
System.out.println("멍-멍-");
}
public dog(String name, int age, String sex){
super(name, age, sex);
}
}
class cat extends animal{
public void shout() {
System.out.println("야옹-");
}
public cat(String name, int age, String sex){
super(name, age, sex);
}
}
class duck extends animal{
public void shout() {
System.out.println("꽥꽥-");
super.shout(); // 부모의 함수를 호출한다.
}
public duck(String name, int age, String sex){
super(name, age, sex);
}
}
public class Main {
public static void main(String[] args) {
animal[] animals = new animal[3]; // animal객체 배열 생성
animals[0] = new dog("BAN",2,"male"); // animal[0]에 dog객체 생성 후 대입
animals[1] = new cat("NAVI",1,"female"); // animal[1]에 cat객체 생성 후 대입
animals[2] = new duck("BBI", 1,"female"); // animal[2]에 duck객체 생성 후 대입
for (int i=0; i<animals.length; i++){
System.out.printf("%s의 울음소리는? ",animals[i].getName());
animals[i].shout();
}
}
}
animal 객체 배열을 생성하고 각각 다른 동물을 생성한 다음 객체 배열에 넣어줬다.
개, 고양이, 앵무새를 생성하고 이때 모두 울음소리를 내라고 지시했을 때
개는 "멍-멍-" 라고 울고 고양이 "야옹-", 오리는 "꽥꽥-" 라고 운다.
객체들에게 같은 지시를 내렸지만, 각 인스턴스가 다른 동작을 하는 것이다.
※ super.메서드명(); 사용시 부모의 함수를 호출할 수 있다.
오버라이딩의 조건
1. 선언부가 같아야 한다. (이름, 매개변수, 리턴타입)
2. 접근제어자를 좁은 범위로 변경할 수 없다.
(부모의 메서드가 protected라면 같거나 protected 넓은 public만 가능하다.
3. 부모 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
오버로딩
메서드의 이름은 같아야 하지만 메서드 시그니처 매개변수의 개수 또는 타입이 달라야 한다.
class test1{
void mul(int num1, int num2){
System.out.println(num1*num2);
}
void mul(int num1, double num2){
System.out.println(num1*num2);
}
}
public class method {
public static void main(String[] args) {
test1 cal = new test1();
cal.mul(10, 20);
cal.mul(24, 3.14);
}
}
다형성의 장점
각 자료형의 코드가 클래스 안에 들어가니 캡슐화가 된다.
유지 보수성이 좋아진다.
새로운 클래스를 추가할 때 클래스 코드만 추가하면 된다.
final
메서드 앞에 final 키워드를 붙이면 자식에서 오버라이딩 불가능하다.
변수 앞에 final 키워드 : 더 이상 변수의 값을 변경하지 못한다.
클래스 앞에 fianl 붙는 키워드 : 더 이상 상속하지 못한다. 자식 클래스 존재 불가
animal a1 = new cat();
cat c1 = new cat();
참조변수가 부모 타입일 때 와, 참조변수가 자식 타입일 때에 차이점은
참조변수로 사용할 수 있는 멤버의 개수가 달라진다.
animal a1 = new cat();
참조변수가 부모 객체일 때 자손 객체를 참조하는 것은 가능하다.
하지만
cat c1 = new animal();
참조변수가 자손 객체일 때 부모 객체를 참조하는 것은 불가능하다.