JaeWon's Devlog
article thumbnail
반응형

- 해당 내용은 백기선 님의 자바 온라인 스터디 공부 및 제출 목적

   -> https://github.com/whiteship/live-study/issues/8

 

8주자 과제: 인터페이스 · Issue #8 · whiteship/live-study

목표 자바의 인터페이스에 대해 학습하세요. 학습할 것 (필수) 인터페이스 정의하는 방법 인터페이스 구현하는 방법 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법 인터페이스 상속 인터

github.com


목표

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

학습할 것 (필수)

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

 * 인터페이스(Interface)

- Java는 클래스(class)를 단일 상속이 가능한 특성을 가지고 있는데, 이는 객체지향 프로그래밍에서 큰 제약이기 때문에 인터페이스(interface)라는 개념을 도입.

- 인터페이스라는 이름답게 디자인(설계)적인 요소를 위한 유형이므로, 메소드를 정의하지만 기본적으로 구현 코드는 제공하지 않음.

- 인터페이스를 구현받는 클래스에서 메소드의 내용을 구현.

interface와 abstract 클래스를 사용하는 이유
- 설계시 선언해두면, 개발할 때 기능을 구현하는 데에만 집중할 수 있다.
- 공통적인 인터페이스와 abstract 클래스를 선언해 놓으면, 선언과 구현을 구분할 수 있다.

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

- 클래스 작성하는 방법과 동일하다. 다만 키워드로 class 대신 interface를 사용.

- 모든 메소드는 추상 메소드로 간주.

- 인터페이스는 공용 API를 정의하기 때문에, 암시적으로 public 이므로 생략하는 것이 일반적.

  • 인터페이스 내에 존재하는 메소드는 무조건 "public abstarct"로 선언되며, 생략 가능
  • 인터페이스 내에 존재하는 변수는 무조건 "public static final"로 선언되며, 생략 가능

- 인스턴스 필드를 정의 할 수 없음.

- 인터페이스는 인스턴스화 할 수 없으므로 생성자가 필요 없음.

- 메소드 정의만 있으며, 구현은 없음(구현은 상속받은 클래스에서 구현)

interface Fruit {
    int MAX_COUNT = "10";
    // public static final MAX_COUNT = "10";
    
    int sale(int count);
    // public abstract int sale(int count);
}

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

- implements 라는 키워드를 사용.

- 클래스의 상속과 달리 여러개의 인터페이스를 implements 할 수 있다.

- 인터페이스가 가지고 있는 메소드를 하나라도 구현하지 않으면, 해당 클래스는 추상 클래스가 된다. ( 추상 클래스는 인스턴스를 만들 수 없다. 즉, 메모리에 할당되어 실제 사용될 수 없다.)

- 인터페이스에 정의되어 있는 메소드를 필수적으로 구현해야 한다.

public class Apple implements Fruit {

    @Override
    public int sale(int count){
    	System.out.println("사과를 " + count + " 개 팔았습니다.");
        return count;
    }
    
    public void myName(){
    	System.out.println("내 이름은 사과");
    }
}
public class Banana implements Fruit, Mart, ... {

    @Override
    public int sale(int count){
    	System.out.println("바나나를 " + count + " 개 팔았습니다.");
        return count;
    }
    
    public void myName(){
    	System.out.println("내 이름은 바나나");
    }
    
    // Mart와 기타 인터페이스를 상속받고, 메소드를 선언하지 않으면 해당 파일은 실제 사용되지 않는다.
    ...
}

 

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

- 다형성을 통해서 자식 클래스의 인스턴스를 부모타입의 참조변수로 참조하는 것이 가능하다는 것이 확인.

- 객체는 클래스가 아닌 터페이스로 참조.

public static void main(String[] args){
	...
    // 추천
    List<String> list = new ArrayList<String>();
    Map<String, Object> map = new HashMap<String, Object>();
	
    // 비추천(선언이 안되는 것은 아님)
    ArrayList<String> list2 = new ArrayList<String>();
    HashMap<String, Object> map2 = new HashMap<String, Object>();
    	...
}

- 인터페이스 타입의 참조변수로 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로 형변환이 가능.

public static void main(String[] args){
    Fruit apple = new Apple();
    Fruit banana = new Banana();
    
    apple.sale(10);  // 사과를 10개 팔았습니다.
    banana.sale(5);  // 바나나를 5개 팔았습니다.
    
    apple.myName();  // X
    banana.myName(); // X
    
    (apple)apple.myName();  // O
    (banana)banana.myName();  // O
}

- 위 예제에서 apple과 banana가 바라보는 것은 Fruit 인터페이스이기 때문에 각각의 myName() 메소드는 호출하지 못한다.

- 해당 메소드를 호출하기 위해서는 각 클래스로 캐스팅하여 사용해야 한다.

public static void main(String[] args){
    Apple apple = new Apple();
    Banana banana = new Banana();
    
    apple.sale(10);
    banana.sale(5);
    
    apple.myName();  // O
    banana.myName();  // O
}

- 위 예제이서 apple과 banana가 바라보는 것은 자신의 클래스이기 때문에 각각의 myName() 메소드 호출이 가능하다.

4. 인터페이스 상속

- 인터페이스는 인터페이스로부터만 상속을 받을 수 있으며, 다중 상속이 가능.

- 클래스의 상속과 마찬가지로 자식 인터페이스에는 부모 인터페이스에 정의된 멤버를 모두 상속.

- 인터페이스는 클래스와 달리 Object 클래스와 같은 최고 부모 인터페이스가 없다.

// 인터페이스 선언
interface Fruit {
    void sale();
}

interface Mart {
    void whereSale();
}

