다형성은 객체지향에서 아주 중요한 개념이다

 

부모-자식 상속 관계인 클래스에서 상위 클래스가 하위 클래스들을 동일한 메세지로 다르게 동작시키는

객체지향 원리이다

 

 

 

Man , Woman 클래스는 People클래스를 상속받아 resultPerson() 함수를 호출할 수 있다.

package com.example.demo;

//다형성
class People{
	public void resultPerson() {
		System.out.println("나는 사람이다.");
	}
}

//Person 클래스 상속받음
class Man extends People{} 
class Woman extends People{}

public class Polymorphism {
	
	public static void main(String[] args) {
		
		Man man = new Man();
		Woman woman = new Woman();
		
		man.resultPerson();
		woman.resultPerson();
		
	}
}

 

결과

나는 사람이다.
나는 사람이다.

 

 

 

  • people은 > man, woman 이다 (X)
  • man, woman은 > people이다 (O)

man, woman은 people이기 때문에 people 자료형을 받을 있다. 아래처럼 (이것이 다형성의 개념)

People p = new Man();
p.resultPerson();

p = new Woman();
p.resultPerson();

 

p라는 참조변수는 Man,Woman 객체를 가르키는 변수이며 객체의 주소값을 저장한다. 

헷갈리는게 객체를 저장하는 변수가 아니다!

 

첫번째 줄인 People p = new Man(); 의 p는 Man객체를 가르키고

두번째인 p = new Woman(); 의 p는 이제 Woman객체를 가르킨다 (p 참조변수는 한개의 객체 주소만 가질 수 있음)

그리고 new 연산자는 힙 메모리에 로드하기 때문에 힙 메모리에는 두 객체의 주소값이 저장된다.

 

따라서 메모리상에서는 Man, Woman 객체가 저장되며 p변수는 마지막에 p = new Woman(); 로 인해 Woman 객체를 가르키는 주소값을 가지고있다.

 

 

 

그리고 man, woman 은 resultPerson()을 물려받았기에 오버라이딩이 가능하다.

man, woman 각 클래스에 맞게 오버라이딩을 해서 다르게 동작하도록 해보자

//Person 클래스 상속받음
class Man extends People{ 
	public void resultPerson() { //resultPerson() 오버라이딩해서 상위 클래스 동작을 다르게 변경하기 위해  
		super.resultPerson();  //상위클래스(People)의 함수실행 
		System.out.println("그리고 난 남자"); //추가 동작
	}
} 
class Woman extends People{
	public void resultPerson() {
		super.resultPerson();
		System.out.println("그리고 난 여자");
	}
}
나는 사람이다.
그리고 난 남자

나는 사람이다.
그리고 난 여자

 

전체 코드

package com.example.demo;

//다형성
class People{
	public void resultPerson() {
		System.out.println("나는 사람이다.");
	}
}

//Person 클래스 상속받음
class Man extends People{ 
	public void resultPerson() { //resultPerson() 오버라이딩해서 상위 클래스 동작을 다르게 변경하기 위해  
		super.resultPerson();  //상위클래스(People)의 함수실행 
		System.out.println("그리고 난 남자"); //추가 동작
	}
} 
class Woman extends People{
	public void resultPerson() {
		super.resultPerson();
		System.out.println("그리고 난 여자");
	}
}

public class Polymorphism {
	
	public static void main(String[] args) {
		
		People p = new Man();
		p.resultPerson(); //부모 클래스 함수 물려받음 = 오버라이딩
		
        System.out.println();
        
		p = new Woman();
		p.resultPerson();
	}
}

 

 

 

만약 man, woman 클래스에서 단독으로 메소드를 추가해보자

class Man extends People{ 
	public void resultPerson() { //resultPerson() 오버라이딩해서 상위 클래스 동작을 다르게 변경하기 위해  
		super.resultPerson();  //상위클래스(People)의 함수실행 
		System.out.println("그리고 난 남자"); //추가 동작
	}
	public void army() {
		System.out.println("군대를 간다.");
	}
} 
class Woman extends People{
	public void resultPerson() {
		super.resultPerson();
		System.out.println("그리고 난 여자");
	}
	public void makeup() {
		System.out.println("화장을 한다.");
	}
}

 

army() , makeup() 함수는 People 클래스에서 없는 메소드이며 상속받은 함수가 아니기때문에

p.army() 할 수가 없다 그래서 amy() 메소드가 있는 객체로 캐스팅(형변환)해서 메소드를 사용한다.

 

따라서 형변환을 Man으로 해서 Man 클래스의 메소드를 사용할 수 있다.

((Man)p).army();

 

People p = new Man(); 을 했을때 new가 동적 메모리에 할당하는 역할을 한다

Man은 heap 메모리에 로드가 되고 p는 형변환을 Man으로 가능하다

public class Polymorphism {
	
	public static void main(String[] args) {
		
		//남자는 사람이다(o)
		People p = new Man();
		p.resultPerson(); //부모 클래스 함수 물려받음 = 오버라이딩
		((Man)p).army();
		
		System.out.println();
		
		p = new Woman();
		p.resultPerson();
		((Woman)p).makeup();
	}
}
나는 사람이다.
그리고 난 남자
군대를 간다.

나는 사람이다.
그리고 난 여자
화장을 한다.

 

 

다형성은 대표적으로 메소드의 매개변수에 상속하는 클래스를 받아서 사용한다

func메소드의 매개변수 people은 People클래스의 객체를 전달할 수 있다.

