1. 다형성
- 동일한 타입을 사용하지만 다양한 결과가 나오는 성질
- 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해줍니다.
- 다형성은 객체를 부품화가 가능하게 합니다. (하나의 타입 여러 객체 대입)
- 다형성을 위해 자바에서는 부모 클래스로 타입 변환을 허용합니다.
- 부모 타입에 모든 자식 객체가 대입될 수 있습니다.
- 타입 변환이란 데이터 타입을 다른 데이터 타입으로 변환하는 행위를 말합니다.
- 자식 타입은 부모 타입으로 자동 타입 변환이 가능합니다.
2. 자동 타입 변환(Promotion)
- 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말합니다.
- 자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급 가능합니다.
- 부모가 아니더라도 상속 계층에서 상위 타입이라면 자동 타입 변환이 일어날 수 있습니다.
- 부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능합니다.
- 변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정
- 예외) 메소드가 자식 클래스에서 오버 라이딩되었다면 자식 클래스의 메소드가 대신 호출 (다양한 기능 구현 가능)
자동 타입 변환 예시
- A 클래스를 상속 받은 B 클래스는 부모 타입인 A 타입으로 자동 변환 가능
- B 클래스를 상속 받은 C 클래스는 상위 타입인 A 타입으로 자동 변환 가능
B b = new B();
C c = new C();
A a1 = b; // B객체 A타입(부모)으로 자동 타입 변환
A a2 = c; // C객체 A타입(상위)으로 자동 타입 변환
부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능(부품화)
public class A {
String fieldA;
void methodA() {
System.out.println("A 클래스의 메소드 입니다.");
System.out.println("필드값: " + this.fieldA);
}
}
public class B extends A {
String fieldB;
void methodB() {
System.out.println("B 클래스의 메소드 입니다.");
}
}
B b = new B();
C c = new C();
// B 객체를 A타입(부모)으로 자동 타입 변환
A a = b;
// 부모 클래스의 필드와 메소드만 접근이 가능합니다.
a.fieldA = "B field";
a.methodA(); // A 클래스의 메소드 입니다. 필드값: B field
// 부모 타입으로 변경이 되면 자식 객체의 필드와 메소드에 접근이 불가능 합니다.
// a.fieldB = "B field"; (x)
// a.methodB(); (x)
메소드가 자식 클래스에서 오버 라이딩되었다면 자식 클래스의 메소드가 대신 호출(다양한 기능)
public class A {
String fieldA;
void methodA() {
System.out.println("A 클래스의 메소드 입니다.");
}
}
public class B extends A {
String fieldB;
@Override
void methodA() {
System.out.println("B 클래스의 메소드 입니다.");
}
}
public class C extends B {
String fieldC;
@Override
void methodA() {
System.out.println("C 클래스의 메소드 입니다.");
}
}
// B 객체 자동 타입 변환 및 메소드 호출(B 객체 메소드 오버라이딩)
A a = new B();
a.methodA(); // B 클래스의 메소드 입니다.
// C 객체 자동 타입 변환 및 메소드 호출(C 객체 메소드 오버라이딩)
a = new C();
a.methodA(); // C 클래스의 메소드 입니다.
3. 강제 형 변환(Casting)
자식클래스 변수 = (자식클래스) 부모클래스타입;
- 자식 타입이 부모 타입으로 자동 변환한 후, 다시 자식 타입으로 변환할 때 강제 타입 변환을 사용할 수 있습니다.
- 자식 타입이 부모 타입으로 자동 변환하면, 부모 타입에 선언된 필드와 메소드만 사용 가능하다는 제약사항이 따르게 되는데 만약 자식 타입에 선언된 필드와 메소드를 꼭 사용해야 한다면 강제 타입 변환을 사용하면 됩니다.
예시
public class A {
String fieldA = "A";
void methodA() {
System.out.println("A 클래스의 메소드 입니다.");
}
}
public class B extends A {
String fieldB = "B";
void methodB() {
System.out.println("B 클래스의 메소드 입니다.");
}
}
// B 객체 자동 타입 변환
A a = new B();
// 필드 접근 및 메소드 호출, 자식 객체의 필드와 메소드 접근 불가
String fieldA = a.fieldA;
a.methodA();
// String fieldB = a.fieldB; (x)
// a.methodB(); (x)
// 자식 타입으로 강제 형 변환(Casting)
B b = (B) a;
// 자식 객체의 필드와 메소드 접근 가능
String fieldA2 = b.fieldA;
b.methodA();
String fieldB2 = b.fieldB;
b.methodB();
4. 필드의 다형성
- 필드의 값을 다양화함으로써 실행 결과가 다르게 나오도록 구현
- 필드의 타입은 변함이 없지만, 실행 도중에 어떤 객체를 필드로 저장하느냐에 따라 실행 결과가 달라질 수 있습니다. (다양한 기능)
- 자식 클래스는 부모가 가지고 있는 필드와 메소드를 가지고 있으니 사용 방법은 동일할 것이고 자식 클래스는 부모의 메소드를 오버 라이딩해서 메소드의 실행 내용을 변경함으로써 다양한 실행 결과가 나오게 할 수 있습니다. (부품화)
- 참조 객체만 변경하면 되므로 코드의 수정이 간결해집니다.
예시
Computer 클래스
public class Computer {
private CPU cpu; // 필드의 다형성
public Computer(CPU cpu) {
this.cpu = cpu;
cpu.cpuSpec(); // 객체 생성 시 CPU 스펙 출력
}
}
Computer 클래스의 필드가 될 CPU 클래스
public class CPU {
private String modelName;
private int coreCnt;
public CPU(String modelName, int coreCnt) {
this.modelName = modelName;
this.coreCnt = coreCnt;
}
public String getModelName() {
return modelName;
}
public int getCoreCnt() {
return coreCnt;
}
public void cpuSpec() {
System.out.println(this.coreCnt);
System.out.println(this.modelName);
}
}
CPU 클래스를 상속받은 InterCpu 클래스
public class IntelCpu extends CPU {
public IntelCpu(String modelName, int coreCnt) {
super(modelName, coreCnt);
}
// 메소드 오버라이딩
@Override
public void cpuSpec() {
System.out.println("---- Intel CPU STATUS ----");
System.out.println("모델명: " + getModelName());
System.out.println("코어 수: " + getCoreCnt());
System.out.println("---- Intel CPU STATUS ----");
}
}
CPU 클래스를 상속 받은 AmdCpu 클래스
public class AmdCpu extends CPU {
public AmdCpu(String modelName, int coreCnt) {
super(modelName, coreCnt);
}
// 메소드 오버라이딩
@Override
public void cpuSpec() {
System.out.println("---- AMD CPU STATUS ----");
System.out.println("모델명: " + getModelName());
System.out.println("코어 수: " + getCoreCnt());
System.out.println("---- AMD CPU STATUS ----");
}
}
실행
// 객체 생성 (생생자에 전달 되는 객체는 부모 타입으로 자동 형 변환)
Computer computer = new Computer(new IntelCpu("intel-001", 8));
System.out.println();
// CPU 교체(객체 교체)
computer = new Computer(new AmdCpu("amd-001", 4));
출력 값
5. 매개 변수의 다형성
- 자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 메소드를 호출할 때도 많이 발생
- 매개 값을 다양화하기 위해 매개 변수에 자식 타입 객체를 지정할 수도 있습니다.
- 매개 변수의 타입이 클래스일 경우, 해당 클래스의 객체뿐만 아니라 자식 객체까지도 매개 값으로 사용할 수 있습니다.
예시
Button 클래스
public class Button {
public void action() {
System.out.println("버튼 누름");
}
}
Button 클래스를 상속 받은 OnButton 클래스
public class OnButton extends Button {
@Override
public void action() {
System.out.println("ON 버튼 누름");
}
}
Button 클래스를 상속 받은 OffButton 클래스
public class OffButton extends Button {
@Override
public void action() {
System.out.println("OFF 버튼 누름");
}
}
Button 객체를 사용하는 Action 클래스
public class Action {
public void buttonAction(Button button) {
button.action();
}
}
실행
Action action = new Action();
OnButton onButton = new OnButton();
OffButton offButton = new OffButton();
// 매개 변수로 Button의 자식 객체 전달
action.buttonAction(onButton); // ON 버튼 누름
action.buttonAction(offButton); // OFF 버튼 누름
출력 값
'Backend > 객체 지향 프로그래밍' 카테고리의 다른 글
[Java] 객체의 다형성 구현 (인터페이스) (0) | 2022.04.22 |
---|---|
[Java] 객체의 다형성 구현 (추상 클래스) (0) | 2022.04.20 |
[Java] final 클래스 final 메소드 (0) | 2022.04.18 |
[Java] 클래스 상속 (Inheritance) (0) | 2022.04.17 |
[Java] Annotation (메타데이터) (0) | 2022.04.16 |