[Java] 08_상속(Inheritance, 오버라이딩)

2022. 8. 8. 10:33·📗 self-study/📗 KH정보교육원 당산지원

08_상속(Inheritance)

 

 매 클래스마다 중복된 코드들을 일일이 기술하면

수정과 같은 유지보수 시 매번 일일이 찾아서 수정해야 한다는 번거로움이 생김
  
 => "상속"이라는 개념을 적용시켜서 매 클래스마다 중복된 필드, 중복된 메소드들을 단 한 번 또 하나의 클래스로 정의해 둔 후
      해당 클래스를 가져다 쓰는 방식으로 진행 
  
 *상속
 다른 클래스가 가지고 있는 필드, 메소드들을 새로 작성할 클래스에서 직접 만들지 않고
 이미 만들어진 클래스에서 "상속" 받음으로서 자신의 필드, 자신의 메소드처럼 사용 가능한 개념
 => 즉, 코드를 물려받겠다
  
* 코드를 물려받는 측 -------> 코드를 물려주는 측
              자식                                           부모
              후손                                           조상
              하위                                           상위

 

// 부모 클래스: 세 클래스 모두 공통적으로 기술했던 요소들만 추출해서 단 한 번 정의해 둔 클래스

package com.kh.chap01.beforeVSafter.after.model.vo;

// 부모 클래스: 세 클래스 모두 공통적으로 기술했던 요소들만 추출해서 단 한 번 정의해 둔 클래스
public class Product {
	
	// 필드부
	private String brand;
	private String pCode;
	private String pName;
	private int price;
	
	// 생성자부
	
	public Product() {
		
	}
	
	public Product(String brand, String pCode, String pName, int price) {
		this.brand = brand;
		this.pCode = pCode;
		this.pName = pName;
		this.price = price;
	}
	
	// 메소드부
	
	public String getBrand() {
		return brand;
	}
	
	public void setBrand(String brand) {
		this.brand = brand;
	}
	
	public String getpCode() {
		return pCode;
	}
	
	public void setpCode(String pCode) {
		this.pCode = pCode;
	}
	
	public String getpName() {
		return pName;
	}
	
	public void setpName(String pName) {
		this.pName = pName;
	}
	
	public int getprice() {
		return price;
	}

	public void setPrice(int price) {
		this.price = price;
	}
	
	public String information() {
		return "brand: " + brand + ", pCode: " + pCode + ", pName: " + pName + ", price: " + price;
	}
}

 

// 자식 클래스: 부모 클래스로부터 중복된 코(필드, 메소드)를 물려받아 사용하는 클래스 - 생성자는 물려받지 않음
// => 자식 클래스에서 우선적으로 해야 할 것: 누구로부터 코드를 물려받을 것인지 언급하기!!

package com.kh.chap01.beforeVSafter.after.model.vo;

// 자식 클래스: 부모 클래스로부터 중복된 코(필드, 메소드)를 물려받아 사용하는 클래스 - 생성자는 물려받지 않음
// => 자식 클래스에서 우선적으로 해야 할 것: 누구로부터 코드를 물려받을 것인지 언급하기!!

	   // 자식  ------->  부모
	   // 후손            조상
    	   // 하위            상위
	   // 서브            슈퍼
public class Desktop extends Product {
	
	// 필드부
	private boolean allInOne; // Product에서 4개의 필드를 상속받았으므로 Desktop의 필드는 5개가 됨
	
	// 생성자부
	public Desktop() {
		
	}
	
	
	// 메소드부
	public boolean isallInOne() {
		return allInOne;
	}
	
	public void setallInOne(boolean allInOne) {
		this.allInOne = allInOne;
	}

}

이렇게 상속받고 나면 자식 클래스를 메인 메소드에 등록했을 때

부모 클래스의 메소드까지 함께 불러올 수 있음!

 

하지만 매개변수를 사용하고 싶다면?

=> 상속에서는 필드, 메소드를 가지고 올 뿐 생성자는 가지고 오지 못함!

자식 클래스에 생성자를 추가해 보려고 했지만 is not visible 오류가 뜸

=> this. 은 나의 주소값, super. 은 부모의 주소값을 가지고 오므로 this.  -> super.으로 바꾸어 주기

