개발 일기

상속과 생성자 본문

카테고리 없음

상속과 생성자

flow123 2022. 3. 8. 16:47
package c.inheritance; 

public class ChildOverridingPrivate {
  public ChildOverridingPrivate() {
    System.out.println("ChildOverridingPrivate Constructor");
  }
  
  public void printName() {
    System.out.println("ChildOverridingPrivate printName()");
    }
    }​
package c.inheritance; 

public class ParentOverriding {
  public ParentOverriding() {
    System.out.println("ParentOverriding Constructor");
  }
  
  public void printName() {
    System.out.println("printName() - ParentOverriding");
    }
    }
package c.inheritance

public class ParentArg {
  public ParentArg(String name) {
    System.out.println("ParentArg("+name+") Constructor");
    }
    
    public void printName() {
      System.out.println("printName() - ParentArg");
      }
  }
package c.inheritance; 

public class ChildArg extends ParentArg {
  public ChildArg() {
    System.out.println("Child Constructor");
    }
  
  }

constructor ParentArg cannot be applied to given types 

public ChildArg() {

required:String

found: no arguments;

}

 

원인: 현재 ParentArg에는 String을 매개변수로 받는 생성자 뿐이다. 

ChildArg클래스의 생성자가 실행될 때, 부모인 ParentArg() 의 매개변수 없는 생성자도 실행되어야 한다.

 

해결

(1) 부모 클래스(ParentArg)에 매개변수 없는 기본 생성자 만들기 

(2) 자식 클래스에서 부모 클래스의 생성자를 명시적으로 지정하는 super 사용

super("ChildArg"); 라고 지정해주자. 

package c.inheritance; 

public class ChildArg extends ParentArg {
  public ChildArg() {
    super("ChildArg");
    System.out.println("Child Constructor");
    }
  
  }

 

 

참고: 자바는 기본적으로 부모의 매개변수가 없는 기본 생성자를 찾는다.

(1) 부모 클래스에 매개 변수가 있는 생성자만 있을 경우에는, super()를 이용해서 부모 생성자를 호출해야 한다. 

 

(2) 자식 클래스의 생성자에서 super()를 명시적으로 지정하지 않으면, 컴파일 시 자동으로 super()가 추가된다. 부모 클래스의 생성자를 호출하는 super()는 반드시 자식 클래스의 생성자에서 가장 첫줄에 선언되어야 한다. 

 

-> 두 번쨰는 조금 애매하다, 컴파일 시 자동으로 super()가 추가될 거라면, 굳이 super()를 왜 따로 명시해줘야 하지?  하는 의문이 들었다. 

 

메소드 오버라이딩을 보면 이 부분이 조금 명료해진다. 

아래 파일을 보자. 

 

package c.inheritance; 

public class InheritanceOverriding {
  public static void main(String[] args) {
    ChildOverriding child = new ChildOverriding(); 
    child.printName();
    }

 

package c.inheritance; 

public class ParentOverriding {
  public ParentOverriding() {
    System.out.println("ParentOverriding Constructor");
  }
  
  public void printName() {
    System.out.println("printName() - ParentOverriding");
    }
    }
package c.inheritance; 

public class ChildOverriding extends ParentOverriding{
  public ChildOverriding() {
    System.out.println("ChildOverriding Constructor");
  }
  
  public void printName() {
    System.out.println("ChildOverriding printName");
    }
    }

컴파일 후 실행하면, 생성자는 child의 부모인 Parent도 불러와지지만, 메서드는 Parent의 메서드가 불러지지 않는다 

부모 클래스에 선언되어 있는 메서드와 동일하게 (메소드 이름, 매개 변수의 타입 개수)선언되어 있는 메서드를 자식 클래스에 선언하면, 자식 클래스의 메서드만 실행된다. 

 

 

상속 관계에서 리턴타입/ 접근 제어자의 제한 

 

참고로 부모 클래스를 overriding한 메소드의 리턴 타입을 다르게 리턴하면 안된다. 

 

접근 제어자의 경우는, 코드를 통해서 보자. 

 

(1) ChildOverriding의 printName 접근제어자가 private으로 바뀐다면? 

package c.inheritance; 

public class ChildOverriding extends ParentOverriding{
  public ChildOverriding() {
    System.out.println("ChildOverriding Constructor");
  }
  
  private void printName() {
    System.out.println("ChildOverriding printName");
    }
    }

접근 제어자가 확대 되는 것은 문제되지 않지만, 축소되는 것은 문제가 된다. 

부모에서 public 으로 선언한 것을, 자식이 private 으로 선언할 수는 없다. 

 

접근 제어자가 확대될 때는 아래에서 보듯 문제가 없다. 

package c.inheritance; 

public class ParentOverridingPrivate {
  public ParentOverridingPrivate() {
    System.out.println("ParentOverridingPrivate Constructor");
  }
  
  private void printName() {
    System.out.println("System.out.println(""ParentOverridingPrivate printName()");
    }
    }

출처: 자바의 신 10장 

Comments