JAVA - 다형성

박종휘·2022년 10월 27일
0

JAVA - 국비

목록 보기
17/29
post-thumbnail

1. 다형성 - 오버라이드

  • 클래스 다이어그램에서 육군(Army), 해군(Navy), 공군(AirForce)은 Unit이라는 클래스를 통하여 공통 속성을 정의하고 있다.
  • 공통속성 : 이름(멤버변수 및 getter, setter), 공격(attack() 메서드)
  • 같은 이름이지만 다른 동작을 수행해야 하는 필요성
    -> 모든 군대는 '공격'이라는 공통된 특성을 갖지만, 공격하는 방법은 육/해/공군이 서로 다르게 처리되어야 한다.
  • 부모 클래스가 갖고 있는 기능을 자식 클래스가 재정의
    -> 부모 클래스에 정의된 것과 동일한 이름을 갖는 메서드를 자식 클래스가 정의한 경우, 부모 클래스의 기능은 자식에게 가려진다.
    -> 이렇게 부모의 기능을 재정의 하는 것을 메서드 Override라 한다.
  • 하나의 이름으로 다양한 효과 얻기
    -> 모든 자식 클래스가 동일한 이름의 메서드를 갖게 되므로 각 객체에 대하여 attack()이라는 이름을 사용하여 서로 다른 형태를 구현할 수 있게 된다.

// 부모클래스
class Hello{
	public void say() {
		System.out.println("Hello");
	}
}

// 자식
class English extends Hello{
	
}

// 자식
class Korean extends Hello{
	public void say() {
		System.out.println("안녕하세요.");
	}
}

public class Main01 {

	public static void main(String[] args) {
		English e = new English();
		// 자식 클래스에 구현된 메서드가 없기 때문에,
		// 부모 클래스에 정의된 메서드를 찾아가게 된다.
		e.say();
		
		// 자식클래스가 부모와 같은 이름의 메서드를 정의하고 있기 때문에
		// k객체에게는 부모 클래스가 정의하고 있는 say()메서드가
		// 가려지게 된다.
		Korean k = new Korean();
		k.say();
	}
}

* 부모 클래스 값도 호출하고 자식 클래스 값도 호출하고 싶을 때
-> Super 사용
result

Hello
안녕하세요.

1-1. Super 키워드

  • 클래스의 상속 관계에서 자식 클래스가 부모 클래스를 가리키는 예약어

  • 사용방법

    • 멤버변수 이름 앞에 명시
      : 부모 클래스의 멤버변수를 의미한다. 하지만 부모 클래스의 멤버변수는 이미 모두 상속되어 있기 때문에 이 경우에는 this키워드를 사용하는 것과 동일한 결과이기에 잘 사용하지 않는다.

    • 메서드 이름 앞에 명시
      : 부모 클래스의 메서드를 의미한다
      : 재정의(Override) 되지 않은 메서드
          - 이미 상속되어 있기 때문에 this 키워드를 사용하는 것과 동일한 결과를 갖는다.
      : 재정의(Override) 된 메서드
          - Override 된 메서드 이름 앞에 사용하게 되면 재정의되기 이전의 원본 메서드를 의미한다.

class HelloP{
	/*
	 * 자식 클래스에서 이 메서드를 재정의 하였기 때문에,
	 * Korean 클래스의 객체는 이 기능에 접근하지 못한다.
	 */
	public void say() {
		System.out.println("Hello!!!!!~~~~~~");
	}
}

class KoreanC extends HelloP{
	/*
	 * Korean 클래스가 say()메서드를 Override 처리하게 되면
	 * Korean 클래스의 객체는 더 이상 부모의 say() 메서드에 
	 * 접근할 수 없게 된다.
	 */
	public void say() {
		/*
		 * 원본 기능에 대한 수정이 발생 할 경우 부모 클래스와 자식 클래스를
		 * 모두 수정해야 하기 때문에 소스코드의 유지보수 효율성이 떨어지게 된다.
		 */
		//System.out.println("Hello!!!!!");
        
		/*
		 * - super 키워드는 부모 클래스의 메서드를 호출하는 기능을 가지고 있기 때문에
		 * Override 된 자식 클래스의 메서드에서 super 키워드를 사용하면,
		 * 재정의 되기 이전의 부모 클래스에 대한 메서드를 호출할 수 있다.
		 *
         * - super 키워드를 사용하여 부모의 메서드를 호출한 뒤에 추가적인 기능을
		 * 정의하고 있으므로, 부모의 원본 메서드에 대한 기능 확장 효과가 있다.
		 */
		super.say();
		System.out.println("안녕하세요.");
	}
	
}

