[Java] 인터페이스(interface)

2022. 10. 5. 15:04Dev.Program/Java & Spring

728x90

p.276

======== JAVA0318 - Ex.java 만들기

p.276

< 인터페이스(interface) >

  • 클래스가 아니므로 선언 시 class 키워드 대신 interface 키워드 사용
  • 인터페이스는 추상메서드, 상수만 가질 수 있다.
  • ⇒ 모든 메서드는 public abstract 가 붙은 추상메서드로 취급됨(생략 가능)
  • ⇒ 모든 멤버변수는 public static final 이 붙인 상수로 취급됨(생략 가능)
  • 추상클래스와 마찬가지로 객체 생성이 불가능
  • ⇒ 단, 참조변수 타입으로는 사용 가능 = 다형성 활용(업캐스팅) 가능
  • 추상메서드 구현을 강제하여, 코드의 통일성이 향상됨
  • 클래스에서 인터페이스를 상속받아 구현해야할 경우 implements 키워드 사용
  • 인터페이스끼리 상속받을 경우 extends 키워드 사용



======== 동물.java → Interface로 만들어보기

  • class 파일 만드는 것보다 간단하다!

 

  • abstract 가 없어도 추상메서드로 취급하기 때문에 {} 를 넣으면 오류남!

  • public도 생략가능!
  • 모두 abstract기 때문에 abstract를 안적어도 전부 추상메서드이다.
  • public abstract 생략가능

  • 최종 : class 파일이랑 다르게 main() 메서드도 없고 코드가 엄청 간단하다

 

<Ex.java>

  • 방금 만든 interface 상속 받음!

  • 오류!
  • 오류창 확인 : 고래의 메서드도 추상메서드라 구현부(body)를 가질 수 없다.
  • public void 번식(); 으로 적는 건 가능!

  • 오류! extends 를 사용했기 때문!
  • 클래스에서 인터페이스를 상속받아 구현해야할 경우 implements 키워드 사용

  • im 까지만 쓰고 Ctrl + space(자동완성) 누르면 자동으로 완성됨!

  • Ctrl + space 눌러보면 내가 상속(구현)받을 수 있는 인터페이스들이 보임.

  • 인터페이스는 다중 상속이 가능하다!

  • 근데 오류가 뜸! 왜?

  • 오류창 확인 : 상속받은 추상메서드를 구현하지 않았기 때문

  • 인터페이스를 상속(구현)할 때, 2개 이상의 부모로부터 상속(구현)이 가능하다.
  • ⇒ 즉, 인터페이스는 다중 구현을 지원함

 

p.278-279 인터페이스

<Ex.java>

  • 인터페이스 내의 메서드는 전부 추상메서드
  • public abstract 가 생략된 추상메서드기 때문에 바디{}를 가질 수 없음(오류!)

  • 인터페이스도 객체 생성이 불가하다.

 

  • extends 키워드를 사용하면 상속 받을 MyInterface가 안보임.

  • implements 키워드로 상속(구현) 받음! - MyInterface 보임.

  • 서브클래스에서 구현한 메서드 앞에 public을 지울 경우 오류

  • public 보다 좁은 protected를 적어도 오류! 
  • 부모의 메서드 접근제한자보다 좁을 수 없으므로(같거나 넓어야함) 반드시 public 사용

  • public 을 사용하면 오류 다 사라짐.

 

Flyer 인터페이스 정의

⇒ 이륙(takeoff()), 비행(fly()), 착륙(land()) 메서드 정의 = 추상메서드

 

 SuperMan 클래스 정의 ⇒ Flyer 인터페이스를 상속받아 구현

⇒ 각 메서드 구현하여 "SuperMan 이륙", "SuperMan 비행", "SuperMan 착륙" 출력

 

Airplane 클래스 정의 ⇒ Flyer 인터페이스를 상속받아 구현

⇒ 각 메서드 구현하여 "Airplane 이륙", "Airplane 비행", "Airplane 착륙" 출력

 

# tip.  interface MyInterface {} 내의 상수 (앞에서 놓친 부분!)

  • 상수는 원래 대문자로 쓰기로 함(약속)
  • 좀 더 좋은 코드를 가지기 위해선 num1, num2 대문자로 바꿔주는 게 좋다!

 

<Ex.java → main()메서드 부분>

  • 인스턴스 생성

  • 인터페이스의 인스턴스 생성은 불가능

  • 하지만, 참조변수 타입으로 다형성 활용 가능
  • 출력창



======== Ex2.java 만들기

