▶ JAVA/개념정리

[Java] 13. 객체지향언어(4)_상속

휴학생감자 2022. 3. 11. 00:37

1. 상속

기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것

 

구현 방법 : 'extends' 이용   

 

Ex) class Student extends School

여기서 Student와 School 클래스는 서로 상속 관계에 있으며,

상속을 받는 Student 클래스는 자손(자식) 클래스,

상속해주는 School 클래스는 조상(부모) 클래스라고 한다.

 

위의 예시에서 Student 클래스는 이미 상속을 한 번 받았는데, 만약 이 Student클래스를 상속받아

A라는 클래스가 생성된다면, A와 School은 간접적인 상속관계라고 할 수 있다.

 

부모 클래스를 상속받아 만든 자손 클래스는 변경사항이 생겨도 부모 클래스에 영향을 주지 않지만,

부모 클래스에서 변경이 생기면 자손 클래스는 영향을 받는다.

 

상속 시 멤버만 상속되며, 생성자와 초기화 블럭은 상속되지 않는다.

 자식 클래스의 멤버 개수는 조상 클래스보다 항상 같거나 많다.

 클래스 간의 관계에서 부모/자식 관계(상속관계)는 있지만, 형제 관계는 없다.

자바에서의 상속은 단일 상속만 가능하다.

 

즉, 자손 클래스의 인스턴스를 생성한다면 조상 클래스의 멤버와 자손 클래스의 멤버가 합쳐진 하나의 인스턴스로 생성된다. 

 

※ 포함관계

상속 이외에 클래스를 재사용하는 방법으로 클래스간에 포함관계를 만드는 것이다.

한 클래스의 멤버변수로 다른 클래스 다입의 참조변수를 선언함으로써 포함관계를 맺어줄 수 있다.

 

Ex) Circle와 Point라는 클래스가 있다고 하면

     class Circle {

         Point p = new Point( );     //포함 관계

         int r;

      }

 

 

# 예제1

class Shape{
    String color = "black";
    
    void draw(){
        System.out.printf("[color=%s]%n", color);
    }
}

class Point{
    int x;
    int y;

    Point(int x, int y){
        this.x = x;
        this.y = y;
    }

    Point(){
        this(0, 0);
    }

    String getXY(){
        return "(" + x + "," + y + ")";
    }
}

class Circle extends Shape{
    Point center;
    int r;

    Circle(){
        this(new Point(0, 0), 100);
    }

    Circle(Point center, int r){
        this.center = center;
        this.r = r;
    }

    void draw() {
        System.out.printf("[center=(%d, %d), r=%d, color=%s]%n", 
        center.x, center.y, r, color);
    }
}

class Triangle extends Shape{
    Point[] p = new Point[3];

    Triangle(Point[] p){
        this.p = p;
    }

    void draw(){
        System.out.printf("[p1=%s, p2=%s, p3=%s, color=%s]%n", 
        p[0].getXY(), p[1].getXY(), p[2].getXY(), color);
    }

}

public class exCode {
    public static void main(String[] args) {
        Point[] p = {new Point(100, 100),
                    new Point(140, 50),
                    new Point(200, 100)
        };

        Triangle t = new Triangle(p);
        Circle c = new Circle(new Point(150, 150), 150);

        t.draw();
        c.draw();
    }
}

[실행 결과]

▶ Circle, Triangle 클래스는 Shape를 상속받는 관계이며, Point와는 포함관계를 맺고있다.

▶ main에서 point 인스턴스를 생성하면서 color를 지정하지 않았으나, 출력결과에는 black으로 나타난다. 이는 Shape 클래스에서 멤버변수로 정의해놓은 것을 상속받아 사용했기 때문이다.

 

 

# 예제2

class Deck{
    final int CARD_NUM = 52;
    Card cardArr[] = new Card[CARD_NUM];

    Deck(){
        int i=0;

        for(int k=Card.KIND_MAX; k>0; k--){
            for(int n=0; n<Card.NUM_MAX; n++){
                cardArr[i++] = new Card(k, n+1);
            }
        }
    }

