티스토리 뷰

day12 190306


드디어 객체지향의 정말 중요한 부분인, 상속을 배웠습니다.

상속의 특징으로 파생되는 메소드 재정의(Override), 다형성 등을 같이 배웠습니다.


--클래스의 관계 2가지


-상속 관계 (is a관계)

ex) iphone is a phone, android is a phone


-포함 관계 (has a관계)

ex) car has a engine



<상속> : 객체 지향의 중요한 특징, extends키워드 사용


*자바는 단일 상속만 지원


*자식클래스는 부모클래스의 생성자와 private으로 선언된 것은 사용할 수 없다. (상속되지 않음)


상속의 목적 : 부모의 기능을 구현없이 사용하려고.

 부모와 같은 종류가 되려고


1
2
3
4
5
6
7
8
9
10
public class Phone {
    String tel;
 
    public void connect() {
        System.out.println(tel + "에서 전화를 겁니다.");
    }
    public void disconnect() {
        System.out.println(tel + "에서 전화를 끊습니다.");
    }
}
cs

>> tel이라는 문자열 변수와, 전화를 걸고 끊는 connect, disconnect메소드를 가진 Phone클래스파일입니다.


1
2
3
4
5
6
7
8
9
10
public class SmartPhone extends Phone {
    String ipAddress;
 
    public void facetime() {
        System.out.println(tel + "화상통화를 시작합니다.");
    }
    public void internet() {
        System.out.println(ipAddress + "로 인터넷에 접속합니다.");
    }
}
cs

>> ipAddress문자열 변수, 화상통화, 인터넷접속 메소드를 가진 SmartPhone클래스파일입니다.

여기서 1행을 보면, extends Phone이라는 부분이 바로 상속입니다. Phone클래스파일을 SmartPhone이 상속받는 것이죠.

(부모클래스 : Phone / 자식클래스 : SmartPhone)

어떤 결과를 가져오게 되는지 확인해보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PhoneApp {
    public static void main(String[] args) {
        Phone p1 = new Phone();
        p1.tel = "010-2345-5678";
        p1.connect();
        p1.disconnect();
 
        SmartPhone p2 = new SmartPhone();
        p2.tel = "010-1111-2222";
        p2.connect();
        p2.disconnect();
        p2.ipAddress = "192.168.10.254";
        p2.internet();
    }
}
cs

>> 위 두 클래스파일을 사용해봤습니다. 실행결과를 먼저 보면,


---------- 실행 ----------

010-2345-5678에서 전화를 겁니다.

010-2345-5678에서 전화를 끊습니다.


010-1111-2222에서 전화를 겁니다.

010-1111-2222에서 전화를 끊습니다.

192.168.10.254로 인터넷에 접속합니다.



위와 같이 출력됩니다. 3~6행은 앞서 다뤘던 메소드부분에서 봐오던 형식입니다.

8~13행을 보시면, SmartPhone에 따로 구현하지 않았던 tel변수, connect메소드, disconnect메소드를 사용하고 있습니다.

이 부분이 바로 상속의 효과입니다. 자식클래스는 부모클래스의 변수나 메소드등을 따로 구현하지않아도 가져와서 사용할 수 있습니다.


--메소드 재정의 (@Override) / 매우 많이 사용됨.

: 부모클래스에 있는 메소드를 자식클래스에서 다르게 사용하려 할 때 자식클래스 안에서 다시 정의하는 것

*반환타입, 매개변수 등의 구조는 무조건 같아야한다. ( 수행문을 달리함)

*재정의된 메소드는 실행에서 최우선순위를 갖는다. ( 재정의의 재정의시 가장 최근에 재정의 된 메소드가 최우선)

1
2
3
4
5
6
7
8
9
10
11
public class Camera {
    public void picture() {
        System.out.println("사진을 찍었습니다.");
    }
    public void save() {
        System.out.println("사진을 저장합니다.");
    }
    public void delete() {
        System.out.println("사진을 삭제합니다.");
    }
}
cs
1
2
3
4
5
6
7
8
9
public class WebCamera extends Camera {
    // 메소드 재정의
    public void save() {
        System.out.println("클라우드에 사진을 저장한다.");
    }
    public void delete() {
        System.out.println("클라우드에 사진을 삭제합니다.");
    }
}
cs

>> Camera클래스파일과, 그 클래스파일을 상속받은 WebCamera파일입니다.

두 클래스의 메소드타입과 이름을 보면 일치하고, 안의 수행문은 다릅니다.

(이때, 재정의된 메소드를 사용하면, WebCamera의 재정의된 메소드의 수행문이 우선적으로 실행되게 됩니다.)

1
2
3
4
5
6
7
8
9
public class CameraApp {
    public static void main(String[] args) {
        WebCamera c = new WebCamera();
 
        c.picture();        // 부모로부터 상속받은 메소드 사용
        c.save();            // WebCamera에 재정의된 기능 사용
        c.delete();            // WebCamera에 재정의된 기능 사용
    }
}
cs

---------- 실행 ----------

사진을 찍었습니다.

클라우드에 사진을 저장한다.

클라우드에 사진을 삭제합니다.


--다형성 : 같은 타입에서 실행 결과가 다양한 객체를 쓸 수 있게 하는 것.

( 메소드 재정의와 타입 형 변환을 통해서 이뤄짐. )


--타입 형 변환 : 객체를 생성해서 참조변수에 대입할 때, 생성한 객체와 참조변수의 타입이 다른 경우 생성된 객체의 안쪽 방향으로 객체를 

    탐색해서 참조변수와 동일한 타입의 객체를 찾아서 그 객체의 주소값을 참조변수에 담는 것

(부모클래스는 자식클래스의 객체를 담는 것이 가능하다.)

ex) 부모클래스 : Tire        자식클래스 : NormalTire, SnowTire

Tire t1 = new NormalTire();

(자식클래스는 부모클래스의 객체를 담을 수 없다.)

NormalTire t2 = new Tire();        << 불가능

1
2
3
4
5
public class Tire {
    public void go() {
        System.out.println("바퀴가 굴러갑니다.");
    }
}
cs
1
2
3
4
5
6
7
8
9
public class SnowTire extends Tire {
    // 메소드 재정의
    public void go() {
        System.out.println("눈에서 안전하게 바퀴가 굴러갑니다.");
    }
    public void chain() {
        System.out.println("타이어에 체인을 추가로 장착할 수 있습니다.");
    }
}
cs
1
2
3
4
5
public class KumhoSnowTire extends SnowTire {
    public void go() {
        System.out.println("금호의 신 기술이 적용된 바퀴가 눈을 밀어내며 굴러갑니다.");
    }
}
cs
1
2
3
4
5
public class HankookSnowTire extends SnowTire {
    public void go() {
        System.out.println("한국의 신기술이 적용된 타이어가 눈을 녹이면서 갑니다.");
    }
}
cs

>> Tire에서 SnowTire, SnowTire에서 KumhoSnowTire와 HankookSnowTire로 상속된 네 가지 클래스입니다.




1
2
3
4
5
6
7
8
9
10
11
public class TireApp {
    public static void main(String[] args) {
        KumhoSnowTire t1 = new KumhoSnowTire();
        SnowTire t2 = new KumhoSnowTire();
        Tire t3 = new KumhoSnowTire();
 
        t1.go();
        t2.go();
        t3.go();
    }
}
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
public class TireApp2 {
    public static void main(String[] args) {
        Tire t1 = new KumhoSnowTire();
        Tire t2 = new HankookSnowTire();
        Tire t3 = new SnowTire();
        Tire t4 = new Tire();
 
        t1.go();
        t2.go();
        t3.go();
        t4.go();
    }
}
cs




우측 그림들의구조의 원리로 부모클래스타입에서 자식클래스를 참조하여 

만들어도 메소드를 실행하면 제일 최근에 재정의된 자식메소드의 
메소드가 실행되게 됩니다. (위 TireApp파일들을 실행해보시길 바랍니다.)
---------- 실행 ----------
금호의 신 기술이 적용된 바퀴가 눈을 밀어내며 굴러갑니다.
한국의 신기술이 적용된 타이어가 눈을 녹이면서 갑니다.
눈에서 안전하게 바퀴가 굴러갑니다.
바퀴가 굴러갑니다.

^TireApp2의 실행결과



1
2
3
4
5
6
7
8
9
10
public class TireApp3 {
    public static void main(String[] args) {
        // KumhoSnowTire객체를 HankookSnowTire타입으로 형변환할 수 없다.
        HankookSnowTire t1 = new KumhoSnowTire(); //형변환 오류로인한 컴파일 오류
        
        // Tire객체를 SnowTire타입으로 형변환할 수 없다.
        // 부모타입객체를 자식타입의 참조변수에 담을 수 없다.
        SnowTire t1 = new Tire();
    }
}
cs

컴파일을 하면 4,8행은 오류가 나게 됩니다. 4행은 서로 전혀 다른 두 클래스파일이므로 형변환이 불가능하고,

8행은 자식클래스가 부모클래스를 참조할 수 없으므로 불가능하다. ( 위에서 말했듯, 부모클래스는 자식클래스 참조, 형변환 가능!)


코딩Tip!

*개방폐쇄원칙

( 확장에는 열려있고, 변화에는 닫혀있다.)

= 버전변경시 기존코드를 건드리지않고, 새로 덧붙여서 확장을 하는 것을 의미.)



상속, 상속에서 비롯된 다형성, 메소드재정의(오버라이드), 다형성을 배워봤습니다.

여러 파일들을 사용하게 되서 헷갈리실 수 있으니, 그림을 참조하셔서 이해하시는게 도움이 될 것 같습니다.

day12.zip



댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함