public class Main02 {

	public static void main(String[] args) {
		KoreanC k = new KoreanC();
		k.say();
	}
}
result

Hello!!!!!~~~~~~
안녕하세요.
  • 키워드 자체를 메서드처럼 사용
    : super()
    : 부모 클래스의 생성자를 의미한다.

1-2. 상속 관계에서의 생성자 처리

  • 생성자가 정의된 클래스의 상속 제한
  • 생성자는 상속되지 않는다.
  • 하지만 생성자가 정의된 클래스는 객체 생성을 위해서 생성자 파라미터를 반드시 전달받아야 하기 때문에, 파라미터를 갖는 생성자가 정의된 클래스를 상속받게 되면 에러가 발생된다.
class Hello3{
	public Hello3( String msg ) {
		System.out.println(msg);
	}
}

class Korean3 extends Hello3 {
	/*
	 * 부모와 동일한 파라미터를 받도록 생성자를 정의하고,
	 * 전달받은 파라미터를 부모에게 재전달 한다.
	 */
	public Korean3( String msg ) {
		super( msg );
	}
}

public class Main03 {

	public static void main(String[] args) {
		
	}
}
  • 부모 생성자의 강제 호출
    • 생성자가 정의된 클래스를 상속받은 경우에는 자식 클래스의 생성자를 통해서 부모 생성자를 강제로 호출해야 한다.
    • 부모의 생성자를 호출하는 방법은 super() 키워드를 메서드 이름으로 사용하는 것이다.
// 부모
class PClass1{
	public PClass1() {
		System.out.println("부모 생성자 호출");
	}
}

// 자식
class CClass1 extends PClass1{
	public CClass1() {
		super();
		System.out.println("자식 생성자 호출");
	}
}

public class Main04 {

	public static void main(String[] args) {
		CClass1 cClass = new CClass1();
	}
}

* 기본 생성자
result

부모 생성자 호출
자식 생성자 호출

// 부모
class PClass2{
	public PClass2( String str ) {
		System.out.println("부모 생성자 호출 : " + str);
	}
}

// 자식
class CClass2 extends PClass2{
	public CClass2( String str ) {
//		super("부모 생성자");
		super(str);
		System.out.println("자식 생성자 호출");
	}
}

/*
 *  - 부모클래스의 생성자는 상속되지 않고, 자식 클래스로 객체를 생성할 때
 *  자동적으로 부모의 기본 생성자로 호출
 *  - 부모 생성자가 매개변수를 갖고 있다면 자식 클래스를 객체화 할때 자동으로
 *  호출되지 않는다.
 *  - 따라서 자식 생성자에서 명시적으로 부모 생성자를 호출해야 한다.
 *  이때 사용되는 키워드가 super()이다. 단, super()를 사용할때
 *  자식 생성자의 첫 줄에 위치해야 한다.
 */

public class Main05 {

	public static void main(String[] args) {
		CClass2 cClass2 = new CClass2("부모 생성자");
	}
}

* 파라미터를 갖는 생성자
result

부모 생성자 호출 : 부모 생성자
자식 생성자 호출

1-3. 메서드 재정의 과정에서 오타가 발생한 경우

  • 부모 클래스의 say() 메서드를 재정의 하는 과정에서 개발자의 실수로 인해 "sai()"라고 메서드가 추가되었다면, Java는 새로운 메서드를 추가한것으로 인식하고, 특별한 에러를 표시하지 않는다.
  • say() 메서드가 재정의 된 것을 생각한 개발자는 이 경우 의도하지 않은 결과를 만나게 될 것이다.

1-4. @Override 옵션 -> Annotation

  • "@Override"은 이 키워드가 명시된 위치 아래에 정의되는 메서드가 부모 클래스에 존재하지 않을 경우 구문 에러로 처리한다.
  • 부모 클래스의 메서드를 재정의 하고자 할 경우 의도치 않은 실수를 예방하기 위한 '오타 방지 옵션'이다.
  • 여러 개의 메서드를 재정의한다면 재정의되는 모든 메서드 위에 각기 명시해야 한다.
profile
개린이의 개발 고수되기 작전!

0개의 댓글