Life is Good

수콩이의 시선

Coding/JAVA

다형성(Polymorphism)

Soocong 2022. 4. 4. 10:52

자바의 다형성 (Polymorphism)

 

다형성의 사전적 의미는 '여러 개의 형태를 갖는다'라는 뜻이다. 여러 형태를 갖으므로써 사용자는 사용편의성을 취할 수 있다.

다형성이라는 것은 객체에게만 국한된 개념은 아니다. 버로딩 오버라이딩은 메소드의 다형성을 쉽게 설명할 수 있는 개념이다. 반면에, 객체의 다형성은 쉽지 않아 개념을 정리해보았다. 

 

설명을 위한 예제 클래스는 아래와 같이 구현되어 있다.

class 자동차{
    void run() {
        System.out.println("달린다.");
    }
}

class 슈퍼카 extends 자동차{
    @Override
    void run() {
        System.out.println("빨리 달린다.");
    }

    void turbo() {
        System.out.println("순간 가속도를 최대로 올린다.");
    }
}

슈퍼카는 자동차를 상속받은 자식클래스로 run메소드를 오버라이딩 하였고, 추가적으로 turbo라는 메소드도 정의되었다.

 

 

자바의 객체 선언 문법

다형성을 설명하기에 앞서서 자바의 객체선언 문법을 정확하게 이해 한다면, 다형성에 대한 이해를 좀 더 쉽게 할 수있다. 아래의 예제로 간단히 살펴보자.

 

참조타입 참조변수 = new 생성자();

이 문법을 풀어서 말해보면,

→ "새로운 객체를 생성 할 것인데, 객체의 이름은 참조변수이고,  참조타입의 역할을 수행하기 위해 만들어진 만들어진 객체이다."

(참고: 정확하게는 객체의 이름이 아니라, 객체를 참조하고 있는 것의 이름이라고 표현해야 합니다.)

 

예제로 치환해보면,

ex) 자동차 붕붕이 = new 슈퍼카();

→ "새로운 객체를 생성 할 것인데, 객체의 이름은 붕붕이이고,  자동차의 역할을 수행하기 위해 만들어진 슈퍼카이다."

자세한 설명은 아래 이어서 하겠다. 

 

객체의 여러가지의 형태 (다형성)

자동차와 관련된 객체 3가지를 선언했다.

자동차 차차 = new 자동차();
슈퍼카 붕붕이 = new 슈퍼카();
자동차 타요 = new 슈퍼카();

첫번째 객체 차차의 경우는 run메소드를 호출하게 되면, "달린다"를 출력한다.

두번째 객체 붕붕이의 경우는 run메소드를 호출하게 되면, 오버라이딩 된 메소드를 호출 할테니, "빨리 달린다"를 출력한다.

세번째 객체 타요의 경우는 run메소드를 호출하게 되면, 참조변수가 자동차 일지라도, 오버라이딩된 "빨리 달린다"를 출력한다. (이건 오버라이딩의 중요한 특성이다.)

 

그럼 붕붕이와 타요의 차이는 뭘까? 바로 추가된 turbo메소드의 호출 가능 여부다.

붕붕이 슈퍼카의 역할을 수행하기 위해 만들어진 슈퍼카이다.

타요 자동차의 역할을 수행하기 위해 만들어진 슈퍼카이다.

 

붕붕이 슈퍼카 역할을 수행하기에, turbo메소드 호출이 필요할 것이고, 호출 할 수 있다.

반면, 타요 자동차 역할을 수행하기에, 슈퍼카의 turbo메소드는 호출할 필요도 없고 호출할 수도 없다.

 

이제 자연스럽게 생기는 궁금증이 나올 수 있다.

그럼 굳이 자동차로써 동작하는 슈퍼카 객체는 왜 쓰는가?

 

내가 공부한 바로는 크게 2가지 경우가 있었다.

 

  1.  객체를 사용하는 사용자에게 참조타입으로써의 동작만 강요하고 싶은 경우
    ex) 슈퍼카를 발렛파킹하는 직원(사용자)이 굳이 turbo메소드를 호출할 필요는 없다. 그럼 자동차로써의 동작만을 강제시킨다.
  2. 부모(조상)클래스에게 상속받은 메소드만을 (오버라이딩된 메소드도 포함) 사용 하는 객체일 경우 
    ex) 만약 슈퍼카가 아닌, 자동차 클래스 상속받은 다른 클래스로 변경해야 할 때, 객체 선언문만 변경한다면 나머지 코드는 검토하지 않아도 된다. 유지보수의 이점이 있는 것이다. (이는 스프링의 의존성 주입을 알고 있다면 더 직관적으로 받아들일 수 있다.)   

결론적으로 메소드의 다형성(오버로딩, 오버라이딩)과 클래스의 다형성 모두 사용자에게 편의성을 제공해준다는 점을 기억하자

부모(조상)클래스의 대표성

위에서 설명한 객체 차차,붕붕이,타요는 모두 자동차로 대표될 수 있다. 

ex) 주차장에 들어 올 수 있는 객체의 조건은 '자동차'로 충분하다. '자동차'라고 명시해주는 것만으로도 자동차를 상속받고 있는 자손클래스들의 객체는 주차장에 입장이 가능하다.  Java의 문법으로 설명하자면, 매개변수의 타입으로 자동차를 명시해주는 것은, 자동차 뿐만 아니라 자동차를 상속받고 구현한 객체들을 받을 수 있다. 

 

