동글이기가 레포

인터페이스

 

■ 인터페이스란?

 

객체의 사용 방법을 정의

 

코드와 객체의 중간 다리 역할이며, 코드에서 인터페이스의 메소드를 호출하면 인터페이스는 객체의 메소드를 호출하는 구조

 

사용자는 객체의 내부 구조를 몰라도 인터페이스의 메소드만 알면 사용 가능

 

 

■ 인터페이스를 왜 사용할까?

 

- 설계시 미리 선언해두면 개발할 때 기능 구현에 초점을 맞출 수 있다.

- 프로젝트 시 개개인의 능력과 관계없이 메소드의 이름과 매개변수의 선언 등의 규칙이 유지된다.

- 공통 인터페이스와 추상 클래스를 선언해 놓으면, 선언과 구현을 구분할 수 있다.

 

 

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

 

가장 큰 차이점은

인터페이스는 모든 메소드가 추상 메소드이고, 추상 클래스는 클래스 내 추상 메소드가 하나 이상 포함되는 경우이다.

 

조금 더 자세한 차이는 아래의 표를 참고

 

  인터페이스 추상 클래스
선언 interface abstract class
추상 메소드 포함 가능(필수) 가능
구현된 메소드 포함 불가능 가능
static 메소드 선언 불가능 가능
final 메소드 선언 불가능 가능
상속(extends) 불가능 가능
구현(implements) 가능 불가능

 

 

 

 

인터페이스 정의하는 방법

 

- 인터페이스의 모든 메소드는 추상 메소드(public abstract)로 작성

- 모든 필드는 public static final

  > 만약, 제어자를 생략한다면, 컴파일 시 컴파일러가 자동으로 추가

 

- 인터페이스는 공용 API를 정의하기 때문에 암묵적으로 public

 

- 인스턴스화 할 수 없으므로 생성자가 필요없음

 

- 인터페이스는 중첩 가능

 

// 인터페이스 정의 예시
public interface InterfaceTest {
    int a = 1; // 컴파일러가 자동으로 public static final을 붙임
    public static final int b = 1;
    void testMethod(); // 컴파일러가 자동으로 public abstract를 붙임
    public abstract void testMethod();

 

 

 

인터페이스 구현하는 방법

 

implements 키워드를 사용

 

반드시! 인터페이스에 명시되어 있는 모든 추상 메소드를 구현해야 함

 

// 구현 예시

public interface Animal {
    public abstract void cry();
}

public class Dog implements Animal {
    @Override
    public void cry() {
        Sysyem.out.println("멍멍");
    }
}

public class Cat implements Animal {
    @Override
    public void cry() {
        Sysyem.out.println("야옹");
    }
}

 

위의 인터페이스 및 클래스를 이용해보자

 

// 실행시켜보자
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Cat cat = new Cat();
        
        dog.cry();
        cat.cry();
    }
}

// 결과
멍멍
야옹

 

 

 

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

 

상속을 학습할 때 자식 클래스의 인스턴스를 부모 클래스의 참조 변수로 사용할 수 있었다.

 

인터페이스도 이와 동일하게 인터페이스 타입의 참조변수로 클래스의 인스턴스를 참조할 수 있다.

 

위의 예시를 그대로 가져와서 이용해보자

 

// 구현 예시

public interface Animal {
    public abstract void cry();
}

public class Dog implements Animal {
    @Override
    public void cry() {
        Sysyem.out.println("멍멍");
    }
    
    // 추가 메소드
    public void name() {
        System.out.println("복돌이");
    }
}

public class Cat implements Animal {
    @Override
    public void cry() {
        Sysyem.out.println("야옹");
    }
    
