자바(Java)의 기초 박살내기 - 상속(Inheritance)과 다형성(Polymorphism)


이번 시간에는 저번 시간에 했던 객체지향의 기본개념에 이어서 상속과 다형성에 대하여 공부하겠습니다.



 1. 상속 


- 상위 클래스의 모든 멤버를 하위 클래스가 물려 받는 것.

- 재사용성코드의 간결성 향상

- 자신이 만들어서 상속 시킬수도 있고 JDK가 지원하는 클래스로 부터 상속 받아 사용가능

- 최상위 클래스는 java.lang.Object

- 상속 키워드 : extends

- 상속의 종류 : 단일 상속(하나 클래스로 부터...), 다중 상속(2개 이상 클래스로 부터...)

- 상속의 용어

- 상속하는 클래스 : Base, Super, Parent Class

- 상속받는 클래스 : Derivation, Sub, Child Class

- 상속의 형식

[public/final/abstract] class 클래스이름 extends 상위클래스이름

{

멤버 변수;

멤버 메소드;

}

- private 멤버를 제외한 상위 클래스의 모든 멤버는 상속됩니다.

- 만약 동일한 이름의 변수가 상위 클래스와 하위 클래스에 존재한다면 상위 클래스의 변수는 가려진다. 

- static 변수도 상속 가능

- 하위 클래스에서 객체 생성시 메모리 할당


<예제 소스코드1 - Employee.class>

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
32
33
34
35
36
37
38
39
40
41
42
public class Employee 
{
    private String empNo;    // 사원번호
    private String name;    // 이름
    private String part;    // 부서
    
    // 매개변수가 없는 생성자
    public Employee()    {    }
    
    // 매개변수 3개를갖는 생성자
    public Employee(String empNo, String name, String part)
    {
        this.empNo = empNo;
        this.name = name;
        this.part = part;
    }
    
    // getter와 setter를 이용한 값을 정해주고 반환해주기
    public String getEmpNo() { return empNo; }
 
    public void setEmpNo(String empNo) { this.empNo = empNo; }
 
    public String getName() { return name; }
 
    public void setName(String name) { this.name = name; }
 
    public String getPart() { return part; }
 
    public void setPart(String part) { this.part = part; }
    
    // 멤버 필드의 결과값 문자열로 
    public String resultStr()
    {
        String result = "";
        
        result += "사번 : " + empNo + "\n";
        result += "이름 : " + name + "\n";
        result += "부서 : " + part + "\n";
        
        return result;
    }
}
cs


<예제 소스코드2 - Manager.class>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Manager extends Employee 
{
    private String position; // 직책
 
    // 매개변수 4개를 갖는 생성자
    public Manager(String empNo, String name, String part, String position) {
        setEmpNo(empNo);
        setName(name);
        setPart(part);
        this.position = position;
    }
 
    // 관리자에서 추가되는 정보를 결과 문자열로 결합
    public String addStr() {
        String result = "";
        result += "직책 : " + position + "\n";
        return result;
    }
}
cs


<예제 소스코드3 - Company.class>

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.io.BufferedReader;
import java.io.InputStreamReader;
 
public class Company 
{
    public static void main(String[] args)
    {
        String result = "";    // 결과 문자열
        Employee emp = null;// Employee 객체의 레퍼런스 변수
        Manager mng = null;    // Manger 객체의 레퍼런스 변수
        String empNo = null;// 사원 번호
        String  name = null;// 이름
        String part = null// 부서
        String  position = null// 직책
        
        // BufferedReader은 String 타입의 데이터 입력받을때 쓰임
        // Scanner은 여러 타입 입력 가능
        BufferedReader in =new BufferedReader(new InputStreamReader(System.in));
 
        try    // 예외처리를 위한 try ~ catch문 (나중이 자세히 배움)
        {
            // 정보 입력 단계
            System.out.print("사번 입력(예)A1010 : ");
            empNo = in.readLine();
            System.out.print("이름 입력(예)너구리 :");
            name = in.readLine();
            System.out.print("부서 입력(예)기획 :");
            part = in.readLine();
            System.out.print("직책 입력(예)사원-1, 대리-2, 과장-3 :");
            position = in.readLine();
        }catch(Exception e)    // 잘못입력 했을시...
        {
            System.out.println("입력 오류");
        }
        
        if (position.equals("1"))    // 직책이 사원 일경우는 사원 생략
        {
            emp = new Employee(empNo, name, part);   
            result += emp.resultStr();    // 결과값 
        }else    // 직책이 매니져급인 대리 과장일 경우
        {
            // 2일경우 대리 나머지일경우 과장
            position = (position.equals("2"))    ?    "대리" : "과장";    
            // 생성자
            mng = new Manager(empNo, name, part, position);
            // 결과값 넣어서 잇기
            result += mng.resultStr() + mng.addStr();
    
        }
        System.out.println(result);    // 결과 출력
    }
}
 

