다형성, 타입변환, 오버라이딩, 오버로딩

kmb·2022년 2월 3일
0

자바

목록 보기
13/31
post-thumbnail

다형성

같은 타입이지만 실행 결과가 다양한 결과가 나오는 성질.
즉 다형성은 하나의 타입에 여러개의 객체를 대입하여 다양한 기능을 이용할 수 있도록 하는것이 목적이다.

 

다형성을 위해 Java는
1. 부모 클래스로의 타입 변환을 허용한다.
2. 부모 타입에 모든 자식 객체가 대입 될 수 있다.

 
타입변환 : 데이터 타입을 다른 데이터 타입으로 변환하는 행위

자동 타입변환 : 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것.
자동 타입변환의 경우, 자식이 부모의 특징과 기능을 상속 받기 때문에 부모와 동일하게 취급된다.

 
예를들어 자식클래스인 Cat으로 부터 Cat 객체를 생성한다음 부모클래스인 Animal의 인스턴스변수에 대입하면 부모 클래스 타입으로 자동 타입 변환이 일어난다.
자식클래스의 인스턴스 변수인 cat과 부모 클래스의 인스턴스 변수인 animal은 동일하게 자식 클래스의 Cat 객체를 참조한다.
비록 인스턴스 변수가 자식객체를 참조하지만, 인스턴스 변수가 접근 가능한 멤버는 부모 클래스의 멤버로만 한정된다.
단, 메서드가 자식 클래스에서 오버라이딩 되었을 경우에는 자식 클래스의 메서드가 대신 호출된다.

결론

부모클래스 인스턴스변수 = new 자식클래스( ); 일때
자동 타입변환이 일어나며 인스턴스 변수는 자식 객체를 바라보지만, 인스턴스 변수는 부모 클래스의 멤버에만 접근 가능하다.
단 자식 클래스에서 오버라이딩 된 메서드의 경우는 자식 클래스의 메서드로 접근한다 (동적바인딩).

왜 저렇게 하나?

다형성을 위해서.
부모타입에 여러 자식객체를 대입해서 객체를 부품화 하기위해서.

 


 

ex) 부모 클래스(요리사)를 상속받는 자식 클래스(홍길동)의 다형성 예시


필드의 다형성

필드의 타입이 변함이 없지만, 실행 도중에 어떤 객체를 필드(field)로 저장하느냐에 따라서 실행 결과가 달라지는것.

필드의 다형성이 왜 필요하지?

객체 지향 프로그램에서 수많은 객체들이 서로 책임을 가지고 각자의 역할을 하게 되는데, 이 객체들이 다른 객체로 교체될 수 있어서 더 좋은 성능을 갖게 하기 위해.
(이를 위해 상속, 오버라이딩, 타입 변환을 이용)

 

매개변수의 다형성

메서드를 호출 할 때에는 매개변수의 타입과 동일한 매개값을 지정해야하지만, 다형성을 위하여 매개변수에 자신과 같은 타입의 객체 혹은 자식 타입의 객체를 지정 할 수 있는것.

 

  • ex) 매개변수의 다형성 예시
public class Vehicle {
	
    public void run() {
    	System.out.println("차량이 달린다");
    }
}

public class Driver {
	
    public void drive(Vehicle vehicle) {
    	vehicle.run();
    }
}

public class Bus extends Vehicle {
	@Override
    public void run() {
    	System.out.println("버스가 달린다");
    }
}

public class Taxi extends Vehicle {
	@Override
    public void run() {
    	System.out.println("택시가 달린다");
    }
}

public class DriverExample {
	
    public static void main(String[] args) {
    	
        Driver driver = new Driver();
        Bus bus = new Bus();
        Taxi taxi = new Taxi();
        
        					 //               부모클래스 인스턴스변수 = new 자식클래스( );
        driver.drive(bus);   // 자동 타입변환 --> Vehicle vehicle = bus;  
        				     //             --> Vehicle vehicle = new Bus();
        
        driver.drive(taxi);  // 자동 타입변환 --> Vehicle vehicle = taxi; 
    }						 //             --> Vehicle vehicle = new Taxi();
}

오버로딩(Overloading)

같은 함수명이지만 매개변수의 개수가 다르거나 자료형(type)이 다른경우 다른 함수로 인식하게 하는것.

 

  • 오버로딩의 장점