    // 추가 메소드
    public void name() {
        System.out.println("나비");
}

 

위의 인터페이스 및 클래스를 이용해보자

 

// 실행시켜보자
public class Main {
    public static void main(String[] args) {
        // 인터페이스 변수를 선언하고 클래스 객체 생성
        Animal dog = new Dog();
        Animal cat = new Cat();
        
        dog.cry();
        cat.cry();
        
        dog.name(); // 에러 발생, dog이 바라보는 것은 Animal 인터페이스이기 때문
        cat.name(); // 에러 발생, cat이 바라보는 것은 Animal 인터페이스이기 때문
        
        // 위의 문제를 캐스팅으로 해결
        ((Dog)dog).name();
        ((Cat)cat).name();
    }
}

// 결과
멍멍
야옹
복돌이
나비

 

 

 

인터페이스 상속

 

앞전에 상속을 할 때, 상속은 다중 상속이 불가능 하다고 했었다.

 

그러나, 인터페이스는 구현을 할 때 다중으로 가능하다.

 

추가적으로 인터페이스는 인터페이스만 상속을 받을 수 있다.

 

// 예시

public interface Animal {
    public abstract void cry();
}

public interface Human {
    public abstract void name();
}

// 인터페이스에 인터페이스를 상속
public interface life extends Animal, Human {
}

// 구현
public class Test implements life {
    @Override
    public void cry() {
        Sysyem.out.println("안녕하세요");
    }
    @Override
    public void name() {
        Sysyem.out.println("재희");
    }
}

 

위의 인터페이스 및 클래스를 이용해보자

 

// 실행시켜보자
public class Main {
    public static void main(String[] args) {
        // 인터페이스 변수를 선언하고 클래스 객체 생성
        Test t = new Test();
        
        t.cry();
        t.name()
    }
}

// 결과
안녕하세요
재희

 

 

물론, 위와 같이 할 수도 있지만 아래의 방법으로 사용 가능하다.

 

// 예시
public interface Animal {
    public abstract void cry();
}

public interface Human {
    public abstract void name();
}

// 구현
public class Test implements Animal, Human {
    @Override
    public void cry() {
        Sysyem.out.println("안녕하세요");
    }
    @Override
    public void name() {
        Sysyem.out.println("재희");
    }
}

 

 

 

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

 

기존에는 인터페이스에서 메소드를 구현할 수 없었지만, Java 8에서부터 인터페이스에 대한 정의가 몇 가지 변경이 되었다.

 

그것은 바로, default 키워드로 선언하면 메소드를 구현할 수 있다는 것이다.

또한, 이를 구현하는 클래스는 default 메소드를 오버라이딩 할 수 있다.

 

■ 특징

 

- default 메소드는 암시적으로 public 이므로 public을 지정할 필요가 없다.

- 추상 클래스의 입지가 줄어듬 (사실 인터페이스에서 구현까지 할 수 있으면 추상 클래스와 동일한 기능이지 않은가...)

- static 메소드가 아니기 때문에 반드시 구현 클래스를 생성 후 사용이 가능

 

// default 메소드 예시
public interface Test {
    public int division(int a, int b);
    public int minus(int a, int b);
    
    // default 메소드을 통한 인터페이스 내부에서 구현
    default int plus(int a, int b) {
        return a + b;
    }
}

 

 

 

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

 

static 메소드는 위의 default 메소드와 같이 인터페이스에서 구현이 가능한 메소드이다.

 

그러나!!

 

static 메소드는 호출할 때, 반드시 인터페이스 명으로 호출해야 하고 재정의가 불가능하다.

 

위의 예제를 끌어와보자

 

// 예시
public interface Test {
    public int division(int a, int b);
    public int minus(int a, int b);
    
    // default 메소드을 통한 인터페이스 내부에서 구현
    default int plus(int a, int b) {
        return a + b;
    }
    
    // static 메소드를 통한 인터페이스 내부에서 구현
    public static int multiple(int a, int b) {
        return a * b;
    }
}

public class ImpleTest implements Test {
    // default 메소드는 재정의 가능
    @Override
    pubilc int plus(int a, int b) {
        return a + b;
    }
    
    // static 메소드는 재정의 불가능
}

 

위의 인터페이스 및 클래스를 이용해보자

 

// 실행시켜보자
public class Main {
    public static void main(String[] args) {
        // 인터페이스 변수를 선언하고 클래스 객체 생성
        Test t = new ImpleTest();
        
        int a = t.plus(1, 3); // 정상출력
        
        // int b = t.multiple(2, 4); << 에러
        int b = Test.multiple(2, 4)
        
        System.out.println(a, b);
    }
}

// 결과
4 8

 

 

 

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

 

자바 8에서 default와 static 메소드가 추가되면서 새로운 기능을 제공하였다.

 

그러나, 내부 메소드일 경우에도 외부로 공개되는 public 으로 선언을 했어야 했는데, 자바 9에서 private 메소드라는 새로운 기능을 제공하여 이러한 문제를 해결하였다.

 

 

■ 특징

 

- private 메소드는 추상화가 불가능

- 인터페이스 내에서만 사용 가능

- static 메소드도 private이 가능

 

 

마지막이기도 하고, 전체적으로 정리해보자

 

// private 메소드 예시
public interface Test {
    // 일반적인 추상 메소드
    public abstract void method1();
    
    // default 메소드
    public default void method2() {
         method4(); // private 메소드는 인터페이스 내부에서만 사용
         method5(); // private 메소드는 인터페이스 내부에서만 사용
         System.out.println("method2");
     }
     
     // static 메소드
     public static void method3() {
         method5(); // private 메소드는 인터페이스 내부에서만 사용
         System.out.println("method3");
     }
     
     // private 메소드
     private void method4() {
         System.out.println("method4");
     }
     
     // private + static 메소드
     private static void method5() {
         System.out.println("method5");
     }
 }
 
 public class Sample implements Test {
     @Override
     public void method1() {
         System.out.println("method1");
     }
 }

 

위의 인터페이스 및 클래스를 이용해보자

 

// 실행시켜보자
public class Main {
    public static void main(String[] args) {
        // 인터페이스 변수를 선언하고 클래스 객체 생성
        Test t = new Sample();
        
        t.method1();
        t.method2();
        t.method3();
    }
}

// 결과
method1
method4
method5
method2
method5
method3

'스터디 > 동기 Java 스터디' 카테고리의 다른 글

7주차 : 멀티쓰레드 프로그래밍  (0) 2021.05.10
6주차 : 예외 처리  (0) 2021.05.05
5주차 : 패키지  (0) 2021.04.28
4주차 : 상속  (0) 2021.04.25
4주차 : 클래스  (0) 2021.04.21

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading