상속,부모 생성자,메소드 재정의

서이·2022년 11월 16일
0

Java

목록 보기
20/27

클래스 상속

  • 새로운 클래스를 정의할 때 이미 구현된 클래스를 상속(inheritance) 받아서 속성이나 기능을 확장하여 클래스를 구현함
  • 이미 구현된 클래스보다 더 구체적인 기능을 가진 클래스를 구현해야 할 때 기존 클래스를 상속함

상속을 구현하는 경우

  • 상위 클래스는 하위 클래스 보다 더 일반적인 개념과 기능을 가짐
  • 하위 클래스는 상위 클래스 보다 더 구체적인 개념과 기능을 가짐
  • 하위 클래스가 상위 클래스의 속성과 기능을 확장 (extends)한다는 의미

 상속을 이용하면 클래스의 수정을 최소화 할 수도 있다. 부모 클래스의 수정으로 모든 자식 클래스들의 수정 효과를 가져오기 때문에 유지 보수 시간을 최소화시켜준다. 예를 들어 B,C가 클래스 A를 상속할 경우 A의 필드와 메소드를 수정함으로써 B,C를 수정하지 않아도 수정돈 A의 필드와 메소드를 이용할 수 있다.

 부모 클래스에서 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외된다. 그리고 부모 클래스와 자식 클래스가 다른 패키지에 존재한다면 default 접근 제한을 갖는 필드와 메소드도 상속 대상에서 제외된다. 그 이외의 경우는 모두 상속 대상이 된다.


부모 클래스의 기본 생성자 호출

 인스턴스를 생성하기 위해서는 반드시 생성자를 호출해야 한다. 부모 클래스로부터 상속받은 메소드 및 필드는 엄연히 부모 클래스에 정의된 것이고 부모의 것이다. 따라서 부모 클래스의 생성자가 호출되어야 자식 클래스에서 사용이 가능한 것이다. 하지만 생성자는 상속이 되지 않는다. 대신 자식 클래스로 인스턴스를 생성할 때 부모 클래스의 기본 생성자를 자동으로 호출하게 된다.

class SuperClass {
	public SuperClass() { // 부모 생성자
		System.out.println("부모 생성자 호출");
	}
}

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

public class InheritanceConstructorEx01 {
	public static void main(String[] args) {
		SubClass sc = new SubClass(); // 자식 인스턴스 생성
	}
}

 부모 클래스와 자식 클래스의 생성자를 각각 정의하고 main 메소드에서는 자식 클래스의 인스턴스를 생성하였다. 그 결과 자식 클래스의 생성자는 물론이고 부모 클래스의 기본 생성자 또한 자동적으로 호출되는 것을 알 수 있다. 이때 부모 클래스의 생성자가 먼저 호출되고 뒤이어 자식 클래스의 생성자가 호출된다.

 부모 클래스의 매개변수를 갖는 생성자 호출
위에서 설명한 것처럼 자식 클래스로 인스턴스를 생성할 때 자동적으로 부모 클래스의 기본 생성자가 호출된다. 다르게 말하면 매개변수를 갖는 부모 클래스의 생성자는 자동으로 호출되지 않는다. 소스코드를 통해 알아보자.

class SuperClass {
	public SuperClass(String str){
		System.out.println(str + "호출");
	}
}

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

public class InheritanceConstructorEx01 {
	public static void main(String[] args) {
		SubClass sc = new SubClass(); // 자식 인스턴스 생성
	}
}

 위 소스코드는 에러를 발생시킨다. 부모 클래스의 매개변수를 갖는 생성자를 호출할 수 없기 때문이다. 따라서 부모 클래스의 생성자를 반드시 호출을 해야 한다. 이때 에러 해결을 위해 부모 클래스의 기본 생성자를 추가할 수 있다. 하지만 좋은 방법은 아니다. 그러면 매개변수를 갖는 생성자의 호출 방법을 소스코드를 통해서 알아보자.

class SuperClass {
	public SuperClass(String str){
		System.out.println(str + "호출");
	}
}

class SubClass extends SuperClass{
	public SubClass() { // 자식 생성자
		super("부모 생성자 "); // 부모 생성자 호출
		System.out.println("자식 생성자 호출");
	}
}

