본문 바로가기

Java

[Java] 상속과 구현에 대한 공부

상속 관계

객체 지향 프로그래밍의 핵심 요소 중 하나로, 기존 클래스의 메서드를 새로운 클래스에서 재사용하게 해 준다.

extends 키워드를 사용하며 하나의 대상만 선택할 수 있다. 

 

부모 클래스

상속을 통해 자신의 필드와 메서드를 다른 클래스에 제공하는 클래스

public class Animals {

    public void sound(){
        System.out.println("소리를 냅니다.");
    }
}

 

자식 클래스

부모 클래스로부터 필드와 메서드를 상속받는 클래스

public class Eagle extends Animals {
    public void fly(){
        System.out.println("날아 갑니다.");
    }
}

eagle이 Animals를 상속받는다.

 

public class Bear extends Animals{

    public void move(){
        System.out.println("뛰어 갑니다.");
    }

    @Override
    public void sound() {
        System.out.println("꽤애액!");
    }
}

Bear도 Animals를 상속받는다. 오버라이딩을 통해서 부모객체에 있는 메서드를 자식 객체에서 구현했다. 

public class AnimalsMain {
    public static void main(String[] args) {
        Eagle eagle = new Eagle();
        System.out.println("Ealge");
        eagle.fly();
        eagle.sound();

        Bear bear = new Bear();
        System.out.println("Bear");
        bear.move();
        bear.sound();
    }
}

실행코드를 실행하면 아래와 같은 실행문이 나온다. 

결과물을 보면 먼저 Eagle에서 가지고 있는 메서드의 값을 확인할 수 있고 또한 상속하고 있는 부모의 메서드를 사용하고 있다. 하지만 Bear는 다르다. 부모에서 상속받은 메서드가 아닌 자신의 메서드인 sound를 사용하고 있다. 

그것은 Bear클래스에 @Override에 있다. 이는 오버라이딩으로 부모에게서 상속받는 메서드를 본인에 맞게 사용하기 위해 사용하는 메서드이다. 

 

코드에서도 보이듯이 하나의 클래스를 여러 개의 자식 클래스가 상속할 수 있지만 한 자식 클래스가 여러 부모를 상속할 수는 없다. 

 

그림으로 이해하면 편할 것이다. 객체가 생성될 때 자신의 부모인 Animals의 클래스 값도 객체 안에 들어간다.

그림에서 보듯이 객체가 구성이 되어있는데 여러 부모를 상속하면 중복되는 코드로 어느 것을 호출해야 하는 문제가 나올 수 있기에 상속은 하나만 가능하다.

또한 그림에서 보듯이 자식클래스부터 살펴보고 상속한 부모 클래스를 살펴본다. 그렇기에 Override가 있다면 부모인 Animals가 아닌 자식객체에 Bear의 메서드에서 실행된다. 이를 통해서 상속을 하더라도 메서드를 내 의도 데로 만들 수 있다.

 

Object 

모든 클래스의 최상위 부모 클래스는 Object를 상속하고 있다.

묵시적으로 상속하고 있어서 표시되지 않는 것뿐이다.

public class AnimalsMain extends Object{
    public static void main(String[] args) {
        Eagle eagle = new Eagle();
        System.out.println("Ealge");
        eagle.fly();
        eagle.sound();

        Bear bear = new Bear();
        System.out.println("Bear");
        bear.move();
        bear.sound();
    }
}

위 코드와 상속에서 설명한 코드는 같은 코드이다. 상속받는 부모가 없으면 묵시적으로 Object 클래스를 상속받는다.

묵시적으로 되기에 extends Object는 생략하는 것을 권장한다.


그림처럼 Object를 묵시적으로 상속하고 있기에 우리는 toString이나 equals를 어디에서도 사용이 가능한 것이다. 

 

추상클래스

구체적이지 않은 추상적인(abstract) 데이터를 담고 있는 클래스이다. 

abstract(추상화)

목표로 하는 실제 객체의 특징과 목적을 간략화시켜서 표현한다.

public abstract class Animals{ //추상클래스 abstract를 선언해야한다.

    public void sound(){
        System.out.println("소리를 냅니다.");
    }

    public abstract void eat(); //추상메서드
}

위 코드를 보면 일단 추상 클래스는 abstract을 선언해야 추상클래스가 된다. 

추상 메서드는 코드와 같이 abstract를 메서드에 붙여준다. 그리고 로직을 적지 않는다. 왜냐하면 이를 상속하는 자식클래스에서 자세하게 로직을 구현할 것이기에 구현 로직을 적지 않는다. 

추상메서드의 abstract는 생략이 가능하다. 

 

이를 상속하는 자식 클래스에서는 아래 코드처럼 추상 클래스의 로직을 무조건 구현해야 한다. 

public class Bear extends Animals{

    public void move(){
        System.out.println("뛰어 갑니다.");
    }

    @Override
    public void sound() {
        System.out.println("꽤애액!");
    }

    @Override
    public void eat() {
        System.out.println("연어를 먹습니다.");
    }
}

만약에 추상클래스의 로직을 구현하지 않으려고 한다면 그 자식클래스도 추상클래스로 선언해야 한다.

결론적으로 클래스로 추상클래스를 상속하면 추상메서드를 무조건 구현해야 한다.

 

추상 클래스에 추상 메서드만 있어도 추상 클래스다. 

접근 제한자인 public을 생략하여(default  접근 제한) 아래 코드와 같이 추상 클래스가 작성이 가능하다.

public abstract class Animals{ //추상클래스 
	
    abstract void sound(); //추상메서드
    abstract void eat(); //추상메서드
}

위에서 언급했듯이 추상메서드에 abstract는 생략이 가능하다.

아래 코드와 위 코드는 같은 코드이다.

public abstract class Animals{ //추상클래스 
	
    void sound(); //추상메서드
    void eat(); //추상메서드
}

 

이 코드 많이 보았지 않은가? 그렇다. 인터페이스이다.

순수 추상클래스를 더 편하게 사용하도록 한 게 인터페이스이다.

public interface Animals{
	
    void sound(); 
    void eat();
}

 

인터페이스

인터페이스는 모든 데이터가 추상화되어있다. 사용자가 직접 로직을 구현해야 한다. 그래서 인터페이스는 상속이 아니라 구현이라고 불리고 구현체를 만들어 줘야 한다. 인터페이스는 상속이 아니기에 implements로 구현한다. 

 

그래서 클래스는 하나만 상속할 수 있지만 인터페이스는 여러 개를 상속해도 무방 한 것이다. 

 

 

 

 

출처

https://www.inflearn.com/course/%EA%B9%80%EC%98%81%ED%95%9C%EC%9D%98-%EC%8B%A4%EC%A0%84-%EC%9E%90%EB%B0%94-%EA%B8%B0%EB%B3%B8%ED%8E%B8