Java 객체지향 프로그래밍 - 다형성 (Polymorphism)
🧑‍💻 𝗣𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴/Java

Java 객체지향 프로그래밍 - 다형성 (Polymorphism)

Java 객체지향 프로그래밍
1. Java 객체지향 프로그래밍 - 상속 (Inheritance)
2. Java 객체지향 프로그래밍 - 메서드 오버라이딩 (Overriding)
3. Java 객체지향 프로그래밍 - 은닉화(Encapsulation) 와 접근 제한자 (modifier)
4. Java 객체지향 프로그래밍 - 싱글톤 패턴 (Singleton)
5. Java 객체지향 프로그래밍 - 다형성 (Polymorphism)

 

 

 다형성 (Polymorphism) 

개요

다형성이란 하나의 객체가 많은 타입을 가질 수 있는 것을 이릅니다.

상속 관계에 있을 시, 부모 클래스의 타입으로 자식 클래스 객체를 레퍼런스 할 수 있습니다.

여기서 레퍼런스란 이를 뜻합니다.

Child c = new Child();
Parents p = c;
GrandParents gp = c;

이런식으로 큰 집에 작은 집을 담을 수 있다는 것입니다.

굳이 앞에 (Parents) 이런식으로 타입을 명시하지 않아도 자동적으로 묵시적 형변환이 이루어집니다.

마치 int 가 double 에 할당될 때 자동으로 형변환이 이루어진 것 처럼요.

 

 

사용되는 경우

1. 부모 클래스로 여러가지 자식 클래스를 하나로 묶을 때
2. 매서드, 생성자 오버로딩
3. 참조형 객체 멤버 사용

 

 

서로 다른 데이터 타입을 하나로 묶을 때

 Animal[] animals = new Animals[10];

 animals[0] = new Dog();
 animals[1] = new Cat();

아까 제가 조상 클래스는 자손 클래스를 레퍼런스할 수 있다고 말씀드렸습니다.

따라서 객체 배열을 만들 때, 이렇게 여러가지 자손 클래스를 조상 클래스의 배열안에 요소로 안착시킬 수 있습니다.

이렇게 되면 여러가지의 타입도 담을 수 있게 됩니다.

따라서 Object 클래스는 모든 클래스의 조상 클래스이므로 모든 객체를 담을 수 있는 마법의 상자가 됩니다.

 

 

오버로딩

package first.subject.m07.polymorphism;


public class MyNote {
	private int no;
	private String title;
	private String content;


	public MyNote() {}


	public MyNote(int no) {
		this.no = no;
	}


	public MyNote(String title) {
		this.title = title;
	}

	// 똑같은 String 이 들어와
	// public MyNote(String content) {
	// super();
	// this.content = content;
	// }


	public MyNote(int no, String title, String content) {
		this.no = no;
		this.title = title;
		this.content = content;
	}


	@Override
	public String toString() {
		return "MyNote [no=" + no + ", title=" + title + ", content=" + content + "]";
	}


	public static void main(String[] args) {
		MyNote note1 = new MyNote();
		System.out.println(note1.toString());

		MyNote note2 = new MyNote("노트2 타이틀");
		System.out.println(note2.toString());

		MyNote note3 = new MyNote(3);
		System.out.println(note3.toString());

		MyNote note4 = new MyNote(4, "노트4 타이틀", "안뇽");
		System.out.println(note4.toString());

	}

}

package first.subject.m07.polymorphism;


public class MyNote {
	private int no;
	private String title;
	private String content;


	public void printNote() {}


	public void printNote(int no) {
		System.out.println(no);
	}


	public void printNote(String title) {
		System.out.println(title);
	}

	// 매개변수 타입이 중복
	// public void printNote(String content) {}


	public void printNote(int no, String title) {
		System.out.println(no + " " + title);
	}


	public static void main(String[] args) {
		MyNote note = new MyNote();

		note.printNote();
		note.printNote(1);
		note.printNote("타이틀");
		note.printNote(2, "타이틀2");
	}
}

이런식으로 생성자를 초기화하거나 메서드를 사용할 때 오버로딩을 사용합니다.

여러가지 타입이 들어온다고 하더라도, 똑같은 이름의 메서드를 가진 메서드로 호출할 수 있습니다.

하지만 만약 매개변수 타입이 똑같다면 중복이 되어 에러가 뜹니다.

매개변수 이름이 다르더라도 타입이 똑같기 때문에 컴파일러가 모릅니다.

 

 

참조형 객체 사용

실제로 사용할 수 있는 것은 왼쪽
실제로 호출되는 것은 오른쪽
// 부모 클래스
package first.subject.m07.polymorphism.reference;


public class Animal {
	private String mouth;


	public void eat() {
		System.out.println("Animal 냠냠");
	}


	public String getMouth() {
		return mouth;
	}


	public void setMouth(String mouth) {
		this.mouth = mouth;
	};

}
// 자식 클래스
package first.subject.m07.polymorphism.reference;


public class Dog extends Animal {
	private String legs;


	@Override
	public void eat() {
		System.out.println("Dog 냠냠");
	}


