본문 바로가기

Study/Java

객체지향 프로그래밍 7장(20강 ~ 24강)

728x90

상속(Inheritance)

 - 기존의 클래스로 새로운 클래스를 작성하는 것.(코드의 재사용)

class 자식클래스 extends 부모클래스{
	// ...
}

 - 두 클래스를 부모와 자식으로 관계를 맺어주는 것.

class Parent { } //부모클래스
class Child extends Parent{
	// Child 클래스에 Parent 클래스를 상속받는다.
    // ...
}

- Child 클래스와 Parent 클래스는 상속관계에 있다고 이야기한다.

상속관계

- 자손은 조상(부모의부모)의 모든 멤버를 상속받는다.(생성자, 초기화블럭 제외)

- 자손의 멤버 개수는 조상보다 적을 수 없다.(같거나 많다.)

class Parent{
       int age;
}

class Child extends Parent{ 
      // 자신의 멤버 0개
      // 상속받은 멤버 1개
}

- 자손의 변경은 조상에 영향을 미치지 않는다.

- 반대로 조상의 변경은 자손에게 영향을 준다.

왜? 상속 받고 있으니깐 ~

class Parent {
      int age;
}
class Child extends Parent{
      void play(){
            syso("놀자~");
      }
}

참고.

변수와 메서드의 모음을 멤버라고 한다.

확장 -> extend

class Point {
     int x;
     int y;
}
class Point3D extends Point {
     int z;
}
Point3D p = new Point3D();

상속

객체 생성

- 두 코드의 결과는 같다.

 

실습 예제.

package com.seulgae.ch07;
class Tv {
	boolean power; 	// 전원상태(on/off)
	int channel;	// 채널

	void power()        {   power = !power; }
	void channelUp()    { 	 ++channel;     }
	void channelDown()  {	 --channel;	    }
}

class CaptionTv extends Tv { // SmartTv는 Tv에 캡션(자막)을 보여주는 기능을 한다.
	boolean caption;		// 캡션상태(on/off)
	void displayCaption(String text) {
		if (caption) {	// 캡션 상태가 on(true)일 때만 text를 보여 준다.
			System.out.println(text);
		}
	}
}

class CaptionTvTest {
	public static void main(String args[]) {
		CaptionTv ctv = new CaptionTv();
		// channel cannot be resolved or is not a field, 채널이라는걸 해석 못하겠음 !
		ctv.channel = 10;				// 조상 클래스로부터 상속받은 멤버
		ctv.channelUp();				//  조상클래스로부터 상속받은 멤버
		System.out.println(ctv.channel);
		ctv.displayCaption("Hello, World");	
		ctv.caption = true;				    //캡션(자막)기능을 켠다.
		ctv.displayCaption("Hello, World");
	}
}

출력 결과

포함 관계

▶ 포함(composite) 이란?

 - 클래스의 멤버 변수로 참조변수를 선언하는 것.

class Circle{
    int x; // 원점의 x좌표
    int y; // 원점의 y좌표
    int r; // 반지름(radius)
}

1번 코드

- 작은 단위의 클래스를 만들고, 이 들을 조합해서 클래스를 만든다.

class Circle{
	Point c = new Point(); // 원점
	int r; // 반지름(radius)
}

2번 코드

class Car {
    Engine e = new Engine(); // 엔진
    Door[] d = new Door[4];  // 문, 문의 개수를 넷으로 가정하고 배열로 처리했다.
}

 

클래스 간의 관계 결정하기

 

상속관계(10%) '~은 ~이다.(is-a)'
포함관계(90%) '~은 ~을 가지고 있다.(has-a)'

- 상속, 포함 관계를 결정할 때 문장으로 만들어보고 뭐가 더 자연스러운지 판단하면 된다.

- 근데 대부분 포함관계를 사용한다.

클래스 간의 관계 결정하기

실습 예제.

package com.seulgae.ch07;

class MyPoint{
	int x;
	int y;
}

//class Circle2 extends MyPoint { // 상속
//	int r;
//}

class Circle2 { // 포함
	MyPoint p = new MyPoint(); // 참조변수의 초기화
	int r;
}

public class InheritanceTest {
	public static void main(String[] args) {
		Circle2 c = new Circle2();
		c.p.x = 1;
		c.p.y = 2;
		c.r = 3;
		System.out.println("c.p.x= " + c.p.x);
		System.out.println("c.p.y= " + c.p.y);
		System.out.println("c.r= " + c.r);
	}
}

출력 결과

 

단일 상속(Single Inheritance)

 - Java는 단일상속만을 허용한다.(C++은 다중상속 허용)

 - 다중 상속은 충돌 위험이 많아 자바는 다중 상속 대신 인터페이스를 사용하여 다중 상속 문제를 해결한다.

 

단일상속이란?

class TvDVD extends Tv, DVD{ // 에러. 조상은 하나만 허용된다.
                   //다중 상속 안됨!
}

 