ex) 모호할 수 있으니 예를 한가지 더 들어보겠다. '사람'이라는 부모(조상)클래스를 상속받아 구현한 객체 '학생', '개발자', '정치인' 등등은 모두 '사람'으로 대표될 수 있을 것이다.

 

 

자바에선 반드시 알아야 할 OOP라는 개념이 있습니다. 캡슐화, 상속, 추상화, 다형성! 그 중 오늘은 다형성에 대해서 조금 자세히 알아보도록 하겠습니다. 

 

자바에서 말하는 다형성은 상위클래스와 하위클래스 사이에서 설명 할 수 있는 다형성과 인터페이스와 구현클래스 사이에서도 설명 할 수 있는 다형성 등이 있습니다. 하지만, 기본적으로 자바의 다형성에 대해서 설명해보세요. 라고 질문을 받게 된다면, 오버로딩(Overloading)과 오버라이딩(Overriding)을 설명하면 됩니다. 자바의 가장 기본적인 다형성이기 때문이지요..

 

우선 오버로딩과 오버라이딩을 구별해 보겠습니다.

 

1. 같은 메서드 이름, 같은 인자 목록에서 상위 클래스의 메서드를 재정의

2. 같은 메서드 이름, 다른 인자 목록에서 다수의 메서드를 중복 정의 

 

어떤 것이 오버로딩이고 오버라이딩일까요???

네 맞습니다. 1 번이 오버라이딩이고, 2번이 오버로딩입니다!! 

 

오버라이딩과 오버로딩을 한번에 설명 할 수 있는 예제를 보겠습니다. 

 

Animal.java

public class Animal {

	public String name;

	public void showName() {
		System.out.printf("안녕 나는 %s야. 반갑다.\n", name);
		
	}

}

Tiger.java

public class Tiger extends Animal {

	public String habitat;
	
	public void showHabitat(){
		System.out.printf("%s는 %s에 살아\n",name,habitat);
	}
	
	//오버라이딩
	public void showName(){
		System.out.println("오버라이딩!! 보안상 이름을 말할 수 없습니다.");
	}
	
	//오버로딩
	public void showName(String yourName){
		System.out.printf("오버로딩!! %s 안녕, 나는 %s라고 해\n",yourName, name);
	}
}

Main.java

public class Main {

	public static void main(String[] args) {
		
		Tiger hodol = new Tiger();
		
		hodol.name ="호돌이";
		hodol.habitat = "시베리아";
		
		hodol.showName();
		hodol.showName("기아타이거즈");
		hodol.showHabitat();
		
		Animal kiaTiger = new Tiger();
		
		kiaTiger.name = "기아타이거즈";
		kiaTiger.showName();

	}

}
 

**결과**

 

오버라이딩!! 보안상 이름을 말할 수 없습니다.

오버로딩!! 기아타이거즈 안녕, 나는 호돌이라고 해

호돌이는 시베리아에 살아

오버라이딩!! 보안상 이름을 말할 수 없습니다.

 

위 코드에 대한 분석을 간단하게 말씀드리면, Animal 상위 클래스에 있는 메소드를 Tiger라는 하위 클래스가 오버라이딩하여 자신의 스타일에 맞게 재정의 하였고, 같은 메서드 이름으로 매개변수 타입 or 매개변수 갯수를 다르게 줘서 오버로딩 중복 정의를 하였습니다.

 

마치며...

 

그럼 도대체 왜 자바에서 다형성을 할까요??? 즉 왜 오버로딩과 오버라이딩을 해야할까요???

바로 코드 재사용성이 높아지기 때문입니다. 개발자는 귀차니즘성향(?)이 강한 직업 중에 하나입니다. 썼던 코드 다시 살짝만 바꿔서 목적과 용도에 맞게끔 설계하면 개발자 편의성이 높아집니다. 덩달아 유지보수도 높아지지요... 또한, 객체지향 설계원칙에 부합됩니다. 사람이 사고하는 생각의 흐름처럼 자연스럽게 코드에도 적용할 수 있으니까요....동시에 한 가지 기능에 대해 용도와 목적에 맞게끔 커스터마징할 수 있습니다. 예를 들어 사람 클래스라는 상위클래스가 있습니다. 사람 클래스를 상속받은 하위클래스 홍길동은 생각하다 메서드를 오버라이딩해서 꿈을 생각하는데 사용합니다! 반면, 길동이의 친구 철수는 생각하다 메서드를 오버라이딩해서 오늘 퇴근하고 뭐하고 놀지 생각합니다. 각자에 스타일에 맞게 구현하는 것입니다. ㅎㅎ 

 

 

크게 자바프로그래밍 객체지향에서 다형성의 개념을 녹여내는 방법은 두가지인데, 

바로 오버라이딩(Overriding) 과 오버로딩(Overloading)이다.

간단하게 설명하자면,

오버라이딩은 부모클래스에서 상속받은 서브클래스 즉 자식클래스에서 부모클래스,즉 상위클래스에서 만들어진 메서드를 자신의 입맛대로 다시 재창조해서 사용하는 것을 말한다.

오버로딩은 하나의 클래스 안에서 같은이름의 메서드를 사용하지만 각 메서드마다 다른 용도로 사용되며 그 결과물도 다르게 구현할 수 있게 만드는 개념인데 오버로딩이 가능하려면 메서드끼리 이름은 같지만 매개변수의 갯수나 데이터타입이 다르면 오버로딩이 적용되어 메서드 이름이 같아도 문법 에러가 나지않는다..

같은 행위를 하지만 용도와 목적에 부합하여 다양한 기능수행과 처리, 결과를 낳을 수 있는 것이다.