package ex_polymorphism;
public class Ex1 {
public static void main(String[] args) {
/*
* 다형성(Polymorphism)
*
* - 동적 바이딩 : 코드상의 실행할 메서드와 컴파일 후 실행 시점에서
* 실행되는 메서드가 달라지는 것
* - 서브클래스에 오버라이딩 된 메서드가 존재할 경우 업캐스팅 후에도 오버라이딩 된
* 메서드가 호출됨
* => 즉, 메서드 호출 시 참조 타입이 누군지는 중요하지 않고 실제 인스턴스가 누군지가 중요!
*/
System.out.println("===== Truck =====");
// Truck 인스턴스 생성 및 접근 가능한 메서드 호출
Truck truck = new Truck();
// Car 클래스로부터 상속받은 메서드
truck.speedUp();
truck.speedDown();
// Truck 클래스에서 정의한 메서드
truck.dump();
System.out.println("===== Taxi =====");
// Taxi 인스턴스 생성 및 접근 가능한 메서드 호출
Taxi taxi = new Taxi();
// Car 클래스로부터 상속받은 메서드
taxi.speedUp();
taxi.speedDown();
// Taxi 클래스에서 정의한 메서드
taxi.lift();
taxi.drop();
System.out.println("===== Truck -> Car 업캐스팅 =====");
Car car = truck; // 업캐스팅
// Truck -> Car 업캐스팅 후 접근 가능한 메서드 호출
car.speedUp(); // 서브클래스에서 오버라이딩된 메서드 호출
car.speedDown(); // 서브클래스에서 오버라이딩 된 메서드 호출
// => 업캐스팅 후에는 오버라이딩된 Truck의 메서드 호출!
// car.dump(); // 참조 영역 축소로 상속 멤버 외에 접근 불가
System.out.println("===== Car -> Truck 다운캐스팅 =====");
// 업캐스팅 된 Car 타입을 다시 Truck 타입으로 다운캐스팅
// truck = car; // 다운캐스팅 시 명시적 형변환 필요
truck = (Truck) car; // 다운캐스팅
// Car 클래스로부터 상속받은 메서드
truck.speedUp();
truck.speedDown();
// Truck 클래스에서 정의한 메서드
truck.dump();
System.out.println("===== Taxi -> Car 업캐스팅 =====");
// Taxi -> Car 업캐스팅 및 접근 가능한 메서드 호출
car = taxi;
car.speedUp();
car.speedDown();
// => 업캐스팅 후에도 오버라이딩된 Taxi의 메서드 호출!
// 참조 영역 축소로 상속 멤버 외에 접근 불가
// car.lift();
// car.drop();
System.out.println("===== Car -> Taxi 다운캐스팅 =====");
// 업캐스팅 된 Car 타입을 다시 Taxi 타입으로 다운캐스팅
taxi = (Taxi) car;
// Car 클래스로부터 상속받은 메서드
taxi.speedUp();
taxi.speedDown();
// Taxi 클래스에서 정의한 메서드
taxi.lift();
taxi.drop();
}
}
/*
* Car 클래스 정의
* - 메서드 정의 : 파라미터 없음, 리턴값 없음
* 1) speedUp() => "Car의 속력 증가!" 출력
* 2) speedDown() => "Car의 속력 감소!" 출력
*
* Truck 클래스 정의 -> Car 클래스 상속
* - 메서드 정의 : 파라미터 없음, 리턴값 없음
* 1) speedUp() / speedDown() 메서드 오버라이딩
* => "Truck의 속력 증가!" / "Truck의 속력 감소!" 출력
* 2) dump() => "Truck의 짐 싣기!" 출력
*
* Taxi 클래스 정의 -> Car 클래스 상속
* - 메서드 정의 : 파라미터 없음, 리턴값 없음
* 1) speedUp() / speedDown() 메서드 오버라이딩
* => "Taxi의 속력 증가!" / "Taxi의 속력 감소!" 출력
* 2) lift() => "Taxi의 승객 승차!" 출력
* 3) drop() => "Taxi의 승객 하차!" 출력
*
*/
class Car {
public void speedUp() {
System.out.println("Car의 속력 증가!");
}
public void speedDown() {
System.out.println("Car의 속력 감소!");
}
}
class Truck extends Car {
@Override
public void speedUp() {
System.out.println("Truck의 속력 증가!");
}
@Override
public void speedDown() {
System.out.println("Truck의 속력 감소!");
}
public void dump() {
System.out.println("Truck의 짐 싣기!");
}
}
class Taxi extends Car {
@Override
public void speedUp() {
System.out.println("Taxi의 속력 증가!");
}
@Override
public void speedDown() {
System.out.println("Taxi의 속력 감소!");
}
public void lift() {
System.out.println("Taxi의 승객 승차!");
}
public void drop() {
System.out.println("Taxi의 승객 하차!");
}
}
연습
package ex_polymorphism;
public class Test1 {
public static void main(String[] args) {
// Circle 인스턴스 생성
Circle c = new Circle();
c.rad = 3;
c.draw();
// Rectangle 인스턴스 생성
Rectangle r = new Rectangle();
r.line1 = 10;
r.line2 = 20;
r.draw();
// Triangle 인스턴스 생성
Triangle t = new Triangle();
t.a = 10;
t.b = 20;
t.c = 30;
t.draw();
System.out.println("============================");
Shape s = c; // 업캐스팅
s.draw(); // 서브클래스에서 오버라이딩 된 메서드 호출
s = r;
s.draw();
s = t;
s.draw();
System.out.println("============================");
shapeDraw(c);
shapeDraw(r);
shapeDraw(t);
System.out.println("============================");
Circle c2 = new Circle();
shapeDraw(c2); // Cricle -> Shape 업캐스팅
// 메서드 파라미터 전달 시 각 클래스 타입이 아닌
// 클래스들의 슈퍼클래스 타입의 매개변수로 전달받을 경우
// 하나의 메서드만으로도 여러 인스턴스 파라미터를 전달받을 수 있음!
Rectangle r2 = new Rectangle();
shapeDraw(r2);
Triangle t2 = new Triangle();
shapeDraw(t2);
Shape s2 = new Shape();
shapeDraw(s2);
} // main() 끝
// Circle, Rectangle, Triangle 타입 인스턴스를 하나의 메서드에서
// 모두 전달받으려면 업캐스팅 활용하여 파라미터 선언
// => 즉, 공통된 슈퍼클래스 타입인 Shape 타입의 변수를 메서드의 매개변수로
// 선언하면 모든 인스턴스를 하나로 전달 가능
public static void shapeDraw(Shape s) {
// 업캐스팅 후에도 공통된 메서드인 draw() 호출이 가능
s.draw();
}
// 다형성을 이용해 메서드의 파라미터를 구성할 때는 사위 타입을 잡는 것이 좋다!
// => 다만, 최상위의 Object까지 올라가면 별도의 형변환 절차가 필요해져서 번거룸이 커짐!
// =========================================================
// public static void shapeDraw(Circle x) {
// x.draw();
// }
//
// public static void shapeDraw(Rectangle x) {
// x.draw();
// }
//
// public static void shapeDraw(Triangle x) {
// x.draw();
// }
// 메서드 오버로딩을 통해 다른 타입의 파라미터를 전달받을 수는 있음
// => 코드의 중복이 발생함
}
/*
* 도형(Shape) 클래스 정의
* - draw() 메서드 정의 : 파라미터 없음, 리턴값 없음
* => "도형 그리기!" 출력
*
* 원(Circle) 클래스 정의 - 도형(Shape) 클래스 상속
* - 멤버변수 : 반지름(rad, 실수)
* - draw() 메서드 오버라이딩
* => "반지름 x을 사용하여 원 그리기!" 출력
*
* 사각형(Rectangle) 클래스 정의 - 도형(Shape) 클래스 상속
* - 멤버변수 : 두 직선의 길이(line1, line2, 정수형)
* - draw() 메서드 오버라이딩
* => "x, y 직선 두 개 사용하여 사각형 그리기!" 출력
*
* 삼각형(Triangle) 클래스 정의 - 도형(Shape) 클래스 상속
* - 멤버변수 : 세 꼭지점의 좌표(a, b, c, 정수형)
* - draw() 메서드 오버라이딩
* => "x, y, z 꼭지점 세 개 사용하여 삼각형 그리기!" 출력
*
*/
class Shape {
public void draw() {
System.out.println("도형 그리기!");
}
}
class Circle extends Shape {
double rad;
@Override
public void draw() {
System.out.println("반지름 " + rad + "을 사용하여 원 그리기!");
}
}
class Rectangle extends Shape {
int line1, line2;
@Override
public void draw() {
System.out.println(line1 + ", " + line2 + " 직선 두 개 사용하여 사각형 그리기!");
}
}
class Triangle extends Shape {
int a, b, c;
@Override
public void draw() {
System.out.println(a + ", " + b + ", " + c + " 꼭지점 세 개 사용하여 삼각형 그리기!");
}
}