	public String getLegs() {
		return legs;
	}


	public void setLegs(String legs) {
		this.legs = legs;
	}

}
package first.subject.m07.polymorphism.reference;


public class Test {
	public static void main(String[] args) {
		Animal a = new Dog();

		a.setMouth("주둥아리");
		System.out.println(a.getMouth());
		a.eat();
		// a.setLegs("네 개의 다리"); // error
	}
}

Animal 객체에 mouth 변수와 eat() 메서드를 만들었습니다.

그리고 Dog 객체에 legs 변수와 똑같이 오버라이딩 하여 eat() 메서드를 만들었습니다.

Animal a = new Dog();

메서드에서 다형성을 이용하여 부모 클래스로 자식 클래스를 레퍼런스하였습니다.

왠지 Dog 에 있는 모든 멤버변수나 메서드도 다 사용할 수 있을거라고 생각되지만 그렇지 않습니다.

보시면 호출할 수 있는 것은 eat(), getMouth(), setMouht() 뿐입니다.

사용할 수 있는 것은 부모의 것들입니다.

즉 실제로 호출될 수 있는 것들은 부모의 멤버 입니다.

하지만 eat() 메서드를 출력해보면 자식의 것이 출력된 것을 볼 수 있습니다.

이렇게 메서드 오버라이딩이 된 함수가 있다면 자식의 내용을 출력하게 됩니다.

 

그러면 자식의 클래스로 부모의 클래스를 레퍼런스하면 어떻게 될까요?

이는 업캐스팅에 해당합니다. 이때는 명시적인 형변환을 해줘야합니다.

package first.subject.m07.polymorphism.reference;


public class Test2 {
	public static void main(String[] args) {
		Animal a = new Animal();
		Dog dog = (Dog) a;

		dog.eat();
	}
}

출력을 해보고자 하지만 되지 않습니다.

package first.subject.m07.polymorphism.reference;


public class Test2 {
	public static void main(String[] args) {
		Animal a = new Animal();
		Dog dog = (Dog) a;

		dog.setLegs("4개의 다리");
		System.out.println(dog.getLegs());

		dog.setMouth("주둥아리");
		System.out.println(dog.getMouth());

		dog.eat();
	}
}

 

되는 거 다 찍어봐도 오류가 나옵니다. 이는 메모리에 객체에 해당 변수나 메서드가 없기 때문입니다.

조상을 무작정 이렇게 자손으로 변경할 수 없습니다. 골치 아프죠?

package first.subject.m07.polymorphism.reference;


public class Test2 {
	public static void main(String[] args) {
		Dog dog = (Dog) new Animal();
		System.out.println(dog.toString());

	}
}

당연히 이렇게 쓰는 것도 오류가 나옵니다.

 

 

instanceof 연산자

그러면 어떻게해야 할까요?

이때는 instanceof 연산자를 사용해서 실제 메모리에 있는 개체가 해당 클래스 타입인지 확인을 해야합니다.

package first.subject.m07.polymorphism.reference;


public class Test3 {
	public static void main(String[] args) {
		Animal a = new Animal();
		Animal ad = new Dog();

		if (a instanceof Dog) {
			Dog dog = (Dog) a;
			dog.eat();
		} else {
			System.out.println("Dog 객체가 아닙니다.");
		}

		if (ad instanceof Dog) {
			Dog dog = (Dog) ad;
			dog.eat();
		} else {
			System.out.println("Dog 객체가 아닙니다.");
		}

	}
}

a 는 안되지만 ad 는 실제로는 Dog 객체 이기 때문에 됩니다.

 

 

참조 멤버 연결

// 부모 클래스
package first.subject.m07.polymorphism.reference;


public class Animal {
	private String mouth;


	public void eat() {
		System.out.println("Animal 냠냠");
	}


	public String getMouth() {
		return mouth;
	}


	public void setMouth(String mouth) {
		this.mouth = mouth;
	};

}
// 자식 클래스 
package first.subject.m07.polymorphism.reference;


public class Cat extends Animal {
	private String mouth;


	@Override
	public void eat() {
		System.out.println("Cat 냠냠");
	}


	@Override
	public String getMouth() {
		return mouth;
	}


	@Override
	public void setMouth(String mouth) {
		this.mouth = mouth;
	}

}
package first.subject.m07.polymorphism.reference;


public class Test4 {
	public static void main(String[] args) {
		Cat c = new Cat();
		c.setMouth("Cat 주둥아리");
		System.out.println(c.getMouth());
		c.eat();

		Animal ac = new Cat();
		ac.setMouth("Animal 주둥아리");
		System.out.println(ac.getMouth());
		ac.eat();

	}
}

보면 멤버변수는 각자 자기자신을 가져오고, 메서드는 오버라이딩이 돼서 Cat 것을 사용합니다.

이렇게 메서드가 오버라이딩 되었을 때 자식 클래스 메서드가 호출되는 것을 virtual method invocation 이라고 합니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

# java 다형성 # java 오버라이딩 # java 오버로딩


 

 

728x90