<Ex2.java>

  • IHello, IGoodbye 인터페이스를 상속받는 ITotal 인터페이스 정의
  • ⇒ 인터페이스 끼리는 다중 상속이 가능하며, extends 키워드를 사용하여 상속

  • Alt + Shift + S + V 눌러보면 구현해야 할 메서드가 총 3개 (체크된 부분 확인 가능)
  • 필수로 구현해야하기 때문에 전부 체크 되어있음

  • 필수로 구현해야할 추상메서드 3개 구현

  • 이렇게 추상메서드 하나라도 구현하지 않으면 오류!
  • 추상 메서드를 구현하지 않아도 오류를 없애는 방법은??

  • ⇒ abstract(추상) 클래스로 정의하면 추상메서드를 구현하지 않아도 오류가 사라짐!
  • (대신 이 클래스도 인스턴스 생성은 못함 자식클래스 중 누군가는 상속 받아서 추상메서드를 구현해줘야 인스턴스 생성 후 사용 가능)

 

======== Ex3.java 만들기

<Ex3.java>

  • 이들의 공통 부모는 Object

  • 나쁜 예 (코드가 길어짐)

 

> 서로 상속 관계가 없는 클래스들 간에 인터페이스를 통한 상속관계를 부여하면 다형성을 확장하여 사용할 수 있게 된다.

  • 공통 부모인 interface를 만듦
  • 공통의 충전 기능에 대한 추상메서드 정의

  • 기존 클래스를 상속받은 상태에서 추가적인 상속을 위해 인터페이스를 활용할 수 있다!

  • 인스턴스 생성 후 charge() 메서드를 부를 때 코드가 훨씬 간단해짐.
  • Chargeable 인터페이스에 공통 추상메서드 charge() 가 존재하므로 별도의 다운캐스팅 없이 바로 charge() 메서드 호출이 가능하다!
  • 좋은 예 (코드가 훨씬 간단)

 

> 향상 for문(확장 for문) 안 배워서 위 코드 중 for문만 우리가 배운대로 바꿈

for(int i = 0; i < objs2.length; i++) {
    Chargeable c = objs2[i];
    c.charge();
}

 

~p.292 [p.293 2.6은 나중에 배움]

======== Ex4.java 만들기

<Ex4.java>

  • 체력만 생성자 만들기(Alt + Shift + S + O 생성자 단축키)
  • (final 부분 최대체력이 오류 난 이유는 상수인데 초기화를 안시켜놨기 때문)

  • 최대체력(final 상수)도 여기서 같이 초기화시켜줌 → final 부분 오류 사라짐

# tip. 인터페이스를 만들 땐 ~able(~할수있는)으로 만든다.

  • 지금은 한글로 적는다고 interface 공격가능{} 이라 했지만 보통은 interface Movable{} 이런 식으로 인터페이스 명에 ~able을 사용

 

  • 병사에 오류 뜸 : 오류 뜨는 2가지 이유
  • 우선 첫 번째로, 유닛 클래스의 이 부분 때문에 오류가 난다 !
  • final 상수인 최대체력을 초기화하기 위한 생성자 정의

  • 오류창 확인 : final 상수인 최대체력을 초기화하기 위한 생성자를 정의해야함

  • 그냥 바로 super() 안에 초기화 시켜줌!

  • 두 번째는, 상속받은 추상메서드를 정의하지 않았기 때문! (오류창 확인)

  • 오류나는 두 가지 이유를 전부 고친 뒤에는 오류가 사라진다.

 

> 병사(Marine) 클래스 정의 - 유닛, 공격가능, 이동가능

class 병사 extends 유닛 implements 공격가능, 이동가능 {

	public 병사() { // final 상수인 체력을 초기화하기 위한 생성자 정의
		super(50); // 유닛 클래스의 생성자를 호출하여 체력 전달
		공격력 = 5;
	}

	@Override
	public void 이동(int x, int y) {
		System.out.println("걸어서 x, y 좌표로 무브!");
	}

	@Override
	public void 공격(유닛 u) {
		System.out.println("총으로 " + u + "를 공격!");
		u.체력 -= 공격력; // 공격력만큼 체력 감소
	}
	
	public String toString() {
		return "병사";
	} ⇒ 이부분은 아직 뭔지 모름! (선생님 따라 코드 침)
}

 

 

> 탱크 클래스 정의 - 유닛, 공격가능, 이동가능

class 탱크 extends 유닛 implements 공격가능, 이동가능 {

	public 탱크() { // final 상수인 체력을 초기화하기 위한 생성자 정의
		super(150); // 유닛 클래스의 생성자를 호출하여 체력 전달
		공격력 = 30;
	}

	@Override
	public void 이동(int x, int y) {
		System.out.println("바퀴를 사용하여 x, y 좌표로 무브!");
	}

	@Override
	public void 공격(유닛 u) {
		System.out.println("대포로 " + u + "를 공격!");
		u.체력 -= 공격력; // 공격력만큼 체력 감소
	}
	
