📔 본 포스팅은 자바의 정석(남궁성 저, 3판)을 읽고 정리한 글입니다.
public
)interface 인터페이스이름 { // 모든 멤버가 public
public static final 타입 상수이름 = 값; // 상수는 가질 수 있으나 변수(iv, cv)는 가질 수 없음
public abstract 메서드이름(매개변수 목록); // 추상 메서드
}
interface PlayingCard {
public static final int SPADE = 4;
final int DIAMOND = 3; // public static final int DIAMOND = 3;
static int HEART = 2; // public static fianl int HEART = 2;
int CLOVER = 1; // public static final int CLOVER = 1;
public abstract String getCardNumber();
String getCardKind(); // public abstract String getCardKind();
}
public
임 (생략 가능)public
, final
, static
은 생략 가능.public
, abstract
은 생략 가능.interface Movable {
/** 지정된 위치(x, y)로 이동하는 기능의 메서드*/
void move(int x, int y); // public abstract 생략
}
interface Attackable {
/** 지정된 대상(u)을 공격하는 기능의 메서드 */
void attack(Unit u);
}
interface Fightable extends Movable, Attackable {} // 멤버 2개
class 클래스이름 implements 인터페이스이름 {
// 인터페이스에 정의된 추상메서드를 모두 구현
}
interface Fightable {
void move(int x, int y); // public abstract
void attack(Unit u);
}
class Fighter implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
public void attack(Unit u) { /* 내용 생략 */ }
}
abstract
를 붙여 추상 클래스로 선언한다.abstract class Fighter implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
// 멤버로 'public abstract vboid attack(Unit u);' 를 가짐
}
class Fighter extends Unit implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
public void attack(Unit u) { /* 내용 생략 */ }
}
Unit u = new Fighter(); // OK
Fightable f = new Fighter(); // OK
interface Fightable {
void move(int x, int y);
void attack(Fightable f); // Fightable인터페이스 구현한 놈들만 와라
}
Fightable method() { // 리턴 타입이 Fightable인터페이스 = Fightable 인터페이스를 구현한 클래스의 인스턴스를 반환
...
Fighter f = new fighter(); // 아래 문장을 포함하여 'return new Fighter'로 사용 가능
// 반환 타입이 Fightable이어야하지만, f는 Fightable로 형변환이 가능하기 때문에 이렇게 사용 가능함
return f; // '(Fightable)' 생략됨(자동 형변환)
}
...
class Fighter implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
public void attack(Unit u) { /* 내용 생략 */ }
}
/* 인터페이스 타입의 매개변수, 인터페이스 리턴타입의 메서드 사용 예제 */
abstract class Unit2 {
int x, y;
abstract void move(int x, int y);
void stop() {
System.out.println("멈춥니다");
}
}
interface Fightable {
void move(int x, int y); // public abstract 생략됨
// 인터페이스 타입 매개변수 사용
void attack(Fightable f); // public abstract 생략됨
}
class Fighter extends Unit2 implements Fightable {
// 오버라이딩 규칙 : 조상(public)보다 접근제어자가 범위가 좁으면 안된다.
public void move(int x, int y) {
System.out.println("[" + x + "," + y + "]로 이동");
}
public void attack(Fightable f) {
System.out.println(f + "를 공격");
}
// 싸울 수 있는 상대를 불러온다.
Fightable getFightable() {
Fighter f = new Fighter(); // Fighter를 생성해서 반환, '(Fightable)' 생략됨
return f;
}
}
public class FighterTest {
public static void main(String[] args) {
Fighter f = new Fighter();
// getFightable()의 리턴타입이 Fightable인터페이스 이기 때문에, 이를 저장하는 참조변수의 타입 또한 Fightable타입
Fightable f2 = f.getFightable();
}
}
void Repair(Tank t) {
// Tank를 수리한다
}
void Repair(Dropship d) { // 오버로딩
// Dropship을 수리한다
}
// 과도한 오버로딩을 방지하기위해 조상 클래스 타입 매개변수를 이용
void Repair(GroundUnit gu) {
// 매개변수로 넘겨진 GroundUnit을 수리한다
}
interface Repairable {}
class SCV extends GroundUnit implements Repairable { }
class Tank extends GroundUnit implements Repairable { }
class Dropship extends AirUnit implements Repairable { }
// 실제 메서드 구현시
void Repariable(Repairable r) { // Repairable인터페이스를 구현한 클래스의 객체만 매개변수로 가능
if (r instanceof Unit) {
Unit u = (Unit) r;
while (u.hitPoint != u.Max_HP) {
u.hitPoint++;
}
}
} // repair(Repairable r)
// 껍데기와 알맹이가 같이 있는 클래스
class B { // 껍데기 + 알맹이. 유연하지 않음 & 변경에 불리
public void method() {
System.out.println("method in B");
}
}
// 껍데기와 알맹이로 분리, 유연함 & 변경에 유리
Interface I { // 껍데기
public void method();
}
class B implements I{ // 알맹이 (B클래스)
public void mehtod() {
System.out.println("method in B");
}
}
// 직접적인 관계의 두 클래스 (A-B)
class A {
public void mehtodA(B b) {
b.methodB();
}
}
class B {
public void mehtodB() {
System.out.println("methodB()");
}
}
class InterfaceTest {
public static void main(String[] args) {
A a = new A();
a.methodA(new B());
}
}
/* 인터페이스의 느슨한 결합 예제 */
class A {
// public void methodA(B b){ // 강한 결합, A클래스와 B클래스가 직접 관계 있음
public void methodA(I i){ // 인터페이스 I를 구현한 넘들의 인스턴스만 들어와라
i.methodB();
}
}
interface I {
void methodB();
}
class B implements I{
public void methodB() {
System.out.println("methodB in B class");
}
}
class C implements I{ // C클래스를 추가해도 A클래스는 변경하지 않아도 됨
public void methodB() {
System.out.println("methodB in C class");
}
}
public class interfaceTest {
public static void main(String[] args) {
A a = new A();
a.methodA(new B()); // "methodB in B class"
a.methodA(new C()); // "methodB in C class"
}
}
interface MyInterface {
void method();
default void newMethod() {} // 디폴트 메서드는 몸통이 있음
}
사실, 충돌 생기면 그냥 고민하지 말고 직접 오버라이딩해서 해결하는 게 낫다