Interface
✅ Interface
인간이나 사물, 시스템 간에 커뮤니케이션이 가능하도록 설계한 상호 작용 방식
1. 유저 인터페이스 UI
인간(유저)와 사물/시스템
유저가 편하게 사물/시스템과 통신할 수 있도록 도와주는 것
하드웨어 유저 인터페이스 인간 <—–> 자동차 핸들 <—–> 자동차
인간 <—–> 리모콘 <—–> 텔레비전소프트웨어 유저 인터페이스
GUI(graphic user interface)
application
2. 시스템 인터페이스 SI
시스템과 시스템이 상호작용
사물/시스템 <—-> 사물/시스템
- 하드웨어 시스템 인터페이스
케이블, USB
3. 소프트웨어 시스템 인터페이스
API(앱을 프로그래밍해서 통신하는 인터페이스)
JAVA의 인터페이스(자바의 객체끼리 통신하기 위한 인터페이스)
✅ JAVA OOP Interface: 소통
자바 객체의 공통된 행위만 보는 추상화
자바 객체간 소통이 가능하도록 기능 구현을 설계(메소드)하는 추상화 문법
인터페이스: 객체들이 이렇게 소통하자! 약속을 정의한 메소드
JPA repository would be an interface, defining methods.
⭐️ interface 특징
다중 적용 가능
- 하나의 클래스가 여러개의 interface implement가능
생성자 ❌
- interface는 사실 다 abstract임.
- 생성자 필요없음. (
new...
필요 없음
❌) - 즉, instance를 생성하지 않고도 실행 클래스에서 바로 불러오기 가능
interface 의 field는 public static final
- 필드 앞에 자동으로
public static final
이 붙는다. - 그래서 field를 정할 때 초기값을 무조건 정해줘야 한다.
그래서 implement한 class에서는 값을 바꿀 수 없다. Final이니까.
interface 의 메소드는
public abstract
- interface 에서는 그냥 메소드 이름만 쓰면 끝
method 구현 override 의무
- 메소드 구현 의무: implement하는 class는 무조건 override해 줘야 함.
- interface는 무조건 abstract이기 때문이다.
interface정의 방법
1
2
3
4
5
6
7
8
public interface Flyable {
//field
long atomsphereLimit= 476; //field 꼭 초기값 정해주어야 한다.
//method
//이름만 선언하면 끝임
//Flyable class를 implement한다면 꼭 override 해야 함.
void fly();
}
interface로도 instance type을 정의할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class Bird extends Animal implements Flyable {
private long weight;
private String color;
// 행위
@Override //abstract class extends Animal
public void eat(String food) {
System.out.printf("새가 %s 을 부리로 쪼아 먹고 있습니다.\n", food);
}
@Override //abstract class extends Animal
public void sleep() {
System.out.println("새가 잠을 자고 있습니다.");
}
@Override //interface implements Flyable
public void fly(){
System.out.println("새가 날고 있습니다.");
}
}
//실행 클래스에서는
//interface로도 인스턴스 타입을 정의할 수 있다.
//이제 인스턴스 타입 bird의 경우 세 가지나 할 수 있음!!
Flyable bird1= new Bird();
Bird bird2 = new Bird();
Animal bird3= new Bird();
interface로 타입 정의한 인스턴스는 원래 인스턴스 메소드 사용 ❌
interface로 타입 정의한 인스턴스는 그 인스턴스의 메소드는 더 이상 쓸 수 없고,
interface에서 정의한 메소드만 사용 가능
1
2
3
4
5
6
7
8
9
Flyable bird= new Bird();
Flyable airplane= new Airplane("AB007");
//interface method⭕️
bird.fly();
airplane.fly();
// 기존 instance에서 정의한 Method는 더 이상 사용 불가
//eat는 Bird class가 가지고 있는 method
//⭐️ 왜냐하면 bird를 flyable(instance type을 interface로 설정했기 떄문이다. )
bird.eat(); //❌
💡 근데 원래 인스턴스 메소드 쓰고 싶은데요ㅠㅠ ➡️ downcasting
1
2
3
4
if(bird instanceof Bird){
Bird birdDowncast= (Bird) bird;
birdDowncast.sleep();
}
abstract class 🆚 interface
공통점
- 둘 다 추상클래스(interface도 일종의 추상클래스)
- 메소드 구현 의무 Override
- 인스턴스화 될 수 없다.
차이점
abstract class
extends
🔴 물려받는 것(혈통/가문)
🟠 다중 적용 불가 ❌ 단일 상속만 가능 (부모는 하나 밖에 없다!)
🟡 상속 관계에 의한 제한 있음
🟢 생성자 가짐 ⭕️
🔵 메소드 구상, 추상 모두 가능
🟣 필드 모두 가능
추상 클래스는 일반 멤버 변수와 메소드까지 같이 받지만, interface는 메소드만 받음
작업의 레벨 분할을 위해 사용
공통 메소드가 있는 경우 추상 클래스가 더 적합
interface
implements
🔴 장착하는 기능
🟠 다중 상속 가능 ⭕️(상속 여러개 할 수 있다는 뜻)
🟡 상속 관계에 의한 제한 없음
🟢 생성자 없음 ❌
🔵 모든 메소드가 추상 메소드 또는 default붙인 구상 메소드, 클래스 메소드
🟣 추상메소드와 상수만 사용(final
이 붙은 애들)
하지만 명시할 필요는 없음 어짜피 상수로 정의되니까
✅ Interface default method
☑️ default: abstract 벗어나기
interface도 기본적으로 abstract이기 때문에,
default를 사용해서 abstract의 기본적인 제약을 벗어날 수 있음.
❓ 왜 굳이 default해서 abstract 벗어나야 하는거야?
만약 사용되던 interface를 implements하는 newClass가 추가되었는데,
이 newClass는 새로운 기능을 추가해야 함.
그러면 기존 class들은 이 새로운 기능을 또 다~~ Override해서 정의해주어야 함?? 너무 번거로움…
(추상 메소드는 override안하면 실행 안 되니까)
그래서 default해서 abstract 벗어나면, newClass에서 새로운 기능 구현 가능!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//식약청 interface
public interface FoodSafety {
//🔴 static
// announcement ()는 static ➡️ FoodSafety 의 메소드
//인스턴스 선언하지 않아도 FoodSafety 하고 바로 실행 가능
static void announcement () {
System.out.println("식품안전 관련 공지");
}
//🟡 default 는 구상 메소드
// 인스턴스에서 따로 정의하지 않았더라도
//인스턴스에서 바로 사용 가능
default void regularInspection () {
System.out.println("정기 체크");
}
//🟢 추상 메소드
//인스턴스에서 반드시 정의해주고(Override) 사용해야 함.
void cleanKitchen ();
void employeeEducation ();
}
//인스턴스 클래스
public class YalcoChicken implements FoodSafety {
//🟢 추상 메소드 정의해주기(Override)
@Override
public void cleanKitchen() {
System.out.println("매일 주방 청소");
}
@Override
public void employeeEducation() {
System.out.println("직원 위생 교육");
}
}
//실행클래스
//🔴 인스턴스 선언하지 않아도 FoodSafety 하고 바로 실행 가능
FoodSafety.announcement();
YalcoChicken store1 = new YalcoChicken();
//🟡 default
//인스턴스에서 따로 정의 안했는데도 사용 가능
store1.regularInspection();
//🟢 추상 메소드
//인스턴스에서 정의 했음.
store1.cleanKitchen();
store1.employeeEducation();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public interface Flyable {
//field
long atomsphereLimit= 476; //💡field 꼭 초기값 정해주어야 한다.
//method에 default, static붙여 abstract 벗어남
//더 이상 abstract가 아니므로 메소드 정의해 주어야 한다.
default void fly(){
System.out.println("Now flying");
}
static void landing(){
System.out.println("Now landing");
}
}
//drone 클라스, implement하는 클라스
public class Drone implements Flyable{ //여러개 interface implement 가능
public void takePic(){
Flyable.landing();
System.out.println("This drone is taking a picture");
}
}
//실행글래스
public class InterfaceTest2 {
public static void main(String[] args) {
//⭐️ 다형성
//instance type으로 instance 선언 가능
//🟢 default이기 때문에 인스턴스에서 정의 안했지만 사용 가능
Flyable drone = new Drone();
drone.fly();
//downcast
if(drone instanceof Drone){
Drone droneDowncast= (Drone) drone;
droneDowncast.takePic();
}
}
}
✅ Interface: 역할 여러개
한 객체가 여러 역할을 수행
그래서 기존 JAVA의 class, abstract class 모두 상속은 1개씩만 가능했지만,
implement는 여러 개 가능!
왜냐하면 한 class가 여러 역할을 수행하니까.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Family {
public static void main(String[] args) {
//male role: employee, dad, husband 🤵🏻♂️👨👧👨🏻⚖️
//husband method
Husband maleHusband= new Male("Galan"); //🤵🏻♂️
Wife femaleWife= new Female("Park");
maleHusband.takeCareWife(femaleWife);
maleHusband.sayLove();
//dad method
//husband이 downcast
Dad maleDad= (Dad) maleHusband ; //🤵🏻♂️ -> 👨👧
Baby baby= new Baby("Haru");
maleDad.educateBaby(baby);
maleDad.sayLove();
//employee method
//dad이 downcast
Employee maleEmployee= (Employee) maleDad; //👨👧 -> 👨🏻⚖️
Employee coworker= new Male("boss");
maleEmployee.workTogether(coworker);
}
}
두 interface 간 default 메소드가 중복된다면? ➡️ 무조건 Override
Override해서 메소드 재정의해야 한다. interface.super.method
로 override
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//현재 husband, dad interface에서 같은 이름으로 default메소드가 정의된 상황
public interface Husband {
default void sayLove(){
System.out.println("I love my wife");
}
}
public interface Dad {
default void sayLove(){
System.out.println("I love my baby");
}
}
//impelemt하는 class
//super을 사용해 override한 method 재정의
public class Male implements Husband, Employee, Dad{
@Override
public void sayLove() {
Husband.super.sayLove();
Dad.super.sayLove();
}
}
혹은 이름이 겹치는 두 method를 다른 interface로 빼내서 만드는 것도 가능
1
2
3
4
5
6
7
8
9
10
public interface HusbandAndDad extends Dad, Husband {
@Override
default void sayLove() {
Dad.super.sayLove();
Husband.super.sayLove();
}
}
//HusbandAndDad는 Dad, Husband에서 sayLove()함수 받아옴.
//이렇게만 해도 함수 실행됨.
interface 도 상속이 가능하다. 심지어 여러개 가능
만약 비슷한 사람이 하나 더 있다면? 두 사람이 비슷한 성질을 공유함
비슷한 성질들은 그냥 선언만 해두고 불러 쓰고 싶음. ➡️ 추상 클래스를 선언한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//Dad, Husband를 합쳐서 FamilyMan이라는 class를 만들어 공통되는 속성을 넣음
public abstract class FamilyMan implements HusbandAndDad{
@Override
public void educateBaby(Baby baby) {
String name= baby.getName();
System.out.printf("Educate baby %s.\n", name);
}
@Override
public void takeCareWife(Wife wife) {
String wifeName= wife.getName();
System.out.printf("Take care of wife %s.\n", wifeName);
}
}
//이제는 새로운 남자가 나타나도 FamilyMan상속만 받으면 됨
public class MaleNew extends FamilyMan implements HusbandAndDad, Employee{
@Override
public void workTogether(Employee employee) {
String employeeName= employee.getName();
System.out.printf("Working with %s.\n", employeeName);
}
@Override
public String getName() {
return this.name;
}
}