cs

//


<결과>


- super

- 앞에서는 super()에 대하여 배웠습니다. 하지만 여기서 super는 쫌 다릅니다.

- 하위 클래스에서 상위 클래스 객체를 가리키는 포인터

- 상위 클래스와 하위 클래스 모두 동일안 메소드 또는 변수가 있을때 상위 클래스 멤버 지지

- 생성자에서만 호출가능

- 사용방법

- 멤버 필드 접근 : super.멤버필드

- 멤버 메소드 접근 : super.멤버메소드(매개변수)

- 생성자 접근 : super(매개변수) - 생성자 메소드에서만 사용이 가능


<수정된 super 예제 소스코드1 - Employee.class>

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
32
33
34
35
36
37
38
39
40
41
42
43
public class Employee 
{
    private String empNo;    // 사원번호
    private String name;    // 이름
    private String part;    // 부서
    
    // 매개변수가 없는 생성자
    public Employee()    {    }
    
    // 매개변수 3개를갖는 생성자
    public Employee(String empNo, String name, String part)
    {
        this.empNo = empNo;
        this.name = name;
        this.part = part;
    }
    
    // getter와 setter를 이용한 값을 정해주고 반환해주기
    public String getEmpNo() { return empNo; }
 
    public void setEmpNo(String empNo) { this.empNo = empNo; }
 
    public String getName() { return name; }
 
    public void setName(String name) { this.name = name; }
 
    public String getPart() { return part; }
 
    public void setPart(String part) { this.part = part; }
    
    // 멤버 필드의 결과값 문자열로 
    public String resultStr()
    {
        String result = "";
        
        result += "사번 : " + empNo + "\n";
        result += "이름 : " + name + "\n";
        result += "부서 : " + part + "\n";
        
        return result;
    }
}
 
cs


<수정된 super 예제 소스코드2 - Manager.class>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Manager extends Employee 
{
    private String position; // 직책
 
    // 매개변수 4개를 갖는 생성자
    public Manager(String empNo, String name, String part, String position) 
    {
        // set대신 상위클래스 멤버 필드 가져오기
        super(empNo, name, part);
        this.position = position;
    }
 
    // 관리자에서 추가되는 정보를 결과 문자열로 결합
    public String addStr() {
        // super를 이용한 상위클래스 메소드 가져오기
        String result = super.resultStr();
        result += "직책 : " + position + "\n";
        return result;
    }
 
}
cs


<수정된 super 예제 소스코드3 - Company.class>

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import java.io.BufferedReader;
import java.io.InputStreamReader;
 
public class Company 
{
    public static void main(String[] args)
    {
        String result = "";    // 결과 문자열
        Employee emp = null;// Employee 객체의 레퍼런스 변수
        Manager mng = null;    // Manger 객체의 레퍼런스 변수
        String empNo = null;// 사원 번호
        String  name = null;// 이름
        String part = null// 부서
        String  position = null// 직책
        
        // BufferedReader은 String 타입의 데이터 입력받을때 쓰임
        // Scanner은 여러 타입 입력 가능
        BufferedReader in =new BufferedReader(new InputStreamReader(System.in));
 
        try    // 예외처리를 위한 try ~ catch문 (나중이 자세히 배움)
        {
            // 정보 입력 단계
            System.out.print("사번 입력(예)A1010 : ");
            empNo = in.readLine();
            System.out.print("이름 입력(예)너구리 :");
            name = in.readLine();
            System.out.print("부서 입력(예)기획 :");
            part = in.readLine();
            System.out.print("직책 입력(예)사원-1, 대리-2, 과장-3 :");
            position = in.readLine();
        }catch(Exception e)    // 잘못입력 했을시...
        {
            System.out.println("입력 오류");
        }
        
        if (position.equals("1"))    // 직책이 사원 일경우는 사원 생략
        {
            emp = new Employee(empNo, name, part);    // 생성자
            result += emp.resultStr();    // 결과값 
        }else    // 직책이 매니져급인 대리 과장일 경우
        {
            // 2일경우 대리 나머지일경우 과장
            position = (position.equals("2"))    ?    "대리" : "과장";    
            // 생성자
            mng = new Manager(empNo, name, part, position);
            // 결과값 넣어서 잇기
            result += mng.addStr();
    
        }
        System.out.println(result);    // 결과 출력
    }
}
cs


<결과>

- 결과는 마찬가지로 같은 결과가 나온다.



 2. 다형성 