어느정도 경우의 수의 제한이 있다면 메서드 이름 1개를 가지고 여러개의 기능구현이 가능하다.

  • 오버로딩의 단점

경우의 수가 많을경우 메서드를 일일히 구현해야 하므로 좋지않다.

 

  • ex) 오버로딩 예시
package ch05;

class 전사 {
	String name = "전사";
	
	// 오버로딩 (메서드 이름 같고, 매개변수가 다름)
	void 기본공격(궁수 e1) {
		System.out.println("검으로 " + e1.name + " 공격");
	}
}

class 궁수 {
	String name = "궁수";
	
	// 오버로딩 (메서드 이름 같고, 매개변수가 다름)
	void 기본공격(광전사 e1) {
		System.out.println("활로 " + e1.name + " 공격");
	}
}

class 광전사 {
	String name = "광전사";
	
	// 오버로딩 (메서드 이름 같고, 매개변수가 다름)
	void 기본공격(전사 e1) {
		System.out.println("도끼로 " + e1.name + " 공격");
	}
}	


public class OverloadingEx {

	public static void main(String[] args) {
		전사 u1 = new 전사();
		궁수 u2 = new 궁수();
		광전사 u3 = new 광전사();

		u1.기본공격(u2); // 검으로 궁수 공격   
		u2.기본공격(u3); // 활로 광전사 공격 
		u3.기본공격(u1); // 도끼로 전사 공격

	}
}

오버라이딩(Overriding)

상속받은 슈퍼클래스의 메서드를 재정의해서 사용하는것.

 

  • 오버라이딩 특징

슈퍼클래스의 메서드를 무효화 시킬수 있지만, 동일한 참조변수이름을 사용 할 경우 슈퍼클래스 참조변수이름의 값을 사용한다. 따라서 서브클래스의 참조변수를 사용하려면 메서드안에 참조변수이름을 정의하여 사용하면 된다.

 

  • ex) 오버라이딩 예시
package ch05;

class 프로토스유닛 {
		String name = "프로토스 유닛";		
	
		String 이름확인() {	// 추상화를 통해 슈퍼클래스의 메서드 무효화
			return "?";
		}
		
		void 기본공격 (프로토스유닛 e1) {	// 추상화를 통해 슈퍼클래스의 메서드 무효화
			System.out.println("프로토스유닛 메서드");
		}
}

class 질럿 extends 프로토스유닛 {
		String name = "질럿";	
		
		String 이름확인() {
			return name;
		}
		
		// 오버라이드 : 부모의 메서드를 무효화한다 , 단 참조변수는 부모 참조변수값 사용
		void 기본공격 (프로토스유닛 e1) {
			System.out.println("질럿 메서드");
			System.out.println(this.name + "이 " + e1.이름확인() + "을 공격");
		}
}

class 드라군 extends 프로토스유닛 {
			String name = "드라군";
			
			String 이름확인() {
				return name;
			}
			
			// 오버라이드 : 부모의 메서드를 무효화한다 , 단 참조변수는 부모 참조변수값 사용
			void 기본공격 (프로토스유닛 e1) {
				System.out.println("드라군 메서드");
				System.out.println(this.name + "이 " + e1.이름확인() + "을 공격");
			}
}

class 다크템플러 extends 프로토스유닛 {
			String name = "다크템플러";
			
			String 이름확인() {
				return name;
			}
			
			// 오버라이드 : 부모의 메서드를 무효화한다 , 단 참조변수는 부모 참조변수값 사용
			void 기본공격 (프로토스유닛 e1) {
				System.out.println("다크템플러 메서드");
				System.out.println(this.name + "가 " + e1.이름확인() + "을 공격");
			}
}

public class OverridingEx {
	
	public static void main(String[] args) {
										//  디폴트 생성자, upcastring	
        프로토스유닛 u1 = new 질럿();		//  (질럿,        프로토스유닛 타입)
		프로토스유닛 u2 = new 드라군(); 	//  (드라군,      프로토스유닛 타입)
		프로토스유닛 u3 = new 다크템플러();	//  (다크템플러,   프로토스유닛 타입)
		
		u1.기본공격(u2);	// 동적바인딩 -->  슈퍼클래스 u1 = new 서브클래스(); 의 경우 둘다 같은 메서드 이름을 가질경우 동적바인딩에 의해 서브 메서드를 사용
		u2.기본공격(u1); 
		u3.기본공격(u1);
	}

}

 

출처

profile
꾸준하게

0개의 댓글