JAVA의 Class (6) 클래스의 상속과 오버라이딩

Updated:

Key point

  1. 상속 = 기존의 클래스를 확장시킨 것 (extends)
  2. 오버로딩 & 오버라이딩 다른 개념

1. 클래스의 상속

부모 클래스와 자식 클래스는 다음과 같이 정의되고 상속된다. 상속된 경우, 부모의 데이터와 메소드 기능을 사용할 수 있게 된다.

// 부모 클래스
Class 부모() {}

// 자식 클래스 
Class 자식 extends 부모() {}

Child 클래스, Parents 클래스를 생성하고 Parents를 부모 클래스, Child를 자식 클래스로 설정해보자.

Parents 클래스

package Pack04;
public class Parents {
	// 속성
	private String parentsData01;
	protected String parentsData02;
		
	// 디폴트 생성자
	public Parents() {System.out.println("Parents 객체 생성완료");}
	
	// Setter, Getter, Putter
	void setPData01(String x) { parentsData01 = x;}
	void setPData02(String x) { parentsData02 = x;}
	String getPData01() { return parentsData01;}
	String getPData02() { return parentsData02;}
	void putPData01() { System.out.println("Parents의 데이터01: "+parentsData01);}
	void puPCData02() { System.out.println("Parents의 데이터02: "+parentsData02);}
	
	// 기능 
	void test01(String x) {
		System.out.println("Parents의 기능 || 입력값: " + x );}
	}

Child 클래스

package Pack04;
public class Child extends Parents {
	// 속성
	private String childData01;	
	
	// Setter, Putter, Getter
	void setCData01(String x) { childData01=x; }
	void putCData() { System.out.println("Child의 데이터: "+childData01);}
	String getCData() { return childData01; }
	
	// 디폴트 생성자
	public Child() {System.out.println("Child 객체 생성완료");}		
}

Test 클래스를 통한 객체 생성

package Pack04;

public class TestPlay {
	public static void main(String[] args) {
		//1. Child 객체 생성
		Child tmp = new Child ();		
	}
}


Parent 클래스를 상속받은 Child 클래스의 객체를 생성하면 상속된 Parents 객체 또한 생성됨을 확인할 수 있다. 그 순서는 부모 클래스 객체 > 자식 클래스 객체 생성으로 진행된다.

img


2. 상속에 따른 접근

상속받는다고 해서 모든 데이터와 메서드에 접근 가능한 것은 아니다. 상태(private, protected, public)에 따라서 접근에 대한 제한이 있다. 객체화를 정말 잘 실현하기 위해서는 모든 속성을 private으로 두고, 상속받은 puuter, getter, setter 등의 메서드를 통해 해당 속성에 접근하는 것이 바람직하다.

  • Private : 동일 클래스에서만 접근 가능함
  • Protected : 상속받은 클래스, 동일 클래스에서 접근 가능함
  • Public : 다른 클래스에서도 접근 가능함


3. 오버라이딩 Overriding

조상이 가진 속성, 메서드를 모두 상속받았지만 조상의 메서드를 그대로 사용하기 싫은 경우(즉, 기능이 적합하지 않은 경우) 본인의 스타일(필요성)에 따라 바꾸는 것을 오버라이딩이라고 한다. 이 때, 중요한 것은 조상의 메서드(기능)와 이름 및 파라미터가 동일해야 한다.

위에서 작성된 Parents의 기능 메서드 중 하나를 Child 에서 상속받아서 오버라이딩 해보자.

Child - 오버라이딩 전

package Pack04;
public class Child extends Parents {
	// 속성
	private String childData01;	
	
	// Setter, Putter, Getter
	void setCData01(String x) { childData01=x; }
	void putCData() { System.out.println("Child의 데이터: "+childData01);}
	String getCData() { return childData01; }
	
	// 디폴트 생성자
	public Child() {System.out.println("Child 객체 생성완료");}		
}

TestPlay 실행 - 오버라이딩 전

img

Child - 오버라이딩 후

package Pack04;
public class Child extends Parents {
	// 속성
	private String childData01;	
	
	// Setter, Putter, Getter
	void setCData01(String x) { childData01=x; }
	void putCData() { System.out.println("Child의 데이터: "+childData01);}
	String getCData() { return childData01; }
	
	// 디폴트 생성자
	public Child() {System.out.println("Child 객체 생성완료");}
	
	// 오버라이딩 > 이 부분이 추가됨
	void test01(String x) {
		System.out.println("Parents의 기능 싫어서 바꿀래 || 입력값: " + x );}		
}

TestPlay - 오버라이딩 후

img


오버로드와 오버라이딩의 개념이 헷갈린다면 아래 글을 참고하도록 하자.
JAVA의 Class (7) 오버로딩과 오버라이딩


4. Super

상속을 받은 후손의 클래스에서 조상 클래스의 메소드나 속성에 접근하는 경우 명시적으로 알려주기 위해 사용한다. (물론 사용하지 않더라도 알아서 잘 찾아오지만 여러 클래스를 오가면서 사용되는 경우 혼란이 시작된다…) 예를 들어 위에서 사용한 코드를 보면, Parents를 상속받은 Child 클래스가 있다. 이 클래스에서 Parents 메서드를 사용할 때 아래와 같이 접근한다.

// Parents에 있는 기능
void putPData02() { System.out.println("Parents의 데이터02: "+parentsData02);}

// Child에서 조상 클래스의 기능을 가져오는 경우 > super 사용
void test02() {super.putPData02();}