	public String toString() {
		return "탱크";
	}
}​

 

> 기계일꾼(SCV) 클래스 정의 - 유닛, 공격가능, 이동가능

class 기계일꾼 extends 유닛 implements 공격가능, 이동가능 {

	public 기계일꾼() { // final 상수인 체력을 초기화하기 위한 생성자 정의
		super(60); // 유닛 클래스의 생성자를 호출하여 체력 전달
		공격력 = 2;
	}

	@Override
	public void 이동(int x, int y) {
		System.out.println("걸어서 x, y 좌표로 무브!");
	}

	@Override
	public void 공격(유닛 u) {
		System.out.println("용접기로 " + u + "를 공격!");
		u.체력 -= 공격력; // 공격력만큼 체력 감소
	}
	
	public String toString() {
		return "기계일꾼";
	}
	
	// 기계 유닛을 수리하는 수리() 메서드 정의
	public void 수리(유닛 u) { // 공통항목으로 유닛타입 객체를 전달받음
		// 대상 유닛의 체력이 최대체력이 될 때까지 체력을 1씩 증가시킴(수리)
		while(u.체력 < u.최대체력) {
			u.체력++;
			System.out.println("수리 중... [" + u.체력 
							+ "/" + u.최대체력 + "]");
		}
		System.out.println(u + "의 수리가 끝났습니다!");
	}
}​

 

<Ex4.java → main() 메서드>

  • 출력창

 

> 체력이 깎였으니 이제 수리에 들어가보자!

  • 출력창

 

> 근데 문제가 되는점! 기계일꾼이 사람인 병사도 수리(?)해버림

→ 기계일꾼은 기계인 탱크만 수리 가능, 병사는 수리가 아니라 치료를 해야됨

  • 출력창

⇒ 이렇게 되면 안된다! 유닛 u.** 으로 받아오기 때문에 병사도 구분없이 수리함.

 

< 인터페이스 활용법 >

  • 수리가 가능한 유닛들을 별도로 구분하기 위한 인터페이스 활용법
    • ⇒ 아무 코드도 기술되지 않은 빈 인터페이스를 정의하고 해당클래스에 인터페이스를 구현하도록 하면 마카(Marker) 용도로 활용 가능
    • ⇒ 추상메서드가 하나도 없으므로 구현의 강제성이 없이 표시 용도로만 사용

> 해결 방법

  • 이렇게 빈 인터페이스 하나 추가!

  • 기계 일꾼에서 받아오는 것도 수리가능 타입으로 받아옴

  • 전부 수리가능 타입으로 수정해 줌!
class 병사 extends 유닛 implements 공격가능, 이동가능 {}

class 탱크 extends 유닛 implements 공격가능, 이동가능, 수리가능 {}

class 기계일꾼 extends 유닛 implements 공격가능, 이동가능, 수리가능 {}

 

⇒  이렇게 만들어 준 수리가능 인터페이스를 탱크와 기계일꾼에게만 적용하면 병사는 더 이상 기계일꾼이 수리하지 못함!

> 이렇게 바꾸면 main() {} 에서

  • 오류남 ( 병사는 더이상 수리하지 못하기 때문)

 

> 병사를 치료해 줄 치료가능 인터페이스를 만들어 줌.

interface 치료가능 {}

// 간호장교 클래스 정의 - 유닛, 공격가능, 이동가능
class 간호장교 extends 유닛 implements 이동가능, 치료가능 {

	public 간호장교() { // final 상수인 체력을 초기화하기 위한 생성자 정의
		super(60); // 유닛 클래스의 생성자를 호출하여 체력 전달
		공격력 = 2;
	}

	@Override
	public void 이동(int x, int y) {
		System.out.println("걸어서 x, y 좌표로 무브!");
	}

	public String toString() {
		return "간호장교";
	}
	
	// 생체 유닛을 치료하는 치료() 메서드 정의
	public void 치료(치료가능 치료유닛) {
		if(치료유닛 instanceof 유닛) { // 치료유닛은 유닛타입입니까?
			유닛 u = (유닛)치료유닛;
			while(u.체력 < u.최대체력) {
				u.체력++;
				System.out.println("수리 중... [" + u.체력 
							+ "/" + u.최대체력 + "]");
			}
			System.out.println(u + "의 치료가 끝났습니다!");
		}
	}
}​
class 병사 extends 유닛 implements 공격가능, 이동가능, 치료가능 {}

 
  • 병사 클래스에 치료가능 인터페이스도 적용

 

<Ex4.java → main() 메서드>

  • 탱크는 수리하고, 병사는 치료한다!
  • 출력창

⇒ 이런 식으로 인터페이스를 활용하여 구분할 수 있다!



728x90