럿고의 개발 노트

[프로그래머스] 자바 입문 > Part7. 상속 본문

Java Note/[프로그래머스] 자바 입문(동영상 강의)

[프로그래머스] 자바 입문 > Part7. 상속

KimSeYun 2020. 1. 27. 14:56

[프로그래머스] 자바 입문

Part7. 상속

1. 상속

상속

  • 부모가 가진 것을 자식에게 물려주는 것

  • is a 관계나 kind of 관계를 생각하면 됨

  • 클래스 이름 뒤애ㅔ extends 키워드를 적고 부모클래스 이름을 적으면 부모 클래스가 가지고 있는 것을 상속 받을 수 있음

  • 부모가 가지고 있는 메소드외에 추기로 메소드를 선언하는 것을 확장하였다고 표현

public class Car {

    public void run() {
        System.out.println("run");
    }
}
public class Bus extends Car { // Car Class를 상속받은 Bus Class
    // public class 클래스명 extends 부모클래스명
    // 상속이란, 부모가 가지고 있는걸 자식이 물려 받는것
    // 즉, 부모가 가지고 있는 것을 자식이 사용할수 있는 것    

    public void ppangppang() { // 메소드 생성
        System.out.println("빵빵");
    }
}
public class BusExam {

    public static void main(String[] args) {
        Bus bus = new Bus();
        bus.run(); // Bus Class에서는 run 메소드가 없었지만, Car Class에 있던 메소드를 상속 받았기 때문에 사용 가능
        bus.ppangppang(); // Bus Class에서 정의한 메소드

        Car car = new Car();
        car.run(); // Car Class가 가지고 있는 메소드
        //car.ppangppang();, 부모클래스는 자식클래스가 가지고 있는 것은 사용 못함!    
    }
}

2. 접근제한자

접근제한자

  • 클래스 내에서 멤버의 접근을 제한하는 역할

  • 접근제한자의 종류

    • public : 어떤 클래스든 접근
    • protected : 자기 자신, 같은 패키지, 다른 패키지는 상속받은 자식 클래스에서 접근 가능
    • private : 자기 자신만 접근 가능
    • default : 접근제한자를 적지 않은 것으로 자기 자신과 같은 패키지에서만 접근 가능
public class AccessObj {
    // 클래스 = 필드 + 메소드
    // 그러나 클래스가 아무거나 가지고 있으면 안됨, 예를 들면 수학과 관련된 Class면 수학과 관련된 것을 가지고 있어야 함
    // 이런 정의를 캡슐화라고 함. 즉, 관련된 내용을 모아서 가지고 있는 것

    // 필드와 메소드 중에 외부에 노출하지 않고 감추고 싶은 것이 있을 것
    // 그걸 가능하게 하는 것이 접근제한자. 즉, 클래스 내에서 멤버의 접근을 제한하는 역할을 하는 것

    /* 접근제한자 종류
     * public : 누구나 사용 가능 / 가장 넓은 의미
     * protected : 같은 패키지인 경우 접근 허용, 다른 패키지라도 상속받은 경우 접근 허용
     * private : 자기 자신만 접근 가능
     * default : 아무것도 쓰지 않은 경우, 자기 자신과 같은 패키지 내에서만 접근 허용
     */
    public int p = 3; 
    protected int p2 = 4;
    private int p3 = 5;
    int p4 = 2; // default    
}
public class AccessObjExam {
    public static void main(String[] args) {
        AccessObj obj = new AccessObj();
        System.out.println(obj.p); // public
        System.out.println(obj.p2); // protected
        // System.out.println(obj.p3); // private / 사용 불가
        System.out.println(obj.p4); // default
    }
}
public class AccessObjExam extends AccessObj { // 상속
    public static void main(String[] args) {
        AccessObjExam obj = new AccessObjExam();
        System.out.println(obj.p); // public
        System.out.println(obj.p2); // protected (자식 클래스가 사용 가능)
        // System.out.println(obj.p3); // private 사용 불가
        // System.out.println(obj.p4); // default 사용 불가(같은 패키지에 없어서 사용 불가)
    }
}

3. 추상클래스

추상클래스

  • 구체적이지 않은 클래스로 예를 들어 독수리, 타조는 구체적인 새를 지칭하는데 포유류 같은 것은 구체적이지 않음.

  • 위와 같은 예제를 구현한 클래스를 추상 클래스라고 함.ㅣ

  • 추상 클래스 정의하기

    • 추상 클래스는 클래스 앞에 abstract 키워드를 이용해서 정의
    • 추상 클래스는 미완성의 추상 메소드를 포함할 수 있음
    • 추상 메소드란, 내용이 없는(구현되지 않은) 메소드
    • 추상 메소드는 리턴 타입 앞에 abstract라는 키워드를 붙임
    • 추상 클래스는 인스턴스를 생성할 수 없음
  • 추상 클래스를 상속받는 클래스 생성하기

    • 추상 클래스를 상속받은 클래스는 추상 클래스가 가지고 있는 추상 메소드를 반드시 구현해야 함
    • 추상 클래스를 상속받고, 추상 클래스가 갖고 있는 추상 메소드를 구현하지 않으면 해당 클래스도 추상 클래스가 됨
public abstract class Bird {
    // 추상클래스 : 구체적이지 않은 클래스

    public abstract void sing(); // 추상메소드
    // 하나라도 추상메소드가 있다면, class도 추상클래스가 되어여 함
    // 추상클래스 내부에는 일반 메소드가 구현 가능
    public void fly() {
        System.out.println("날다");
    }
}
public class Duck extends Bird {
    @Override
    public void sing() { // 추상메소드였기때문에, 상속받을때 메소드를 정의해줘어 함.
        System.out.println("꽥꽥!");
    }    
}
public class DuckExam {
    public static void main(String[] args) {
        Duck duck = new Duck();
        duck.sing();
        duck.fly();

        // Bird bird = new Bird(); 추상클래스를 생성할수는 없음
        // 즉, 객체로 생성이 되지 않음
    }
}

