본문 바로가기
IT 이야기/Java

[Java Study] 8일차 인터페이스(interface)

by Dblog 2021. 1. 6.
728x90

학습할 것

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

인터페이스

인터페이스(interface)는 서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면이다. 즉, 사용자가 기기를 쉽게 동작시키는데 도움을 주는 시스템을 의미한다. 컴퓨팅에서 컴퓨터 시스템끼리 정보를 교환하는 공유 경계이다. 이러한 교환은 소프트웨어, 컴퓨터 하드웨어, 주변기기, 사람 간에 이루어질 수 있으며, 서로 복합적으로 이루어질 수도 있다. 터치스크린과 같은 일부 컴퓨터 하드웨어 장치들은 인터페이스를 통해 데이터를 송수신할 수 있으며 마우스나 마이크로폰과 같은 장치들은 오직 시스템에 데이터를 전송만 하는 인터페이스를 제공한다.

https://ko.wikipedia.org/wiki/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4_(%EC%BB%B4%ED%93%A8%ED%8C%85)

 

인터페이스 (컴퓨팅) - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. 인터페이스(interface)는 서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면이다. 즉, 사용자가 기기를 쉽게 동작시키는

ko.wikipedia.org

 

인터넷에 인터페이스를 검색했을 때 인터페이스의 정의는 사용자가 기기를 쉽게 동작시킬 수 있도록 도와주는 시스템을 말합니다.

OS, UI와 같은 장비를 말하는 거 같은데 이번에 공부할 Java의 인터페이스랑 조금 다른 거 같아 다시 검색을 해봤더니 OOP interface, 즉 객체 지향의 인터페이스를 공부해야 했습니다. 

 

사설이 길었습니다.
이번에 공부할 인터페이스

빈 껍데기, 구현을 해서 사용해야 하는 것, 어떠한 기능을 정의해놓지 않고, 단지 비슷한 기능을 모아서 어떻게 만들겠다고 추상적으로 선언만 해놓은 것
(출처: https://ksj14.tistory.com/entry/interface-인터페이스)

으로 정의할 수 있습니다.  예를 들어 클래스를 붕어빵 틀에 비유한다면 인터페이스는 붕어빵 안에 슈크림이 들어가는지 팥이 들어가는지에 대한 레시피를 예 로들 수 있을 것 같습니다.

인터페이스도 붕어빵 틀과 비슷한 거 같긴 하지만.. 굳이 차이를 두자면 레시피를 예로 들 수 있을 것 같습니다.
(앙고는 오버 라이딩으로 변경 가능)

 

인터페이스 정의하는 방법
  • 인터페이스는 Interface 키워드와 함께 정의합니다. 
  • 인터페이스에 정의되는 모든 멤버 변수는  public static final로 선언해야 하며 public static을 생략하면 자동으로 생성됩니다.

이제 이 인터페이스를 상속받는 클래스는 run(), stop() 함수 두 개는 무조건 오버 라이딩해야 합니다.

public interface Roots {
	void run();
	void stop();
}

 

 

인터페이스 구현하는 방법
  • implements 키워드를 사용해서 인터페이스를 상속받습니다.
  • 인터페이스에 정의된 함수는 모두 오버 라이딩합니다.

클래스를 상속할 때는 extends를 사용하지만 인터페이스는 implements로 상속받습니다. implements는 extends와 다르게 한 개 이상의 인터페이스를 상속받을 수 있습니다.

public class Root implements Roots{	

	@Override
	public void run() {
		// TODO Auto-generated method stub
	}
	
	@Override
	public void stop() {
		// TODO Auto-generated method stub
	}
}

 

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

인터페이스

public interface Animals {
	
	boolean Wings();
	boolean tail();
	int getLeg();
	String getname();
}

 

인터페이스를 상속하는 구현체

public class Dog implements Animals {
	
	@Override
	public int getLeg() { return 4; }
	@Override
	public String getname() { return "BBobbi"; }
	@Override
	public boolean tail() { return true; }
	@Override
	public boolean Wings() { return false; }
	
}


public class Cat implements Animals{
	
	@Override
	public int getLeg() { return 4; }
	@Override
	public String getname() { return "Nabi"; }
	@Override
	public boolean tail() { return true; }
	@Override
	public boolean Wings() { return false; }
}


public class Bird implements Animals{
	
	@Override
	public int getLeg() { return 2; }
	@Override
	public String getname() { return "jack"; }
	@Override
	public boolean tail() { return true; }
	@Override
	public boolean Wings() { return true; }
}

 

아래와 같은 방법으로 이미 인터페이스를 상속받은 클래스를 객체화 시켜 사용할 수 있습니다.

public class AnimalMain {
	
	void printlns(Animals animals) {
		System.out.println("-----------------");
		System.out.println(animals.getLeg());
		System.out.println(animals.getname());
		System.out.println(animals.tail());
		System.out.println(animals.Wings());
		System.out.println("-----------------");
	}
	
	public static void main(String[] args) {
		
		Cat cat = new Cat();
		Dog dog = new Dog();
		Bird bird = new Bird();
		
		new AnimalMain().printlns(cat);
		System.out.println();
		new AnimalMain().printlns(dog);
		System.out.println();
		new AnimalMain().printlns(bird);
		
	}
}

 

 

인터페이스 상속

자바는 다중 상속을 금지 한다고 공부해왔습니다. 하지만 특별한경우 즉, 인터페이스의 경우는 다중상속을 지원합니다. 

PC 클래스를 만든다고 가정했을 때 PC에는 RAM, CPU, GPU 등 다양한 클래스를 상속받아야 하기 때문에 여러 클래스를 상속받는 것이 편리합니다. 

CPU, GPU, RAM을 클래스로 정의하고 상속받는다면 다중 상속이 불가능하지만 인터페이스로 정의해서 사용하면 정해진 틀 안에서 개발할 수 있는 장점이 있습니다.

public interface Cpu {
	// inner method
}

public interface Gpu {
	// inner method
}

public interface Ram {
	// inner method
}


public class PC  implements Ram, Cpu, Gpu {
	// impliment method
}

 

 

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

Java 8이 등장하면서 많은 것이 바뀌었습니다. 람다식의 사용, Optional의 등장, default , static 메서드의 등장 등이 있는데

default 키워드의 등장으로 기존에 추상 메서드만 작성할 수 있었던 인터페이스에서 메소드 안에 구현체가 있는 default 메소드를 사용할 수 있게 되었습니다.

default 메소드가 등장하게 된 배경을 알면 얼마나 default 메소드가 얼마나 편리한 기능인지 알 수 있습니다. 

인터페이스 A를 상속받는 클래스가 100개가 있다고 가정해 보겠습니다. 그럼 이전 인터페이스 구조에서는 100개 클래스 모두 method A를 오버 라이딩해야 합니다

오버 라이딩이야 처음 클래스를 만들 때 강제적으로 해야 하고 인터페이스에는 구현체가 없어서 딱히 문제가 없을 수도 있습니다.

하지만 만약에 method A의 리턴 타입이 바뀌거나 method B, method C 라도 생기는 날에는 상속받은 100개의 클래스 모두 수정해야 하는 끔찍한 상황이 발생하게 됩니다. (업무로 몇 번 해보니 죽을 맛입니다.)

 

지속적인 불편함이 있었고 불편을 해소하는 방법으로 제시된 것이 default 메소드 입니다. 인터페이스 내부에 구현체를 구현함으로써 상속받은 클래스에 따로 오버 라이딩하지 않아도 필요할 때만 메소드를 불러다 쓸 수 있기 때문에 앞서 생긴 문제와 같은 경우 그냥 새로 default 메소드를 만들어 필요한 클래스에서만 사용하면 되니 전보다 수정 요소가 많이 감소하게 됩니다. 

public interface Root {
	void run();
	
	default void print() {
		System.out.println("default print");
	}
}




public class Childs implements Root{
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		
	}
	
	
	public static void main(String[] args) {
		Childs ch = new Childs(); // Root를 상속받고 있기 때문에 Childs 클래스에 찍어도 문제 없음
		ch.print(); // 오버라이딩 하지 않아도 사용 가능
	}
}

 

 

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