- 비중이 높은 클래스 하나만 상속관계로, 나머지는 포함관계로 한다.

다중 상속 처럼 구현하는법

 

Object클래스  - 모든 클래스의 조상

- 부모가 없는 클래스는 자동적으로 Object 클래스를 상속받게 된다.

- 모든 클래스는 Object 클래스에 정의된 11개의 메서드를 상속받는다.

- toString(), equals(Object obj), hashCode(), ... (9장에서 배울꺼임)

상속 계층도

 

실습 예제.

- 참조변수가 들어오면 toString()을 호출함.

package com.seulgae.ch07;

class MyPoint{
	int x;
	int y;
}

class Circle2 extends Object{ // 포함
	MyPoint p = new MyPoint(); // 참조변수의 초기화
	int r;
	
//	Circle2(){ // 참조변수의 초기화
//		c = new MyPoint();
//	}
}

public class InheritanceTest {
	public static void main(String[] args) {

		Circle2 p = new Circle2();
		System.out.println(p.toString()); //Circle2@4926097b 문자열 반환
		Circle2 c2 = new Circle2();
		System.out.println(c2); //Circle2@39ed3c8d 문자열 반환
	}
}

출력 결과

 

오버라이딩(overriding) - 덮어쓰다.

- 상속받은 조상의 메서드를 자신에 맞게 변경하는 것

 

실습 예제.

package com.seulgae.ch07;

class MyPoint3 extends Object{
	int x;
	int y;
	
	//생성자 : 인스턴스 초기화 메서드
	MyPoint3(int x, int y){
		this.x = x;
		// this가 붙으면 매개변수에 x가아닌 바로 위 인스턴스 메서드를 가르킨다.
		// 변수이름이 같아서 혼동하지 말자.
		this.y = y;
	}
	
	// Object 클래스의 toString()을 오버라이딩
	public String toString() {
		return "x:"+x+", y:" +y;
	}
}

public class OverrideTest {
	public static void main(String[] args) {
		MyPoint3 p = new MyPoint3(3, 5);
		System.out.println(p);
	}
}

출력 결과

오버라이딩(overriding) 조건 3가지

1. 선언부가 조상 클래스의 메서드와 일치해야 한다.

선언부 일치

+ 선언부(반환타입, 메서드이름, 매개변수 목록)

 

2. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경 할 수 없다.

 - public, protected, (default), provate

 

3. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.

예외가 더 많으면 안된다.

 

오버로딩과 오버라이딩 차이점.

오버로딩(overloading) 기존에 없는 이름이 같은 새로운 메서드를 정의하는 것(new)
상속하고 관계x
오버라이딩(overriding) 상속받은 메서드의 내용을 변경하는 것(change, modify)
상속하고 관계o

오버로딩과 오버라이딩 구분

 

참조변수 super = this(lv와 iv 구별하는데 사용했었음.)

- 객체 자신을 가리키는 참조변수. 인스턴스 메서드(생성자)내에만 존재(static 메서드 내에서 사용불가)

- 조상의 멤버를 자신의 멤버와 구별할 때 사용

 

실습 예제.

package com.seulgae.ch07;
class SuperTest {
	public static void main(String args[]) {
		Child2 c = new Child2();
		c.method();
	}
}

class Parent2 {
	int x=10; /* super.x */
}

class Child2 extends Parent2 {
	int x = 20; //this.x
	
	void method() {
		System.out.println("x=" + x);
		System.out.println("this.x=" + this.x);
		System.out.println("super.x="+ super.x);
	}
}

출력 결과

 

package com.seulgae.ch07;
class SuperTest2 {
	public static void main(String args[]) {
		Child2 c = new Child2();
		c.method();
	}
}

class Parent2 { /* super.x와 this.x 둘 다 가능 */
	int x=10;
}

class Child2 extends Parent2 {
	int x=20;

	void method() {
		System.out.println("x=" + x);
		System.out.println("this.x=" + this.x);
		System.out.println("super.x="+ super.x);
	}
}

출력 결과

 

super() - 조상의 생성자

- 조상의 생성자 호출할 때 사용

- 조상의 멤버는 조상의 생성자를 호출해서 초기화

 class Point {
 	int x, y;
    
    Point(int x, int y){
    	this.x = x; // iv 초기화
        this.y = y;
 	}
 }
 
 class Point3D extends Point{
 	int z;
    
    Point3D(int x, int y, int z) {
    	this.x = x; //조상의 멤버를 초기화
        this.y = y; // 조상의 멤버를 초기화
        this.z = z;
    }
 }
 
 Point3D(int x, int y, int z) {
 	super(x, y); // 조상클래스의 생성자Point(int x, int y)를 호출
   	this.z = z;  // 자신의 멤버를 초기화
 }

- 조상의 생성자를 호출해서 조상의 생성자가 조상의 멤버를 초기화 한다.

 

(추가조건) 생성자의 첫 줄에 반드시 생성자를 호출해야 한다.

그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();를 삽입

꼭 기억하자.

 

 

반응형