하지만! 기존 필드가 private이므로 여전히 is not visible 오류가 뜨면서 생성자를 만들 수 없음

 

*해결 방법1: private -> protected로 접근 제한자를 변경

=> 단, 이 방법 사용 시 정보은닉(캡슐화)를 어긴 꼴이 됨!

 

*해결 방법2: 부모 클래스에 있는 public 접근 제한자인 setter 메소드를 호출해서 필드값을 채워 넣는 방법

// 상속 관계에서 부모 클래스에 있는 메소드에 직접 접근 하고자 할 경우 super.메소드명()으로 호출

=> setter 값을 매번 입력해 줘야 하는 번거로움 있음

 

// 해결 방법3: 부모 클래스에 있는 매개변수 생성자를 호출하기(== super 생성자 호출)

// 상속관계에서 부모 클래스에 있는 생성자를 호출하고자 할 경우 super 생성자를 호출
// => 내 안에 있던 생성자를 호출할 경우 this 생성자를 호출했었음! (반드시 생성자의 가장 윗줄에 호출 구문 작성)

// super(); // 부모의 기본 생성자가 호출이 됨

 

이 방법들을 이용하면 이제 Run 클래스에서 호출도 잘됨

 

하지만 현재 부모 클래스에서 만들어 둔 information() 메소드를 호출했기 때문에 자식 클래스의 값들이 출력되지 않음

// 출력
		System.out.println(d.information());
		System.out.println(s.information());
		System.out.println(t.information());
		
       
       
// 현재 출력물
brand: 삼성, pCode: d-01, pName: 짱짱데스크탑, price: 2000000
brand: 애플, pCode: s-01, pName: 아이폰, price: 1300000
brand: 엘지, pCode: t-01, pName: 고오급벽걸이티비, price: 4000000

 

실행하고자 하는 메소드가 부모 클래스에만 있고 자식 클래스에는 없음
자식 클래스에서는 부모 클래스의 내용을 가져다 쓸 수 있지만
부모 클래스에서는 자식 클래스의 내용을 가져다 쓸 수가 없다!! => 상속 구조의 가장 핵심적인 특징
자식 클래스 입장에서 물려받은 부모 클래스의 메소드를 내 입맛대로 재정의해서 쓸 수 있음 (오버라이딩)
=> 오버라이딩 시 해당 메소드를 호출했을 때 오버라이딩된 자식 메소드가 우선적으로 호출됨(동적 바인딩)


 *주의사항
 오버로딩이랑 헷갈리면 안 됨!
 오버로딩: 상속과는 관련 없이 메소드명을 동일하게 여러 개 만들 수 있는 규칙
                  메소드명 동일, 매개변수의 자료형의 종류, 순서, 개수가 다르면 중복된 이름이 가능
 오버라이딩: 상속과 관련 있는 개념으로 
                     "상속 관계에서" 부모 메소드의 내용물을 자식이 내 입맛대로 재정의해서 사용 가능
                      메소드 틀(접근제한자, 반환형, 메소드명, 매개변수) 동일해야 함

 

//// --------------- Desktop 클래스 -------------
// 오버라이딩 작업(information 메소드)
	public String information() {
		// return "brand: " + super.getBrand() + ", pCode: " + super.getpCode() + ", pName: " + super.getpName()
		// + ", price: "  + super.getPrice() + ",allInOne: " + allInOne; 
		return super.information() + ", allInOne: " + allInOne;
	}


//// --------------- SmartPhone 클래스 -------------
	public String information() {
			return super.information() + ", mobileAgency: " + mobileAgency;
		}
       
       
//// --------------- Tv 클래스 -------------        
       public String information() {
			return super.information() + ", inch: " + inch;
		}

자식 클래스에 부모 클래스의 information 메소드를 불러 온 뒤 + 자식 클래스의 값을 따로 information 메소드 만드는 것과 같ㅇ느 방법으로 추가해 줌

super.information() +  "출력하고 싶은 문자" + 자식클래스필드명

만들어 주고 난 후 다시 출력하면

 

**상속의 과정

1) public class 클래스명 extends 부모클래스 {

=> 부모클래스로부터 상속을 받겠다라는 것을 정의

 

2) 자식 클래스에 추가할 값을 필드부, 메소드부, 생성자부에 기재

 

3) information 메소드 작성 시 오버라이딩 과정 진행