Java 8에서 default 메소드와 함께 추가된 또 다른 기능인 static 메소드 또한 앞서 설명한 불편한 점을 개선하기 위해 등장한 기능중 하나로 볼 수 있는데 default 메소드와 다른 점이 조금 있습니다.

  • 클래스 명으로 메소드를 호출해야 한다
  • public으로 선언된다 (명시하지 않으면 자동으로 할당)
  • 오버 라이딩 불가능

default 메소드의 경우는 오버 라이딩해서 재정의 할 수 있지만 static 메서드는 오버 라이딩을 할 수 없으며 만약 상속받은 클래스에서 같은 이름으로 만든다 해도 인터페이스 내부에 정의된 static 메소드와는 다른 메소드 입니다.

public interface Root {
	void run();
		
	static void staticPint() {
		System.out.println("static print");
	}
}



public class Childs implements Root{
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		
	}
	void staticPint(){
		System.out.println("Childs print");		
	}
	
	public static void main(String[] args) {
		Root.staticPint();
		new Childs().staticPint();
	}
}

 

 

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

Java 8에서 default, static 메소드가 추가 되었습니다. 그런데 Java 9에 새로운 메소드가 하나 더 추가 되었는데 그게 private 메소드 입니다. (그만,, 추가해..)

private 메소드 도 앞서 추가된 default, static 메소드와 비슷한 특징도 있고 반면 다른 특징도 있습니다.

  • 인터페이스 내부에 구현체를 정의할 수 있다
  • 함수 내부에 다른 함수를 call 할 수 있다
  • 상속받은 클래스에서는 private 메서소드를 실행하거나 상속할 수 없다
public interface Root {
	void run();
		
	static void staticPint() {
    	privatePint();  // private method는 다른 인터페이스 내부에 선언이 가능
		System.out.println("static print");
	}
    
    private void privatePint() {
    	System.out.println("private method");
    }
}



public class Childs implements Root{
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		
	}
	void staticPint(){
		System.out.println("Childs print");		
	}
	
	public static void main(String[] args) {
		Root.staticPint();
        Root.privatePint(); // 이 method는 에러발생, private method는 상속받은 클래스에서 사용 불가능
		new Childs().staticPint();
	}
}
728x90

댓글