매개 변수의 다형성
다형성 : 객체 사용 방법은 동일하지만 실행결과가 다양하게 나오는 성질을 말함
기능 수정 x, 기능 추가
자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생
메소드를 호출할 때에는 매개 변수의 타입과 동일한 매개값을 지정하는 것이 정석이지만,
매개값을 다양화하기 위해 매개 변수에 자식 객체를 지정할 수도 있음
외우기
선언
public class Driver {
public void drive( Vehicle vehicle) {
vehicle.run();
}
}
호출
public class DriverEx {
public static void main(String[] args) {
Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
driver.drive(vehicle);
Vehicle의 자식 클래스인 Bus 객체를 drive() 메소드의 매개값으로 넘겨준 경우

drive() 메소드는 Vehicle 타입을 매개 변수로 선언했지만, Vechicle을 상속받는 Bus 객체가
매개값으로 사용되면 자동 타입 변환이 발생
매개변수의 타입이 클래스일 경우, 해당 클래스의 객체뿐만 아니라 자식 객체까지도 매개값으로
사용할 수 있다.
즉, 매개값으로 어떤 자식 객체가 제공되느냐에 따라 메소드의 실행결과는 다양해질 수 있다.
자식 객체가 부모의 메소드를 재정의했다면 메소드 내부에서 재정의된 메소드를 호출함으로써
메소드의 실행결과는 다양해진다.
Vehicle => 자식 객체
void drive(Vehicle vehicle) {
vehicle.run(); <= 자식 객체가 재정의한 run() 메소드 실행
}
매개 변수의 다형성 예제 1
부모
package sec02.exam09;
//매개 변수의 다형성
public class Vehicle {
public void run() {
System.out.println("차량이 달린다.");
}
}
Vehicle을 이용하는 클래스
package sec02.exam09;
//매개 변수의 다형성
public class Driver {
//drive()메소드에서 Vehicle 타입의 매개값을 받아서 run()메소드를 호출
public void drive( Vehicle vehicle) {
vehicle.run();
//Pony pony = (Pony) vehicle;// 강제 타입 변환
}
}
자식 1
package sec02.exam09;
//매개 변수의 다형성
public class Bus extends Vehicle {
@Override
public void run() {
System.out.println("버스가 달린다.");
}
}
자식 2
package sec02.exam09;
//매개 변수의 다형성
public class Pony extends Vehicle {
@Override
public void run() {
System.out.println("포니 달린다.");
}
}
자식 3
package sec02.exam09;
//매개 변수의 다형성
public class Taxi extends Vehicle {
@Override
public void run() {
System.out.println("택시가 달린다.");
}
}
실행
package sec02.exam09;
// 매개 변수의 다형성
public class DriverEx {
public static void main(String[] args) {
Driver driver = new Driver();
Vehicle vehicle = new Vehicle();
driver.drive(vehicle);
Pony pony = new Pony();
driver.drive(pony);//자동 타입 변환:Vehicle vehicle = pony;
Bus bus = new Bus();
driver.drive(bus);//자동 타입 변환:Vehicle vehicle = bus;
Taxi taxi = new Taxi();
driver.drive(taxi);//자동 타입 변환:Vehicle vehicle = taxi;
}
}
< 결과 >
차량이 달린다.
포니 달린다.
버스가 달린다.
택시가 달린다.
매개 변수의 다형성 예제 2
부모
package sec02.exam09_02;
// 매개 변수의 다형성
public class Animal {
void eat() {
System.out.println("먹는다");
}
}
Animal을 이용하는 클래스
package sec02.exam09_02;
//매개 변수의 다형성
public class Feed {
void feed(Animal animal) {
animal.eat();
}
}
자식
package sec02.exam09_02;
//매개 변수의 다형성
public class Dog extends Animal {
@Override
void eat() {
System.out.println("개가 먹는다.");
}
}
실행
package sec02.exam09_02;
//매개 변수의 다형성
public class FeedEx {
public static void main(String[] args) {
Feed feed = new Feed();
Dog dog = new Dog();
feed.feed(dog);
// dog 객체를 feed 메서드의 매개변수로 전달
}
}
< 결과 >
개가 먹는다.
강제 타입 변환
강제 타입 변환은 부모 타입을 자식 타입으로 변환하는 것을 말함
그렇다고 해서 모든 부모타입을 자식 타입으로 강제 변환할 수 있는 것은 아님자식 타입이 부모 타입으로 자동 타입 변환한 후 다시 자식 타입으로 변환할 때 강제 타입 변환을 사용할 수 있다.


자식 타입이 부모 타입으로 자동 타입 변환하면, 부모에 선언된 필드와 메소드만 사용 가능하다는
제약 사항이 따른다.
만약 자식에 선언된 필드와 메소드를 꼭 사용해야 한다면 강제 타입 변환을 해서 다시 자식 타입으로
변환한 다음 자식의 필드와 메소드를 사용하면 된다.

field2 필드와 method3() 메소드는 Child 타입에만 선언되어 있으므로 Parent 타입으로 자동 타입
변환하면 사용할 수 없다.
field2 필드와 method() 메소드를 사용하고 싶다면 다시 Child 타입으로 강제 타입 변환을 해야 한다.
강제 타입 변환 실습 예제
부모
package sec02.exam09_03;
// 강제 타입 변환
public class Parent {
public String field1;
public void method1() {
System.out.println("parent-method1");
}
public void method2() {
System.out.println("parent-method2");
}
}
자식
package sec02.exam09_03;
//강제 타입 변환
public class Child extends Parent {
public String field2;
public void method3() {
System.out.println("Child-method3");
}
}
실행
package sec02.exam09_03;
//강제 타입 변환
public class ChildEx {
public static void main(String[] args) {
// Parent p1 = new Parent();
// Child c1 = (Child) p1; // 컴파일 에러
// 필드 다형성
Parent parent = new Child();
parent.field1 = "aaa";
//parent.field2 = "bbb";// 자식만 가지고 있어서 에러
parent.method1();
parent.method2();
// parent.method3(); // 자식만 가지고 있어서 에러
// 강제 형변환시 가능
Child child = (Child) parent;
child.field2 = "bbb";
child.method1();
child.method2();
child.method3();
}
}
< 결과 >
parent-method1
parent-method2
parent-method1
parent-method2
Child-method3
객체 타입 확인
강제 타입 변환은 자식 타입이 부모 타입으로 변환되어 있는 상태에서만 가능하기 때문에 다음과 같이
처음부터 부모 타입으로 생성된 객체는 자식 타입으로 변환할 수 없다.
Parent parent = new Parent();
Child child = (Child) parent; // 강제 타입 변환을 할 수 없음
부모 변수가 참조하는 객체가 부모 객체인지 자식 객체인지 확인하는 방법은 instanceof 연산자 사용
어떤 객체가 어떤 클래스의 인스턴스인지 확인하기 위해 instanceof 연산자를 사용함
boolean result = 좌항(객체) instanceof 우항(대입)
instanceof 연산자의 좌항에는 객체가 오고 우항에는 타입이 오는데, 좌항의 객체가 우항의 인스턴스이면
즉 우항의 타입으로 객체가 생성되었다면 true를 리턴하고 그렇지 않으면 false를 리턴 한다.
instanceof 연산자는 주로 매개값의 타입을 조사할 때 사용됨
메소드 내에서 강제 타입변환이 필요할 경우 반드시 매개값이 어떤 객체인지 instanceof 연산자로 확인하
고 안전하게 강제 타입 변환을 해야 한다.
만약 타입을 확인하지 않고 강제 타입 변환을 시도한다면 ClassCastException이 발생할 수있음
객체 타입 확인 실습 예제
부모
package sec02.exam09_04;
//객체 타입 확인
public class Parent {
}
자식
package sec02.exam09_04;
//객체 타입 확인
public class Child extends Parent {
}
실행
package sec02.exam09_04;
//객체 타입 확인
public class InstanceofEx {
// instanceof 연산자로 변환 가능한지 확인한 후 변환
public static void method1(Parent parent) {
if(parent instanceof Child) {// Child 타입으로 변환이 가능한지 확인
Child child = (Child) parent;
System.out.println("method1 - Child로 변환 성공");
}else {
System.out.println("method1 - Child로 변환되지 않음");
}
}
//Parent 객체를 Child 타입으로 강제로 변환
public static void method2(Parent parent) {
Child child = (Child) parent;// ClassCastException 발생할 가능성 있음
System.out.println("method2 - Child로 변환 성공");
}
public static void main(String[] args) {
Parent parentA = new Child();// Child 객체를 Parent 타입으로 참조
method1(parentA);// Child 객체를 매개값으로 전달
method2(parentA);
Parent parentB = new Parent();// Parent 객체를 생성
// parentB 객체는 Child 타입으로 변환할 수 없으므로 "method1 - Child로 변환되지 않음"이 출력
method1(parentB); // Parent 객체를 매개값으로 전달
// parentB 객체는 Child 타입으로 변환할 수 없음
method2(parentB); // 예외 발생
}
}
< 결과 >
method1 - Child로 변환 성공
method2 - Child로 변환 성공
method1 - Child로 변환되지 않음
Exception in thread "main" java.lang.ClassCastException:
그외 실습
static 메서드 호출 방식
package sec02.exam09_04;
//static 메서드 호출 방식
public class TestExStatic {
public void bbb() {
System.out.println("bbb()");
}
public static void aaa() {
System.out.println("aaa()");
}
public static void main(String[] args) {
aaa();
TestExStatic t1 = new TestExStatic();
t1.bbb();
}
}
확인 문제 2번
부모
package sec02.exam09_05;
//확인 문제 2번
//SnowTireEx 실행 시켰을 때 출력 결과는?
public class Tire {
public void run() {
System.out.println("일반 타이어가 굴러갑니다.");
}
}
자식
package sec02.exam09_05;
// 확인 문제 2번
// SnowTireEx 실행 시켰을 때 출력 결과는?
public class SnowTire extends Tire {
@Override
public void run() {
System.out.println("스노우 타이어가 굴럽갑니다.");
}
}
실행
package sec02.exam09_05;
//확인 문제 2번
//SnowTireEx 실행 시켰을 때 출력 결과는?
public class SnowTireEx {
public static void main(String[] args) {
SnowTire snowTire = new SnowTire();
Tire tire = snowTire;
//재정의
snowTire.run();
tire.run();
}
}
< 결과 >
스노우 타이어가 굴럽갑니다.
스노우 타이어가 굴럽갑니다.
확인 문제 3번
상속 관계
package sec02.exam09_05;
//확인 문제 3번
public class A {}
class B extends A{}
class D extends B{}
class E extends B{}
class C extends A{}
class F extends C{}
실행
package sec02.exam09_05;
// 확인 문제 3번
// A, B, C, D, E, F 클래스 상속 관계 빈 칸에 들어올 수 없는 코드
public class Ex1 {
public static void method(B b) {}
public static void main(String[] args) {
// B b = new B();
// method(new B()); 가능
// B b = (B) new A();// 에러는 안나오지만 실행시키면
// method((B) new A());// ClassCastException 발생
// B b = new D();
// method(new D()); 가능
// B b = new E();
// method(new E()); 가능
}
}
확인 문제 4번
상속 관계 정의
package sec02.exam09_05;
//확인 문제 4번
//Controller 클래스의 setService() 메소드를 호출하려고 한다.
// setService() 메소드의 매개값으로 올 수 있는 것은?
class Service{}
public class MemberService extends Service {}
class Aservice extends MemberService{}
class Bservice extends MemberService{}
class BoardService extends Service{}
class Dservice extends BoardService{}
메소드 정의
package sec02.exam09_05;
public class Controller {
public MemberService service;
public void setService(MemberService service) {
this.service = service;
}
}
실행
package sec02.exam09_05;
//확인 문제 4번
//Controller 클래스의 setService() 메소드를 호출하려고 한다.
//setService() 메소드의 매개값으로 올 수 있는 것은
public class ControllEx {
public static void main(String[] args) {
Controller controller = new Controller();
// 불가능
// controller.setservice(new Service());
// 상속관계에 있지 않으므로 매개값으로 전달할 수 없음
// 가능
// controller.setService(new MemberService());
// Service 클래스를 상속받았으므로 매개값으로 전달할 수 있음
// 가능
// controller.setService(new Aservice());
// MemberService 클래스를 상속받았으므로 매개값으로 전달할 수 있음
// 가능
// controller.setService(new Bservice());
// MemberService 클래스를 상속받았으므로 매개값으로 전달할 수 있음
// 불가능
// controller.setService(new BoardService());
// Service 클래스와 상속관계가 없으므로 매개값으로 전달할 수 없음
// 불가능
// controller.setService(new Dservice());
// BoardService 클래스를 상속받았으나, Controller 클래스의 setService() 메서드에 전달할 수 있는
// 매개값은 MemberService와 그 하위 클래스들뿐이므로 매개값으로 전달할 수 없음
}
}
'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글
2023-06-09 16일차 (0) | 2023.06.09 |
---|---|
2023-06-08 15일차 (0) | 2023.06.08 |
2023-06-02 13일차 (0) | 2023.06.02 |
2023-06-01 12일차 (0) | 2023.06.01 |
2023-05-31 11일차 (0) | 2023.05.31 |