[WIL 23.02.06] 상속과 인터페이스

이승렬·2023년 2월 6일
0

항해99

목록 보기
23/34
post-thumbnail

이번주는 상속과 인터페이스에 대한 개념을 정리하는 시간이다.
특히나 상속과 인터페이스는 많이 쓰는 개념이므로 정리를 하는 것이 좋아보인다.

상속

  • 상속은 객체지향프로그래밍에서 기존의 클래스를 새로운 클래스로 만들때 사용하는 개념이다.
  • 새로운 클래스는 기존의 클래스의 특징을 상속받아서 재사용할 수 있다.
class Animal {
  void walk() {
    System.out.println("Walking");
  }
}

class Cat extends Animal {
  void meow() {
    System.out.println("Meowing");
  }
}
  • 다음과 같은 예시를 통해서 cat 클래스가 animal 클래스를 상속받아서 사용되는 것을 알 수 있다.

  • 이떄 animal 에서 정의된 메서드와 변수 또한 cat 클래스에서 사용할 수 있다.

  • 다음 예시와 같은 경우에는 walk 메서드도 cat 클래스에서 쓸 수 있다는 말이다.

인터페이스

  • 인터페이스는 객체지향프로그래밍에서 클래스가 구현해야할 메서드와 상수들의 목록을 정의하는 것이다.
  • 인터페이스를 구현한 클래스는 인터페이스에 정의된 메서드와 상수를 모두 구현해야 한다.
interface Drawable {
  void draw();
}

class Circle implements Drawable {
  void draw() {
    System.out.println("Drawing Circle");
  }
}
  • 다음과 같이 Drawble 이라는 그릴 수 있다 라는 인터페이스가 있고, circle 이라는 클래스를 만들고 싶다고 가정하자.
  • 이때 circle 클래스는 Drawble 인터페이스를 "모두" 구현해야한다.
  • 즉 Drawble 인터페이스에서 정의된 'draw' 메서드를 circle 클래스에서 구현해야 한다.

상속과 인터페이스의 차이

  • 상속은 기존의 클래스에서 특징을 상속받아 새로운 클래스를 만드는 것이다.
  • 인터페이스는 클래스가 구현해야할 상수들의 목록을 정의하는 것이다.

추상클래스와 인터페이스의 차이?

추상클래스

  • 추상클래스는 추상메서드를 가질 수 있으며, 하위 클래스에서 구현해야 할 메서드의 구조를 정의한다.
  • 추상클래스는 일반적인 클래스와 달리 인스턴스화할 수 없다.

인터페이스

  • 인터페이스는 메서드의 구조만 정의할 수 있으며, 구체적인 구현은 인터페이스를 구현하는 클래스에서 구현해야 한다.
  • 인터페이스는 클래스와 달리 인스턴스화 할 수 없다.

즉 추상클래스는 추상 메서드를 가질 수 있으며, 구체적인 구현을 하위 클래스에서만 할 수 있다. 인터페이스는 메서드의 구조만 정의할 수 있고, 인스턴스화 할 수 없다.

둘이 코드로만 보면 비슷해 보이기는 한다.
다음과 같은 예시를 들어보자.


// 추상 클래스: Vehicle
abstract class Vehicle {
    abstract void accelerate();
    abstract void stop();
    abstract void turn();
}

// 추상 클래스를 상속받은 클래스: Car
class Car extends Vehicle {
    void accelerate() {
        // 구현
    }
    void stop() {
        // 구현
    }
    void turn() {
        // 구현
    }
}

// 인터페이스: VehicleOperations
interface VehicleOperations {
    void accelerate();
    void stop();
    void turn();
}

// 인터페이스를 구현한 클래스: Car
class Car implements VehicleOperations {
    void accelerate() {
        // 구현
    }
    void stop() {
        // 구현
    }
    void turn() {
        // 구현
    }
}
  • 추상클래스와 인터페이스 둘다 메서드의 선언과 구현부분을 분리하여 구조화를 하는 것을 목적으로 한다.
  • 추상 클래스와 인터페이스의 차이는 추상 클래스는 메서드의 구현을 가지고 있어서 인스턴스를 생성할 수 있지만, 인터페이스는 메서드의 구현이 없어서 인스턴스를 생성할 수 없다는 것이다.

다음 예시를 한번 더 보자

abstract class Shape {
    abstract double area();
}

class Circle extends Shape {
    double radius;
    Circle(double radius) {
        this.radius = radius;
    }
    @Override
    double area() {
        return Math.PI * radius * radius;
    }
}

interface Drawable {
    void draw();
}

class Square implements Drawable {
    double side;
    Square(double side) {
        this.side = side;
    }
    @Override
    public void draw() {
        // Draw a square
    }
}
  • 다음 코드에서 Shape 은 추상래스, Drawble 은 인터페이스이다.
  • 둘다 메서드의 구현이 없지만, Shape 은 추상메서드를 가지고는 있지만, 구현이 필수적인 것은 아니다. 상속을 통해서 override 를 통해서 구현은 가능하다.
  • 하지만 Drawble 은 인터페이스로써 추상메서드를 강제적으로 구현하게 하고 있다.
Circle c = new Circle(5);
Square s = new Square(6);
  • 다음과 같이 그렇다면 추상 클래스와 인터페이스 객체를 생성하는데 상관 없지 않냐 라고 생각할 수 있다.
  • 하지만 다음의 예시를 보자.
abstract class Shape {
   abstract void draw();
}

class Circle extends Shape {
   void draw() {
      System.out.println("Drawing Circle");
   }
}

public class Main {
   public static void main(String[] args) {
      Shape shape = new Circle();
      shape.draw();
   }
}

  • 다음 예시에서는 Circle 클래스는 객체를 생성할 수 있다.
  • 이때 다형성이라는 개념을 이용해서 Shape 이라는 추상클래스 리모콘을 가지고 Circle을 찍는 것이다.

다음 예시도 확인해보자.

abstract class Shape {
  abstract void draw();
}

class Circle extends Shape {
  void draw() {
    System.out.println("Drawing Circle");
  }
}

class Square extends Shape {
  void draw() {
    System.out.println("Drawing Square");
  }
}

public class Main {
  public static void main(String[] args) {
    Shape shape1 = new Circle();
    Shape shape2 = new Square();
    shape1.draw(); // Output: Drawing Circle
    shape2.draw(); // Output: Drawing Square
  }
}
  • Main 부분을 잘 보면 다음과 같이 shpae이라는 추상클래스에 상속을 받은 Circle , Square (Shape을 상속받은 클래스) 를 구현했다.
  • 즉 Shape 타입의 변수로 Circle 과 Square 객체를 각각 가리킨다.
  • 다음 예시와 비교해보면서 판단해보자.
interface Drawable {
    void draw();
}

class Circle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a Circle");
    }
}

class Rectangle implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a Rectangle");
    }
}

class Square implements Drawable {
    @Override
    public void draw() {
        System.out.println("Drawing a Square");
    }
}

public class Main {
    public static void main(String[] args) {
        Drawable[] shapes = {new Circle(), new Rectangle(), new Square()};
        for (Drawable shape : shapes) {
            shape.draw();
        }
    }
}
profile
Backend_Developer

0개의 댓글