본문 바로가기

코딩공부일지/수업 review

자바 - 상속 & 오버라이딩

Part1 상속

1. 상속이란

 매 클래스마다 중복된 필드, 메소드를 하나의 클래스(부모클래스) 로 정의해두고
 해당 클래스를 상속받는 자손클래스를 통해 
 코드의 중복 없이 부모-> 자손 관계의 클래스를 구현하는 것 

*상속이 없다면:
매 클래스마다 중복된 코드를 하나하나 기술하여 수정, 유지보수때마다 모든 중복코드를 수정해야함

 

Class Parent { // 부모클래스 

int x;

}

Class Child extends Parent {  // Child는 자손클래스, Parent는 부모클래스

int y;

}
< 상속 클래스간의 관계 표현법>
부모 - 자식클래스,
조상 - 후손클래스,
상위 - 하위클래스,
슈퍼클래스 - 서브클래스 ,
확장클래스-파생클래스  등....

**  자식클래스는 부모로부터 상속받은 부분(필드, 메서드)은 중복 기술하지 않는다
   --> 단, 자식클래스의 메소드는 재정의 가능  (오버라이딩)

 

자손클래스에서 내가 호출하고자 하는 메서드가 존재하지 않는다면
==> 컴파일러는 자동으로 해당 클래스의 부모클래스에 있는 메소드를 호출

2. 상속의 장점

   중복된 코드를 공통으로 관리하여 새로운 코드 작성, 수정에 용이 , 적은 코드로 새로운 클래스를 만들 수 있음

   ==> 프로그램 생산성, 가독성, 유지보수에 크게 기여 가능 

3. 상속의 특징
   1) 클래스간의 다중상속이 불가능함  (단일상속만 가능)
   2) 모든 클래스는 object class의 후손임 ===>object클래스 메서드 호출가능
      => object클래스의 메서드 오버라이딩을 통해 재정의가능 

   3) 자식클래스는 부모클래스의 필드, 메서드, 그리고 클래스타입을 상속받음 (생성자 상속불가)

 

 

 

public class Product { // 부모클래스 

	// 필드부
	private String brand;
	private String pCode;
	private String pName;
	private int price;
	
    // 생성자부
	public Product() {
		super();
	}
	public Product(String brand, String pCode, String pName, int price) {
		super();
		this.brand = brand;
		this.pCode = pCode;
		this.pName = pName;
		this.price = price;
	}

// getter- setter메서드 (생략)
// information 메서드	
	public String information() {
		return "brand: "+getBrand()+ "pCode : "+getpCode() +"pName : "+getpName()+"price: "+getPrice();
		
	}

}

<상속시 생성자는 상속받지 못함: 부모의 생성자 super>

public class SmartPhone extends Product {	
	
     필드부 (상속부분 생략 + 자기자신)   
	private String mobileAgency;
	
     ** 생성자부 (상속불가)
    
    1.기본생성자 
	public SmartPhone() {}
  
    2. 매개변수가 있는 생성자	
        
	public SmartPhone(String brand, String pCode, String pName, int price, String mobileAgency) {
	
      1) 문제: 상속x클래스처럼 매개변수 생성자를 만들면..
           this.brand ==> this ==> 객체의 주솟값을 담고있음	
           super.brand ==> 해당 부모의 주소를 가지고 있음. 부모에 접근 가능 
		   super.brand = brand; 
        --> 부모필드의 접근제한자가 private이므로 보이지 않는다 (not visible)******
	     