- 다형성은 여러 가지 형태를 가질 수 있는 능력을 의미하며 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록하고 상속관계에서 일어난다.

- 위 예제 소스코드중 Company.class에서 38라인과 45라인이 다형성에 예라고 할 수 있다.



 3. 추상 클래스 


- 클래스 이름 앞에 abstract라는 예약어가 사용된 클래스

- 하위 클래스에서 구현될 기능을 추상 메소드로 선언한 클래스

- 추상 메소드는 선언만 되어 있고 구현 부분이 없는 메소드로 메서드의 결과형 앞에 abstract를 기재해서 생성

- 추상 메소드는 반드시 하위 클래스에서 오버라이딩 되어서 구현되어야 한다.

- 추상 메소드는 일반적인 멤버 변수와 메소드를 가질 수 있습니다.

- 하지만 객체를 생성하지 못하여 상속을 통해서만 사용되어 집니다.


<추상 클래스 예제 소스코드1 - Starcraft.class>

1
2
3
4
5
// 추상 클래스
abstract class Starcraft 
{
    abstract void attack();
}
cs

<추상 클래스 예제 소스코드2 - Protoss.class>
1
2
3
4
5
6
7
8
9
10
public class Protoss extends Starcraft 
{
    // 추상 클래스는 오버라이딩 해서 사용 
    @Override
    public void attack() 
    {
        System.out.println("프로토스의 공격");
    }
 
}
cs


<추상 클래스 예제 소스코드3 - Terran.class>

1
2
3
4
5
6
7
8
9
public class Terran extends Starcraft 
{
    // 추상 클래스는 오버라이딩 해서 사용
    @Override
    public void attack() 
    {
        System.out.println("테란의 공격");
    }
}
cs


<추상 클래스 예제 소스코드4 - Zerg.class>

1
2
3
4
5
6
7
8
9
public class Zerg extends Starcraft 
{
    // 추상 클래스는 오버라이딩 해서 사용
    @Override
    public void attack() 
    {
        System.out.println("저그의 공격");
    }
}
cs


<추상 클래스 예제 소스코드5 - Main.class>

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
public class Main 
{
    public static void main(String[] args) 
    {
        Terran marine = new Terran();
        marine.attack();
        Protoss dragoon = new Protoss();
        dragoon.attack();
        Zerg hydralisk = new Zerg();
        hydralisk.attack();
        
        System.out.println("====객체 형변환과 오버라이딩을 이용====");
        Starcraft obj = new Terran();    
        // 상위 클래스의 참조형 변수에 하위 클래스의 객체를 대입
        obj.attack();                  // shot() 메소드 호출
        obj = new Protoss();
        obj.attack();                  // shot() 메소드 호출 
        obj = new Zerg();
        obj.attack();                  // shot() 메소드 호출
 
        /* error
        추상 클래스는 자신의 생성자를 이용해서 객체를 생성할 수 없음
        obj = new Starcraft();
        obj.shot();
        */
    }
 
}
cs


<결과>



 4. final 관련 키워드 정리 


- final 클래스 : 상속할수 없는 클래스

- final 메소드 : 재정의 할 수 없는 메소드

- final 필드 : 값을 변경할 수 없는 필드



 5. 인터페이스 


- 다중 상속을 위해서 나온 개념

- static final 변수와 추상 메소드 만을 소유

- 인터페이스에 정의된 모든 메소드는 상속받는 클래스에서 전부 오버라이딩해야 한다.

- 인터페이스로부터 상속 받을 때 implements키워드 사용


<Interface 예제 소스코드1 - Inter.class>

1
2
3
4
5
6
7
8
9
10
public interface Inter 
{
    // 인터페이스에서는 final을 사용하지 않아도 변수는 final
    public int a=100
    public final int b = 200;
    public abstract void method1();
    // 인터페이스에서는 abstract을 사용하지 않아도 메소드는 abstract
    public void method2();         
}
 
cs


<Interface 예제 소스코드2 - InterTest.class>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class InterTest implements Inter
{
    @Override
    public void method1()
    {
        System.out.println("추상메소드");
    }
    
    @Override
    public void method2()
    {
        System.out.println("추상메소드");
    }
 
    public static void main(String args[])
    {
        InterTest obj = new InterTest();
        //obj.a = 200;    // final 이므로 변경할 수 없다.
        obj.method1();
        System.out.println("Inter의 a : " + obj.a);
        System.out.println("Inter의 b : " + obj.b);
    }
}
cs


<결과>



여기까지 객체지향 클래스의 대하여 알아보았습니다. 다음 시간에는 참조형 자료형인 배열에 대해서 공부하겠습니다. 


  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유