따라서 func 메소드는 People 클래스를 직접 상속한 Man, Woman 객체를 전달한다 이것이 다형성의 특징이다.

 

즉 Man, Woman 은 하위 클래스로 func 메소드의 매개변수로 전달하며 동일한 메소드를 이용해 다양한 객체를 다룰 수 있고 객체의 실제 타입에 따라 적절한 동작을 수행 할 수 있다는게 다형성의 특징!

 

public class Polymorphism {
	public static void func(People people) {
		people.resultPerson();
	}
	
	public static void main(String[] args) {
		
		Man man = new Man();
		Woman woman = new Woman();
		func(man);
		System.out.println();
		func(woman);
    }
}

 

결과

나는 사람이다.
그리고 난 남자

나는 사람이다.
그리고 난 여자

 

전체코드

package com.example.demo;

//다형성
class People{
	public void resultPerson() {
		System.out.println("나는 사람이다.");
	}
}

//Person 클래스 상속받음
class Man extends People{ 
	public void resultPerson() { //resultPerson() 오버라이딩해서 상위 클래스 동작을 다르게 변경하기 위해  
		super.resultPerson();  //상위클래스(People)의 함수실행 
		System.out.println("그리고 난 남자"); //추가 동작
	}
	public void army() {
		System.out.println("군대를 간다.");
	}
} 
class Woman extends People{
	public void resultPerson() {
		super.resultPerson();
		System.out.println("그리고 난 여자");
	}
	public void makeup() {
		System.out.println("화장을 한다.");
	}
}



public class Polymorphism {
	public static void func(People people) { //people객체를 받아서 이 객체를 상속받는 모든 클래스의 객체도 전달할 수 있다.
		people.resultPerson();
	}
	
	public static void main(String[] args) {
		
		Man man = new Man();
		Woman woman = new Woman();
//		//People 클래스를 상속한 하위 클래스를 매개변수로 전달 
		func(man); 
		System.out.println();
		func(woman);
		
	}
}

 

 

man, woman 클래스에서 단독으로 추가한 메소드는 어떻게 출력을 해야할까

people 변수를 Man 타입으로 형변환을 하면 people변수가 Man 타입으로 인식이 되어 army() 메소드를 사용 할 수 있다 

((Man)people).army();
public class Polymorphism {
	public static void func(People people) { //people객체를 받아서 이 객체를 상속받는 모든 클래스의 객체도 전달할 수 있다.
		people.resultPerson();
		((Man)people).army();
	}
	
	public static void main(String[] args) {
		
		Man man = new Man();
		//Woman woman = new Woman();

		func(man); 
		System.out.println();
		//func(woman);

	}
}
나는 사람이다.
그리고 난 남자
군대를 간다.

 

 

대신 Woman 객체로도 형변환을 해야하기 때문에 insanceof 연산자를 이용하여 캐스팅(형변환)을 해보자 

참조변수 instanceof 클래스
> people instanceof Man  // people 변수가 Man  클래스의 객체인지 확인하는 연산자

people 변수가 Man 클래스의 객체를 참조한다 = people 변수가 Man 클래스의 인스턴스이다

people 변수가 Man 클래스로 생성된 객체인지를 검사?

 

people instanceof Man = true! 

왜?

func(man); 에서 man 변수는 func()메소드의 매개변수로 전달받아 people 매개변수는 man 변수가 가리키고 있는 Man 클래스의 객체를 참조한다.

정리하자면 man변수는 People 타입으로 자동형변환을 하고 func()메소드의 people 개변수로 전달. 그럼 people매개변수는  'man의 변수가 가르키고 있는' Man 클래스의 객체를 참조하게 된다 

그럼 people 변수는 Man 클래스의 속성과 메소드에 접근가능

 

** 헷갈리는거!

참조한다는 것은 변수가 해당 객체를 가르키고 있다는 뜻

예를들어 Man man = new Man();

Man 클래스 객체생성하면 그 객체를 man 변수에 할당한다 man변수는 객체를 참조하고 있어 man변수를 사용해  Man클래스의 속성과 메소드에 접근할 수 있다.

 

 

people 변수는가 Man, Woman 클래스의 메소드에 접근하려면 타입이 다르니까 형변환을 해줘야함

if(people instanceof Man) { 
    ((Man)people).army();
}else {
    ((Woman)people).makeup();
}

 

public class Polymorphism {
	public static void func(People people) { 
		people.resultPerson();
        
		//Man,Woman클래스의 단독으로 추가한 메서드 출력하기
		if(people instanceof Man) { 
			((Man)people).army();
		}else {
			((Woman)people).makeup();
		}
	}
    
    public static void main(String[] args) {
		
		Man man = new Man();
		Woman woman = new Woman();
		//man이라는 변수를 func()메소드의 people 매개변수에 전달하면 people 매개변수는 man의 변수가 가르키는 Man클래스의 객체를 참조한다.
		func(man); 
		
		System.out.println();
		func(woman);
		
	}
}

 

 

 

 

 이해는 어느정도 했지만 아직까지 헷갈리는 다형성..

 

반응형
LIST

'공부' 카테고리의 다른 글

클래스 멤버  (0) 2023.07.20
추상 메소드와 인터페이스 | 다중상속  (0) 2023.06.27
접근 제한자 | 지역변수, 전역변수와 static  (0) 2023.06.22
생성자  (0) 2023.06.20
메소드화 | 객체화 | 인스턴스  (0) 2023.06.16

+ Recent posts