    Card pick(int index){
        return cardArr[index];
    }

    Card pick(){
        int index = (int) (Math.random()*CARD_NUM);
        return pick(index);
    }

    void shuffle(){
        for(int i=0; i<cardArr.length; i++){
            int r = (int) (Math.random()*CARD_NUM);

            Card temp = cardArr[i];
            cardArr[i] = cardArr[r];
            cardArr[r] = temp;
        }
    }
}

class Card{
    static final int KIND_MAX = 4;
    static final int NUM_MAX = 13;

    static final int SPADE = 4;
    static final int DIAMOND = 3;
    static final int HEART = 2;
    static final int CLOVER = 1;

    int kind;
    int number;

    Card(){
        this(SPADE, 1);
    }

    Card(int kind, int number){
        this.kind = kind;
        this.number = number;
    }

    public String toString(){
        String[] kinds = {"", "CLOVER", "HEART", "DIAMOND", "SPADE"};
        String numbers = "0123456789XJQK";

        return "kind : " + kinds[this.kind] + ", number : " + numbers.charAt(this.number);
    }
}

public class exCode {
    public static void main(String[] args) {
        Deck d = new Deck();
        Card c = d.pick(0);
        System.out.println(c);

        d.shuffle();
        c = d.pick(0);
        System.out.println(c);
    }
}

[실행 결과]

 


 

2. 제어자

클래스, 변수, 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여하는 것이다.

 

종류

- 접근 제어자 : public, protected, private, default

- 그 외 : static, final, abstract, native, transient, sunchronized, volatile, strictfp

 

접근 제어자는 한 번에 한가지만 사용할 수 있으며, 그 외의 제어자는 여러개를 조합하여 사용할 수 있다.

 

#제어자

static : 클래스의, 공통적인

멤버변수, 메서드, 초기화 블럭에 사용할 수 있다.

인스턴스가 아닌 클래스에 관련된 것이므로 인스턴스를 생성하지 않아도 사용할 수 있다는 의미를 가진다.

 

final : 마지막의, 변경될 수 없는

클래스, 메서드, 멤버변수, 지역변수의 거의 모든 곳에 사용할 수 있다.

변수에 사용하면 값을 변경할 수 없는 상수가 되고, 메서드에 사용하면 오버라이딩이 불가해진다. 클래스에 사용하면 자손클래스를 정의하지 못하게 된다는 의미이다.

 

abstract : 추상의, 미완성의

클래스와 메서드에 사용할 수 있다.

추상 메서드를 선언할 때 많이 사용되는데, 이는 메서드의 선언부만 작성하고 실제 수행내용은 구현하지 않았다는 것을 의미한다. 클래스 앞에도 사용가능한데, 클래스 내에 추상 메서드가 선언되어 있다는 것을 알려준다.


#접근 제어자

클래스, 멤버변수, 메서드, 생성자에 사용 가능하다.

public

접근 제한 없이 어디서든 접근이 가능하다.

 

protected

같은 패키지 내 또는 다른 패키지의 자손클래스에서 접근이 가능하다.

 

default

같은 패키지 내에서만 접근이 가능하다.

 

private

같은 클래스 내에서만 접근이 가능하다.

 

접근범위 : public > protected > (default) > private

 

사용 시 주의사항

1. 메서드에 static과 abstract을 함께 사용할 수 없다.

2. 클래스에 abstract과 final을 동시에 사용할 수 없다.

3. abstract메서드의 접근 제어자로 private은 사용할 수 없다.

4. 메서드에 private과 final을 같이 사용할 수 없다.

 

 

 

 

 

'▶ JAVA > 개념정리' 카테고리의 다른 글

[Java] 12.객체지향언어(3)_클래스  (0) 2022.03.08
[Java] 11.객체지향언어(2)_클래스  (0) 2022.03.07
[Java] 10. 객체지향언어(1)_클래스  (0) 2022.02.10
[Java] 9. 배열_예제  (0) 2022.02.07
[Java] 8. 배열  (0) 2022.02.04