public class InheritanceConstructorEx01 {
	public static void main(String[] args) {
		SubClass sc = new SubClass(); // 자식 인스턴스 생성
	}
}

 자식 생성자의 첫 줄에 super()라는 키워드를 추가했다. super는 부모를 의미하고 괄호(( )) 안에 매개값을 전달하여 부모 생성자를 호출하게 된다. 이때 주의해야 할 내용이 있다. super()는 반드시 자식 클래스 생성자의 첫 줄에 위치하여야 하며 부모 생성자의 매개변수와 동일한 타입을 매개값으로 작성해야 한다.

부모 클래스에 기본 생성자가 없고 매개 변수가 있는 생성자만 있다면 자식 생성자에서 반드시 부모 생성자 호출을 위해 super(매개값...) 를 명시적으로 호출해야 합니다. super(매개값...)는 반드시 자식 생성자 첫 줄에 위치해야 합니다.

public class Customer {
	protected int customerID;
	protected String customerName;
	protected String customerGrade;
	int bonusPoint;
	double bonusRatio;

	String agentID;
	double saleRatio;

	public Customer() {
		customerGrade = "SILVER";
		bonusRatio = 0.01;
		System.out.println("Customer() call");
	}

	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;

		return price;
	}

	
public class VIPCustomer extends Customer{
	
	double salesRatio;
	private String agentID;
	
	public VIPCustomer() {
		//컴파일러가 super(); 를 넣어줌  (디폴트 생성자)
		bonusRatio = 0.05;
		salesRatio = 0.1;
		customerGrade = "VIP";
		System.out.println("VIPCustomer() call");
		//customer쪽의 생성자가 먼저생성이 된다음에 VIP가 생성됨 그래서 
        //이름과 아이디를 만들수가있는거임
        
		//인스턴스 변수는 인스턴스가 생성될 때 생성된다. 
        //그렇기 때문에 인스턴스 변수의 
        //값을 읽어오거나 저장하려면 인스턴스를 먼저 생성해야한다.
        
		//인스턴스 변수는 객체가 생성될 때니까 부모생성자가 생성될때
        //(객체가 생성될때)니까 제일 위에 말이 나오는거임
	}
	
	public String getAgentID() {
		return agentID;
	}
}



요약
1. 부모 클래스의 생성자는 상속되지 않고, 자식 클래스로 인스턴스를 생성할 때 자동적으로 부모의 기본 생성자가 호출된다.
2. 부모 생성자가 매개변수를 갖고 있다면 자식 클래스를 인스턴스화할 때 자동으로 호출되지 않는다.
3. 따라서 자식 생성자에서 명시적으로 부모 생성자를 호출해야 한다. 이때 사용되는 키워드가 super(); 이다. 단, super()를 사용할 때는 자식 생성자의 첫 줄에 위치하여야 한다.


메서드 재정의하기(overriding)
하위 클래스에서 메서드 재정의 하기

  • 오버라이딩(overriding) : 상위 클래스에 정의된 메서드의 구현 내용이 하위 클래스에서 구현할 내용과 맞지 않는 경우 하위 클래스에서 동일한 이름의 메서드를 재정의 할 수 있음.

메소드가 오버라이딩되었다면 부모 객체의 메소드는 숨겨지기 때문에 자식 객체에서 메소드를 호출하면 오버라이딩된 자식 메소드가 호출된다.

메소드를 오버라이딩할 때는 다음과 같은 규칙에 주의해서 작성해야한다.

  • 부모의 메소드와 동일한 리턴타입,메소드 이름, 매개 변수 리스트를 가져야한다.
  • 접근 제한을 더 강하게 오버라이딩할 수 없다.
  • 새로운 예외(Exception)를 throws할 수 없다.

자식 클래스에서 부모 클래스의 메소드를 오버라이딩하게 되면, 부모 클래스의 메소드는 숨겨지고 오버라이딩된 자식 메소드만 사용된다. 그러나 자식 클래스 내부에서 오버라이딩된 부모 클래스의 메소드를 호출해야 하는 상황이 발생한다면 명시적으로 super 키워드를 붙여서 부모 메소드를 호출할 수 있다. super는 부모 객체를 참조하기 때문에 부모 메소드에 직접 접근할 수 있다.

class Parent {
	void method1(){...}
    void method2(){...}
}

class Child extends Parent {
	void method2() {...} //overriding (재정의된 호출)
    void method3() {...}
    super.method2(); // 부모 메소드 호출
}
profile
작성자 개인이 잊을 때마다 보라고 정리한 글

0개의 댓글

관련 채용 정보