4. super와 부모생성자

super와 부모 생성자

  • class가 인스턴스화 될 때 생성자가 실행되면서 객체의 초기화를 한다. 그때 자신의 생성자만 실행되는 것이 아니라 부모 생성자부터 실행 됨

  • 생성자는 객체를 초기화 하는 역할을 하는데, 생성자가 호출될 때 자동으로 부모의 생성자가 호출되면서 부모 객체를 초기화 함

  • 자신을 가리키는 키워드가 this라면, 부모를 가리키는 키워드는 super

  • super()는 부모의 생성자라는 의미

  • 부모의 생성자를 임의로 호출하지 않으면, 부모 class의 기본 생성자가 자동으로 호출

  • 클래스는 기본 생성자가 없는 경우도 존재하는데, 이런 문제를 해결하기 위해 자식 클래스의 생성자에서 직접 부모 생성자를 호출해줘야 함.

  • super키워드는 자식에서 부모의 메소드나 필드를 사용할 때도 사용

public class Car1 {
    public Car1(String name) { // 기본생성자
        System.out.println("Car1의 name 생성자 입니다.");
    }
}
public class Truck extends Car1 {
    public Truck() { // 기본생성자
        // super키워드 : 부모 개체를 나타내는 키워드
        // super(); // 부모의 기본생성자를 실행해달라고 하는건데, 부모가 있다면 자동으로 생성
        // super 키워드가 필요한 경우, 부모의 생성자가 기본생성자가 아닐때, 부모 생성자를 직접 호출해줘야 함
        super("소방차"); // 부모의 생성자가 기본생성자가 아닌 경우 부모 생성자를 수동으로 정의해야함
        System.out.println("Truck의 기본생성자 입니다.");
    }
}
public class TruckExam {
    public static void main(String[] args) {
        Truck truck = new Truck(); // Car1 기본생성자 다음 Truck 기본생성자가 실행            
        //Car1 car1 = new Car1(); // Car1 기본생성자만 실행
    }
}

5. 오버라이딩

오버라이딩(OverRiding)

  • 부모가 가지고 있는 메소드와 똑같은 모양의 메소드를 자식이 가지고 있는 것

  • 즉, 메소드를 재정의 하는 것

  • 메소드를 오버라이드 하면, 항상 자식클래스에서 정의된 메소드 호출

  • 그러나, 오버라이딩을 한다고 해서 부모의 메소드가 사라지는 것은 아님
    (super 키워드를 이용하여 부모 클래스 호출 가능)

public class Bus2 extends Car2 {
    public void run() {
        super.run(); // 부모의 run메소드를 호출, 부모의 메소드의 기능도 쓰고 거기에 기능을 추가하고 싶을때 사용
        System.out.println("Bus의 run 메소드");
    }
}
public class BusExam2 {
    public static void main(String[] args) {
        Bus2 bus2 = new Bus2(); // 인스턴스 생성
        bus2.run(); // 부모의 메소드가 아니라 자식의 메소드가 실행
    }
}
public class Car2 {
    // 오버라이딩
    // 부모가 가지고 있는 메소드와 똑같은 모양의 메소드를 자식이 가지고 있는 것
    // 즉, 메소드를 재정의 하는 것
    // 부모의 기능을 그대로 사용하지 않을 경우 자식이 기능을 재정의 하는 것
    public void run() {
        System.out.println("Car2의 run 메소드");
    }
}

6. 클래스 형변환

클래스 형변환

  • 부모타입으로 자식 객체를 참조하게 되면 부모가 가지고 있는 메소드만 사용 가능

  • 자식 객체가 가지고 있는 메소드나 속성을 사용하고 싶으면 형변환이 필요

  • 객체들 끼리도 형 변환이 가능하지만 상속관계가 있을때만 가능

  • 부모타입으로 자식타입의 객체를 참조할 때는 묵시적 형변환이 발생

  • 부모타임의 객체를 자식타입으로 참조하게 할때는 명시적 형변환을 해줘야 함.

  • 단, 이렇게 형변환을 할때는 부모가 참조하는 인스턴스가 형변환 하려는 자식타입일때만 가능

public class Bus3 extends Car3{ // Bus3 is a Car3
    public void ppangppang() { // 자식만 가지고 있는 메소드
        System.out.println("빵빵");
    }
}
public class BusExam3 {
    public static void main(String[] args) {
        // 클래스 형변환
        // 부모타입으로 자식객체를 참조하게 되면 부모가 가지고 있는 메소드만 사용 가능
        // 자식객체가 가지고 있는 메소드나 속성을 사용하고 싶다면 형변환을 사용 해야 함
        Car3 car3 = new Bus3(); // 부모타입으로 자식객체를 참조할 수 있음
        car3.run(); 
        // car3.ppangppang(); // 그러나 자식객체를 참조한다 해도, 부모가 가지고 있는 메소드만 사용 가능
        // 즉, 부모 타입으로 자식을 가르킬 수 있지만, 부모가 가지고 있는 것만 사용 가능

        // 그러나, 사용할 수 있는 방법이 있는데, 그것이 형 변환이다.

        Bus3 bus3 = (Bus3)car3; // 형변환
        bus3.run();
        bus3.ppangppang(); // 따라서 사용 가능

        // 그리고 car3를 참조하고 있는 것이 Bus3이기 때문에 형변환을 가능한 것
    }
}
public class Car3 {
    public void run() {
        System.out.println("Car의 run 메소드");
    }
}

※ 출처

[프로그래머스] 자바 입문

Comments