       2) 해결방법 ==>3가지
	      [1] 부모클래스의 필드에 자손이 접근 가능하도록 접근제한자를 바꾼다( private => protected) ==> 캡슐화 원칙에 위배, 적합한 방법은 아님
		    --> 캡슐화 원칙에 위배
        
          [2] 부모클래스에 있는 public 접근제한자 setter메소드 호출
			super.setBrand(brand);
			super.setpCode(pCode);
			super.setpName(pName);
			super.setPrice(getPrice());
         
    ****  [3]부모생성자를 호출
		     자손클래스 생성시 해당 객체의 부모클래스가 먼저 생성됨
		     부모객체가 heap에 먼저 할당됨 ---> 상속이 일어나면 부모객체 (부모공간만큼 공간을 만든 후) 그 공간에 포함되지 않는 자손객체의 공간이 추가됨. 
		     부모객체 없이는 자식객체가 생성될 수 없음. 
		     따라서 기본생성자 호출시 해당 객체의 부모생성자가 자동적으로 컴파일됨(super(); )
             모든 생성자 앞에는 부모의 생성자가 생략되어 있음
             ===>	super(); // 항상 제일 윗 줄에 컴파일됨
       	    super (brand, pCode, pName, price) ;  ===> 부모필드:부모의 생성자를 호출하여 초기화 
	    	+ this.mobileAgency = mobileAgency;   ===> 자손필드: 대입
	}
	

      getter setter 생략 
      information
	public String information () {
		super.information() + "inch : "+inch ;   조상의 information을 호출한 후 자손 추가내용 추가
                   String 형  +   String형 
	}
}

Part2 오버라이딩

 

1. 오버라이딩이란?

  1) 상속 관계에 있는 부모 클래스에서 이미 정의된 메소드를 자식 클래스에서 같은 메소드명과, 매개변수를 갖는 메소드로 다시 정의하는 것 (접근제한자, 메서드명, 선언부 동일/ 구현부 상이)

  2) 상속받은 부모클래스의 메서드를 자식클래스에서 재정의(재작성)하는것 
  3) 부모클래스가 제공하는 메서드를 자식클래스가 일부 수정하여 사용

 자식객체에서  메서드 호출시 자식클래스의 오버라이딩된 메서드가 우선권을 가져 호출됨 

2. 오버라이딩 성립조건

  1) 부모메서드와 메서드명이 동일
  2) 매개변수의 자료형, 개수, 순서가 동일 
  3) 반환형이 동일 
     ==> 규약의 개념
  4) 부모메서드의 접근제한자와 같거나 공유`범위가 넓어야함

 

부모클래스
public class Vehicle {
	1.필드부
    private String name;
	private double mileage;
	private String kind;
	
    2.생성자부
	public Vehicle() {
		super();
	}
	public Vehicle(String name, double mileage, String kind) {
		super();
		this.name = name;
		this.mileage = mileage;
		this.kind = kind;
	}
	
    getter-setter 생략
	public void howToMove() {
	    System.out.println("움직인다");
	}
    
    3. toString오버라이딩을 통한 information메서드
	  - object클래스의 기존 메소드를 오버라이딩하여 쓸 것
      - information대신 toString을 오버라이딩하여 쓸 것
      
		public String toString () {
		   return "name : " + name + "mileage : "+mileage + "kind : "+kind ;
        }

    4.기타 메서드
		public void howToMove() {
	   		 System.out.println("움직인다");
		}
}

 

 

자식클래스
public class Ship extends Vehicle {
	1. 필드부
    private int propeller;
    
    2. 생성자부
	public Ship () {}
	public Ship(String name, double mileage, String kind, int propeller) {
		super(name, mileage, kind);  ==> 부모의 생성자 호출하여 대입
		this.propeller = propeller;  --> 필드부 대입
	}
	
    
    3. getter-setter
	public int getPropeller() {
		return propeller;
	}
	public void setPropeller(int propeller) {
		this.propeller = propeller;
	}
	
    *** 4. 메소드부 ====> 부모의 메서드를 오버라이딩 하여 사용한다!
	public void howToMove () {               :메소드 이름이 부모와 일치, 구현부 수정
		System.out.println("부우우우웅");
	}
	
	public String toString() {                :메소드 이름이 부모와 일치, 구현부 수정
		return super.toString() + "propeller: "+propeller;
                                              : 부모메서드 호출(String반환) + 추가
	}
}

 

 

 

<기타 배운점> 

 toString 메서드
toString() : 해당 객체의 풀클래스명 + @+해당객체의 주소값 형태로 반환 : 문자열형
==> 출력문 내에서 toString을 생략해도 같은 값이 나옴 
 앞으로 Object 클래스의 toString이라는 메소드를 오버라이딩하여 사용할것
단축키

* 생성자
Alt + Shift + s -> o
* getter - setter 
Alt + Shift + s -> r
* toString
Alt + Shift + s -> s  -> Alt + g


 

 

 

<오늘의 의문점>

왜 다른 메서드가 아닌 toString을 오버라이딩하여 사용할까..?