public String information() {

    return super.information() + "출력을원하는문자" + 자식클래스필드명;

 

4) 기본 생성자 작성 후 모든 필드에 대해 매개변수 있는 생성자 만들 때

public 자식클래스명(①자료형 필드명) {

     super.(부모필드명1, 부모필드명2, ...);

     this.자식필드명 = 자식필드명;

 

*①: 자료형 필드명을 기재할 때는 부모 클래스, 자식 클래스 모두 다 적음!

 

만약에 각 자식 클래스에 information 메소드를 재정의하지 않았다면 (재정의 == 오버라이딩)
각각 부모 클래스인 Vehicle에 있는 information 메소드로 호출됐을 것!!
=> 재정의 하는 순간 자식 메소드로 우선권이 넘어가서 자식 클래스의 information 메소드가 호출됨

오버라이딩을 진행할 경우 @Override로 표시해 주는 것이 좋음!

여기서 @ <- 주석과 같은 역할을 함

*상속의 장점
- 보다 적은 양의 코드로 새로운 클래스들을 작성 가능함
- 중복된 코드를 공통적으로 관리하기 때문에 새로운 코드를 추가하거나 수정할 때 용이
- 프로그램의 생산성과 유지보수에 큰 기여
 
*상속의 특징
- 자식 클래스는 부모 클래스의 필드, 메소드를 모두 가져다 쓸 수 있지만
  부모 클래스는 자식 클래스의 코드를 가져다 쓸 수 없음
- 클래스 간의 상속은 다중 상속이 불가능함(단일 상속만 가능)
  만약 다중 상속 시에 서로 같은 필드명, 메소드명이 있을 것에 대비해 처음부터 막아 둠
- 명시되어 있지는 않지만 모든 클래스(자바에서 미리 만들어서 제공되는 클래스, 내가 만든 클래스)
  Object(자바에서 미리 만들어서 제공되는 클래스) 클래스의 후손임
  => Object 클래스에서 이미 만들어진 메소드를 가져다 쓸 수 있음
  => Object 클래스에서 이미 만들어진 메소드가 마음에 들지 않는다면
   오버라이딩을 통해 재정의 가능

 

다중 상속 불가능

Object는 모든 클래스의 조상

 

*setter, getter 메소드 한 큐에 만들기 (자동 완성)

 

*오버라이딩

모든 클래스는 Object 클래스의 후손임
즉, 최상위 클래스는 항상 Object
=> Object에 있는 메소드들은 다 가져다 쓸 수 있음
=> Object에 있는 메소드들을 내 입맛대로 오버라이딩 할 수 있음


 - 상속받고 있는 부모 클래스의 메소드를 자식 클래스에서 재정의(재작성) 하는 것
 - 부모가 제공하고 있는 메소드를 자식이 일부 고쳐서 사용하겠다라는 의미
 - 오버라이딩 시 해당 메소드를 호출하면 자식 메소드가 우선권을 가짐

package com.kh.chap03.override.run;

import com.kh.chap03.override.model.vo.Book;

public class OverrideRun {

	public static void main(String[] args) {
		
		// 모든 클래스는 Object 클래스의 후손임
		// 즉, 최상위 클래스는 항상 Object
		// => Object에 있는 메소드들은 다 가져다 쓸 수 있음
		// => Object에 있는 메소드들을 내 입맛대로 오버라이딩 할 수 있음
		
		Book bk = new Book("수학의정석", "나수학", 10000);
		
		System.out.println(bk /* .toString() */); // 주소값
		System.out.println(bk.hashCode()); // 주소값 십진수 형태
		// Object에서 제공하는 유용한 메소드를 상속받아서 사용 가능
		
		// 그중에서도 아주! 유용하게 쓸 수 있는 메소드
		// toString() 메소드
		System.out.println(bk.toString()); // 주소값 내용이 bk만 제시했을 때랑 동일하게 출력
		
	}

}

 

 * toString() 메소드
해당 참조 타입의 풀클래스명 + @ + 해당 객체의 주소값의 16진수의 형태로 돌려주는 메소드
알게 모르게 객체명만 제시했을 경우 내부적으로 toString() 메소드가 호출된 꼴 (JVM에 의해)
 
출력문 안에서 참조형 변수를 제시해서 해당 내용을 출력하고자 할 때
toString() 메소드가 내부적으로 알아서 호출된다는 점을 이용해서
toString() 메소드를 오버라이딩 해서 각 필드의 값을 한 개의 문자열로 리턴해 주게끔 재정의해서 씀!!
=> 기존에 information 메소드의 역할을 toString이 하게끔 오버라이딩 하겠음


*오버라이딩 성립 조건

- 부모 메소드명과 메소드명이 동일해야 함
- 매개변수의 자료형, 개수, 순서가 동일해야 함(단, 매개변수명과는 무관하나 헷갈리지 않게 맞춰 주는 게 좋긴 함!)
- 반환형 동일해야 함
- 부모 메소드의 접근 제한자보다 같거나 공유 범위가 더 커야 함
=> 규약의 개념이 들어가 있음(재정의 하려면 이 정도의 규칙은 지켜야 함)

 

 

*오버로딩

: 메소드명을 중복해서 정의할 수 있는 규칙 / 상속이랑 관련 없는 개념이므로 주의할 것! 

 

*오버로딩 성립 조건

1. 메소드명은 일치

2. 매개변수의 자료형, 순서, 개수가 달라야 함

3. 반환형, 매개변수명, 접근제한자는 영향을 주지 않음

 

	
	@Override // 어노테이션(생략 가능)
  	public String toString() {
		return "title: " + title + ", author: " + author + ", price: " + price;
	}
    
    // 기존 information 메소드의 역할을 toString 메소드가 대체하는 것임!

 * @Override 어노테이션
- 생략 가능(명시를 안 해도 부모 메소드와 형태가 같다면 오버라이딩이 잘된 것)
- 어노테이션을 붙이는 이유? (생략 가능하지만 붙이는 걸 권장)
  > 잘못 기술했을 경우 오류를 알려 주기 때문에 다시 검토할 수 있게 유도함
  > 혹시라도 부모 메소드가 후에 수정되었을 때 오류로 알려 주기 때문에 검토할 수 있게 유도함
  > 이 메소드가 오버라이딩 된 메소드라는 것을 알리기 위한 목적으로 사용 (주석의 역할)

 

오버라이딩 전후 차이

*클래스 구조
 public class 클래스명 {
  
 // 필드부
 
 // 생성자부: 기본 생성자, 모든필드에대한매개변수생성자
 
 // 메소드부: getter / setter, toString() 오버라이딩

}

 

*toString 자동 완성

필드부만 선택 후 Generate

 

저작자표시 (새창열림)
'📗 self-study/📗 KH정보교육원 당산지원' 카테고리의 다른 글
  • [Java] 09_다형성(추상 클래스와 인터페이스)
  • [Java] 09_다형성(Polymorphism)
  • [Java] 06_객체(생성자, 메소드, 오버로딩), 07_객체 배열(oneVsmany)
  • [Java] 06_객체(캡슐화, 클래스 실습, 필드, 접근 제한자)
천재강쥐
천재강쥐
  • 천재강쥐
    디버거도 버거다
    천재강쥐
  • 전체
    오늘
    어제
    • Category (467)
      • 진짜 너무 궁금한데 이걸 나만 몰라...? (0)
      • 💾 Portfolio (2)
      • 🐤 CodingTest (28)
        • Java (20)
        • ᕕ(ꐦ°᷄д°᷅)ᕗ❌ (5)
      • 🚀 from error to study (142)
        • AI (1)
        • Cloud (2)
        • DB (12)
        • Front-End (16)
        • Github (14)
        • Java (39)
        • Mac (7)
        • Normal (29)
        • Server (22)
      • 📘 certificate (44)
        • 📘 리눅스마스터1급 (1)
        • 📘⭕️ 정보처리기사 (40)
        • 📘⭕️ SQLD (3)
      • 📗 self-study (234)
        • 📗 inflearn (35)
        • 📗 생활코딩 (8)
        • 📗 KH정보교육원 당산지원 (190)
      • 🎨 Scoop the others (0)
        • 📖 Peeking into other people.. (0)
        • 🇫🇷 (0)
        • 📘⭕️ 한국사능력검정시험 심화 (11)
        • 오블완 (4)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.1
천재강쥐
[Java] 08_상속(Inheritance, 오버라이딩)
상단으로

티스토리툴바