ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 8주차 과제: 인터페이스
    Programming/Java live study 2021. 1. 5. 14:51
     

    whiteship/live-study

    온라인 스터디. Contribute to whiteship/live-study development by creating an account on GitHub.

    github.com

    목표

    자바의 인터페이스에 대해 학습하세요.

     

    학습할 것

    • 인터페이스 정의하는 방법
    • 인터페이스 구현하는 방법
    • 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
    • 인터페이스 상속
    • 인터페이스의 기본 메소드 (Default Method), 자바 8
    • 인터페이스의 static 메소드, 자바 8
    • 인터페이스의 private 메소드, 자바 9

    1. 인터페이스 정의하는 방법

    1.1 인터페이스란?

     서로 다른 하드웨어 장치들이 상호 접속하여 데이터를 주고받을 수 있는 규격을 의미한다. 이러한 규격은 컴퓨터로 예시를 들어보았다. 메인 보드와 주변 장치를 기계적으로 기계 내부적으로 접속하는 규격을 약속하면 그 약속에 맞추어 제작만 한다면 다양하게 조합이 가능하다. 이러한 개념을 Java는 소프트웨어에 적용하였다. 

    1.2 Java에서 인터페이스

     동일한 기능을 수행하도록 강제한다. Java의 다형성을 극대화하여 코드 수정을 줄이고 동일한 기능과 의도를 전달한다. 특정 객체가 인터페이스를 사용한다면 그 객체를 인터페이스의 모든 메소드를 구현해야 한다. 

    1.3 인터페이스 정의하는 방법 

    public interface Car {
        int MAX_SPEED = 300; // public static final int
        void moveForward(int degree); // public abstract moveForward(int degree);
        void moveBackward(int degree); // public abstarct moveBackward(int degree);
    }

     

     class 키워드 대신 interface를 사용하여 작성한다. Java 8 이전 이러한 특성을 가지고 있었다.

    • 멤버는 추상 메소드와 상수만 가능하다.
    • 모든 메소드는 public이며 생략이 가능하다.
    • 상수는 public static final 생략이 가능하다.
    • 인터페이스는 객체를 생성할 수 없다. ex) new Car(); // X
    • 다른 인터페이스에 상속될 수 있고 다중 상속을 허용한다.
    • 인터페이스는 래퍼런스 변수로 사용이 가능하다. ex) Car car; // O

     Java 8 이후 부터는 default 메소드와 static 메소드가 추가되었다. 

     Java 9 이후 부터는 private 메소드를 정의할 수 있다.

     

     인터페이스안에 인터페이스나 클래스를 중첩하여 사용 할 수 있다. 인터페이스 내부에 선언된 인터페이스나 클래스는 public static으로 간주된다.

     

    1.4 추상 클래스와 인터페이스의 공통점

     자기 자신을 객체화 할 수 없으며 다른 객체가 상속하거나 구현하여 객체를 생성할 수 있다. 상속, 구현한 하위 클래스는 상위에서 정의한 추상 메소드를 반드시 구현해야 한다.

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

    추상 클래스

     - 일반 메소드가 포함 가능하다.

     - 다중 상속이 불가능 하다.

     - 상수, 변수 필드가 포함 가능하다.

     

    인터페이스

     - 모든 메소드는 추상 메소드이다. 하지만 Java 8이후 부터는 defualt와 static이, Java 9 이후 부터는 private이 추가되었다.

     - 다중상속이 가능하다.

     - 상수 필드만 포함이 가능하다.

     

    1.6 is-a, has-a 

     추상 클래스는 is-a ~은 ~ 이다.

     인터페이스는 has-a ~은 ~을 할 수 있다.

    1.7 인터페이스에 하나의 메소드

     인터페이스에 하나의 메소드만 있는 경우 익명 클래스로 작성이 가능하다.


    2. 인터페이스 구현하는 방법

     인터페이스를 구현하는 것은 인터페이스의 추상 메소드를 클래스에 구현하는 것을 의미한다. 클래스에 구현하기 위해서는 implements라는 키워드가 필요하다.

     

    public class ElectricCar implements Car {
    
        private int speed;
    
        public int getSpeed() {
            return speed;
        }
    
        public void setSpeed(int speed) {
            this.speed = speed;
        }
        
        public int getMaxSpeed() {
            return MAX_SPEED;
        }
    
        @Override
        public void moveForward(int degree) {
            speed += degree;
        }
    
        @Override
        public void moveBackward(int degree) {
            speed -= degree;
        }
    }

     

     인터페이스는 반드시 모든 추상 메소드를 구현해야 한다. 앞서 정의한 moveForward와 moveBackward를 전부 구현하였다. 구현하지 않으면 컴파일 오류가 발생하는 것을 알 수 있다.

     

    public class ElectricCar implements Car, Power{
    
        private int speed;
    
        public int getSpeed() {
            return speed;
        }
    
        public void setSpeed(int speed) {
            this.speed = speed;
        }
    
        public int getMaxSpeed() {
            return MAX_SPEED;
        }
    
        @Override
        public void moveForward(int degree) {
            speed += degree;
        }
    
        @Override
        public void moveBackward(int degree) {
            speed -= degree;
        }
    
        @Override
        public void powerOn() {
            System.out.println("power on");
        }
    
        @Override
        public void powerOff() {
            System.out.println("power off");
        }
    }

     

     인터페이스는 다중으로 구현이 가능하다. 또한 상속 extends와 함께 인터페이스 구현 또한 가능하다.

     

    상속과 다중 구현이 적용된 ArrayList


    3. 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법

     위의 코드를 활용하여 구현체를 사용하였다.

     

    레퍼런스 변수로 사용된 인터페이스 Car

     인터페이스를 레퍼런스 변수로 사용하여 구현체인 클래스를 가리키고 있다. Car 인터페이스를 구현한 모든 클래스를 가리킬 수 있다. 하지만 구현체에 새롭게 정의한 메소드나 필드는 사용할 수 없다. 오로지 인터페이스에서 정의한 메소드만 사용이 가능하다.


    4. 인터페이스 상속

     인터페이스는 클래스와 동일하게 extends 키워드를 사용하여 다른 인터페이스를 상속할 수 있다. 인터페이스는 클래스와 다르게 다중 상속이 가능하다. extends 키워드 옆에 여러 개의 인터페이스를 지정하면 된다. 

     

     상속받은 인터페이스를 구현하는 클래스는 상위 인터페이스에 있는 abstract methods들 까지 구현해야 한다.


    5. 인터페이스의 기본 메소드 (Default Method), 자바 8

    5.1 default 메소드의 등장 배경

     하위 호환성 때문에 등장하였다. 많은 사람들이 사용하는 오픈 소스가 있다고 가정하자. 만약 그 오픈 소스의 인터페이스에 새로운 메소드를 만들어야 하는 상황이다. default 메소드가 없던 시절에는 인터페이스에 메소드를 추가하면 그것을 구현한 구현체들은 전부 오류가 발생하게 된다. 이러한 상황에서 default 메소드는 적합한 해결책이다.

     

     기존 인터페이스에 default 메소드를 생성하면 기존의 코드들을 수정하지 않아도 된다. 추가된 메소드가 필요한 시점에 재정의하면 그만이다. 이런 점이 하위 호환성을 높이는데 기여한 것 같다.

     

    출처https://dev-coco.tistory.com/13 [슬기로운 개발생활😃]

    5.2 default 메소드

     인터페이스에 default 키워드가 선언되어 있으면 메소드를 구현할 수 있다. 이를 구현하는 클래스는 default 메소드를 오버라이딩 할 수 있다.

     

    public interface Car {
        int MAX_SPEED = 300;
        void moveForward(int degree);
        void moveBackward(int degree);
    
        default void pushHorn() {
            System.out.println("빵빵");
        }
    }

     

    public class ElectricCar implements Car, Power {
    
        private int speed;
    
        public int getSpeed() {
            return speed;
        }
    
        public void setSpeed(int speed) {
            this.speed = speed;
        }
    
        public int getMaxSpeed() {
            return MAX_SPEED;
        }
    
        @Override
        public void moveForward(int degree) {
            speed += degree;
        }
    
        @Override
        public void moveBackward(int degree) {
            speed -= degree;
        }
    
        @Override
        public void powerOn() {
            System.out.println("power on");
        }
    
        @Override
        public void powerOff() {
            System.out.println("power off");
        }
    }

     

     해당 메소드를 오버라이딩 하지 않아도 ElecticCar는 사용이 가능하다. 필요에 의해서 오버라이딩 하여 사용할 수 있다.

     

     이 기능이 도입된 이유는 기존 인터페이스를 새로운 메소드로 확장하는 방법을 제공하기 위해서 이다. default 메소드가 이미 구현을 제공하기 때문에 인터페이스를 구현하는 클래스는 새로운 메소드를 구현할 필요 없이 그대로 사용이 가능하다. 구현이 적합하지 않으면 나중에 다시 재정의 할 수 있다.

     

    5.3 Java 8이전 과 이후 인터페이스의 default 메소드

     Java 8 이전에 인터페이스의 default 메소드가 제공되지 않았던 시절에는 인터페이스의 여러가지 메소도들 중 한 가지 메소드만 사용하는 구현체가 있을때 중간에 추상 클래스를 만들어서 이 추상 클래스를 확장하는 구현체에서 필요한 메소드만 구현하도록 편의를 제공하였다.

     

     하지만 Java 8 이후 인터페이스의 default 메소드가 제공되었기 때문에 필요한 메소드만 골라서 상속할 수 있게 되었다.

    5.4 한 클래스에서 동일한 이름을 가진 default 메소드를 가진 인터페이스를 구현할 경우

     만약 두 개의 인터페이스에 같은 메소드 명이 존재한다고 가정하자. 두 개의 인터페이스를 전부 구현하는 클래스는 어떻게 되는가? 

     

     컴파일 에러가 나는 것을 알 수 있다. 피해가기 위한 방식에는 여러가지가 있다.

      - 해당 메소드를 오버라이딩하여 사용한다.

      - 특정 인터페이스의 defualt 메소드의 body 부분을 사용하고 싶다면, 인터페이스.super.메소드명() 이러한 형태로 재정의한 메소드에 명시해준다.

     

    출처:

    www.notion.so/4b0cf3f6ff7549adb2951e27519fc0e6


    6. 인터페이스의 static 메소드, 자바 8

     Java 8에서는 인터페이스에 static method를 정의할 수 있다. 인터페이스의 모든 메소드는 public 이기 때문에 자동적으로 public하게 접근이 가능하다. 또한 static 메소드는 상속되지 않기 때문에 인터페이스에서 바로 접근해야 한다.

     

    public interface Car {
        int MAX_SPEED = 300;
        void moveForward(int degree);
        void moveBackward(int degree);
    
        static void pushHorn() {
            System.out.println("빵빵");
        }
    }

     

    public class Main {
    
        public static void main(String[] args) {
            Car.pushHorn(); // Car로 바로 접근해서 사용
        }
    }

     

    빵빵

     

     인터페이스의 static 메소드는 재정의할 수 없다. 인스턴스로 접근하는지 클래스로 접근하는지에 대한 차이가 있다. 서로 다른 영역에 있는 것이기 때문에 관련하여 잘 생각하고 메소드를 재정의 해야 한다. 또한 default 메소드가 있는 인터페이스를 상속하여 default 메소드를 static으로 재정의할 수 없다.

     

     default 메소드와 마찬가지로 static 메소드를 추가해도 기존의 코드들을 수정하지 않고 그대로 사용할 수 있다.


    7. 인터페이스의 private 메소드, 자바 9

     Java 9 이후부터는 인터페이스에 private method와 private static method 사용이 가능하다. Java 8에서 default 메소드와 static 메소드의 등장으로 인터페이스 내에 구현을 포함하게 되었다. 하지만 복잡한 로직을 구현하기 위해서는 길고 복잡한 코드들로 body를 채워야 했다.

     

     메소드를 구현할 때 간단한 메소드로 복잡한 메소드를 구성하는 것이 재사용성과 코드 이해에 많은 도움이 된다. 그렇기 때문에 Java 9에서는 구현 세부 사항이 들어 있는 메소드들은 private 키워드를 사용하여 private 메소드로 작성한다. 

     

     Java 9에서 private 메소드는 body가 있고, abstract가 아니다. 또한 static 키워드가 붙을 수 있다. private 메소드는 인터페이스 내부에서만 사용되기 때문에 구현 클래스에서 구현할 필요 없다. 

     

     또 한가지 고려해야 할 점은 private 메소드는 private, abstract, default, static 메소드를 호출 할 수 있다. private static은 static과 static private 메소드만 호출이 가능하다.


    8. 이제 추상 클래스는 필요 없지 않은가?

     그렇지 않다. 상태의 존재 여부에 따라 달라진다. 추상 클래스의 많은 것들을 인터페이스가 대체한다. 하지만 추상 클래스에서만 할 수 있는 것들이 남아 있다. 예를 들면 private 필드가 있다. 이러한 부분은 인터페이스가 대체할 수 없기 때문에 아직까지도 추상 클래스가 필요한 부분이 있다. 

     

    References.

    황기태, 김효수 지음 명품 JAVA Programing

     

    [Java] Java Interface feature 변화의 history - 번역

    History of Java interface feature changes 원문 : https://www.vojtechruzicka.com/java-interface-history/ 지나가며 글을 읽다가 빠른 번역(잘못된 번역이 많을 수 있습니다)을 해보았습니다. Original inter..

    flyburi.com

     

    'Programming > Java live study' 카테고리의 다른 글

    10주차 과제: 멀티쓰레드 프로그래밍  (0) 2021.01.21
    9주차 과제: 예외 처리  (0) 2021.01.13
    7주차 과제: 패키지  (0) 2020.12.30
    6주차 과제: 상속  (0) 2020.12.24
    5주차 과제: 클래스  (0) 2020.12.24

    댓글

Designed by Tistory.