--------------------------------------------------------
// 구현 class
public class test implements Fruit, Mart {
	
    @Override
    public void sale(){
    	System.out.println("사과를 팔다");
    }
    
    @Override
    public void whereSale(){
    	System.out.println("사과를 마트에서 사다");
    }
}

- 위 예제를 살펴보면, test 클래스가 Fruit, Mart 2개의 구현을 받았기 때문에, 각각의 메소드를 구현해주어야만 한다.

// 인터페이스 선언
interface Fruit {
    void sale();
}

interface Mart {
    void whereSale();
}

interface Apple extends Fruit, Mart {}

--------------------------------------------------------
// 구현 class
public class test implements Apple {
	
    @Override
    public void sale(){
    	System.out.println("사과를 팔다");
    }
    
    @Override
    public void whereSale(){
    	System.out.println("사과를 마트에서 사다");
    }
}

- 위 예제를 살펴보면, Apple은 Fruit, Mart를 다중 상속을 받았고, test 클래스는 Apple를 implements(구현)을 받았으므로, 상속받은 2개의 메소드를 구현해주어야만 한다.

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

- Java 8 에서 부터 도입된 기능으로 구현을 포함하는 메소드를 포함한 인터페이스를 정의 할 수 있다.

- 인터페이스에 메소드를 추가하는 것은, 추상 메소드를 추가한다는 것이고, 이는 해당 인터페이스를 구현한 기존의 모든 클래스에 새로 추가된 메소드를 구현해야 하는 것이다.

- Default Method(디폴트 메소드)는 추상 메소드가 아니기 때문에, 추가되어도 기존 클래스에서 추가된 메소드를 구현하지 않아도 된다.

- 메소드 앞에 default 키워드를 붙이며, 추상 메소드와 달리 { }가 있어야 한다.

- 상속받은 인터페이스의 메소드도 Default Method 로 정의 할 수 있다.

interface Fruit {
    void whereSale();
    
    default void sale(){
    	System.out.println("과일을 팔다")
    }
}

--------------------------------------------
// 구현 class
public class Apple implements Fruit {
    @Override
    public whereSale(){
    	System.out.println("시장에서 사과를 팔다");
    }
    
    // Default Method 는 생략 가능
}

--------------------------------------------
public static void main(String[] args){
    Fruit Apple = new Apple();
    apple.sale(); // "과일을 팔다"
}
interface Fruit {
    void whereSale();
    
    default void sale(){
    	System.out.println("과일을 팔다")
    }
}

--------------------------------------------
// 구현 class
public class Apple implements Fruit {
    @Override
    public whereSale(){
    	System.out.println("시장에서 사과를 팔다");
    }
    
    // Default Method 는 재선언 가능
    @Override
    public sale(){
    	System.out.println("사과를 팔다")
    }
}

--------------------------------------------
public static void main(String[] args){
    Fruit Apple = new Apple();
    apple.sale(); // "사과를 팔다"
}

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

- 인스턴스 생성과 상관없이 인터페이스 타입으로 호출하는 메소드.

- static 키워드를 사용하며, 접근제어자는 항상 public 이지만 생략 가능.

- { } 가 있어야 한다.

- 재선언(Override)이 불가능하다.

interface Fruit {
    void whereSale();
    
    static void sale(){
    	System.out.println("과일을 팔다")
    }
}

--------------------------------------------
// 구현 class
public class Apple implements Fruit {
    @Override
    public whereSale(){
    	System.out.println("시장에서 사과를 팔다");
    }
    
    // Default Method 는 재선언 불가능
    /*
    @Override
    public sale(){
    	System.out.println("사과를 팔다")
    }
    */
}

--------------------------------------------
public static void main(String[] args){
    Fruit Apple = new Apple();
    //apple.sale(); // Error
    
    Fruit.sale(); // "과일을 팔다"
}

- static 메소드를 사용할 경우, 기존 클래스의 static 메소드처럼 class명.메소드 "apple.sale()"로 호출하는게 아닌, interface명.메소드"Fruit.sale()"로 호출해야 한다.

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

- Java 9 에서부터 인터페이스에서 private methods 사용이 가능.

- Default Methods 가 동일한 구현을 가지고 있다면 이 부분을 private method로 따로 분리하여 처리가 가능.

- { } 가 있어야 하고, abstract(추상적)이 아니다.

- 구현체에서 구현할 수 없고 자식 인터페이스에서 상속이 불가능.

- static 메소드도 private이 가능.

interface Fruit {
    void whereSale();
    
    default void fruitMethod(){
    	sale();
    }
    
    private void sale(){
    	System.out.println("과일을 팔다")
    }
}

--------------------------------------------
// 구현 class
public class Apple implements Fruit {
    @Override
    public whereSale(){
    	System.out.println("시장에서 사과를 팔다");
    }
}

--------------------------------------------
public static void main(String[] args){
    Fruit Apple = new Apple();
    apple.fruitMethod(); // "과일을 팔다"
}

참고

- https://blog.baesangwoo.dev/posts/java-livestudy-8week/

- https://dev-coco.tistory.com/13?category=962739

- https://yadon079.github.io/2021/java%20study%20halle/week-08

반응형

'Study > Java(Online-Study)' 카테고리의 다른 글

9주차 과제: 예외 처리  (0) 2021.08.07
7주차 과제 : 패키지  (0) 2021.07.19
6주차 과제: 상속  (0) 2021.07.17
5주차 과제: 클래스 - 이론(1)  (0) 2021.06.27
4주차 과제: 제어문 - 이론(1)  (0) 2021.06.20
profile

JaeWon's Devlog

@Wonol

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!