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 오버로딩
'🧑💻 𝗣𝗿𝗼𝗴𝗿𝗮𝗺𝗺𝗶𝗻𝗴 > Java' 카테고리의 다른 글
Java HashSet 정렬하기 (0) | 2022.09.28 |
---|---|
Java Lambda식 + Comparable 및 Comparator 인터페이스 (0) | 2022.07.31 |
Java 객체지향 프로그래밍 - 싱글톤 패턴 (Singleton) (0) | 2022.07.31 |
Java 객체지향 프로그래밍 - 은닉화(Encapsulation) 와 접근 제한자 (modifier) (0) | 2022.07.31 |
Java 객체지향 프로그래밍 - 메서드 오버라이딩 (Overriding) (0) | 2022.07.31 |