인터페이스(interface)

배지원·2022년 9월 28일
0

JAVA

목록 보기
18/32

1. 인터페이스

  • 자바 특성상 다중 상속이 불가능한데 다중 상속의 이점을 버릴 수는 없기에 인터페이스를 통해 다중 상속을 할 수 있다.
  • 추상 메서드만의 집합
  • 구현된 것이 전혀 없는 설계도(모든 멤버가 public)
  • 추상화 클래스와 달리 인스턴스 변수를 가질수 없음
interface 클래스이름{
	public static final 타입 상수이름 =;	
    // interface안에 있는 변수는 모두 상수이므로 (public static final)생략 가능
    // static int ex = 1;
    // final int ex2 = 2;
    // int ex3 = 3;
    public abstract 메서드이름(매개변수목록);
}

2. 인터페이스의 상속

  • 인터페이스의 조상은 인터페이스만 가능(Object가 최고 조상 아님)
  • 다중 상속 가능(추상메서드는 충돌해도 문제가 없음)
    어차피 서로 다른 클래스의 같은 메서드를 상속받아도 안에 내용이 없기때문에 충돌이 나지 않음
interface Movable{
	void move(int x, int y);
}

interface Attackable{
	void move(int x, int y);
}

interface Fightable extends Movable, Attackable{}	// 다중 상속

3. 인터페이스의 구현(inplements)

  • 인터페이스에 정의된 추상 메서드를 완성하는 것
  • implements를 사용한 클래스는 인터페이스 클래스를 완성시키는 클래스임
  • 추상메서드2개를 가진 인터페이스를 implement를 통해 완성시키는데 만약 1개만 완성시킬경우 1개는 아직 미완성 이므로 abstract을 붙여줘야함
class test implements test2{
		public void move(int x, int y){
        		추상클래스에서 받은 메서드 완성시킴
        }
}

---------  추상메서드 2개를 인터페이스하여 1개의 메서드만 완성 시킬경우 ---------
abstract class Fighter implements Fightable{	
// 1개는 미완성 이므로 abstract 사용
		public void move(int x, int y){ }
        (public abstract void attack(){})	// 생략 가능
}

4. 인터페이스를 이용한 다형성

  • 인터페이스 타입 매개변수는 인터페이스 구현한 클래스의 객체만 가능
class Fighter extends Unit implements Fightable{
		public void move(int x, int y){	}
        public void attack(Fightable f){ }	
        // Fightable인터페이스를 구현한 클래스의 인스턴스만 가능 
        // (Unit 상속을 받은 클래스는 불가능)
         
}	
// 다중 상속
Unit u = new Fighter();			// 부모 클래스 다형성
Fightable f = new Fighter();	// 인터페이스 클래스 다형성
// 

실습

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 붙여줘야 함)
    public void move(int x, int y){
        System.out.println("["+x+","+y+"]로 이동");
    }
    public void attack(Fightable f){
        System.out.println(f+"를 공격");
    }

    Fightable getFightable(){				
    // Fightable 인터페이스를 구현한 객체만 올수 있다.
        Fighter f = new Fighter();
        return  (Fightable)f;
    }
}

public class interfaceTest {
    public static void main(String[] args) {
        Fighter f = new Fighter();
        Fightable f3 = f.getFightable();

        // -------- Fightable 다형성 (interface)       Unit2 클래스에 있는 stop()메서드 사용 불가
        Fightable f2 = new Fighter();
        f2.move(100,200);
        f2.attack(new Fighter());       // Fighter f2 = new Fighter();
                                       // f.attack(f2);

        // --------- Unit 다형성 (상속)              Fightable 클래스에 있는 attack()메서드 사용 불가
        Unit2 u = new Fighter();
        u.move(10,20);
        u.stop();
    }
}

5. 인터페이스 장점(1)

  • 두 대상 간의 '연결, 대화, 소통'을 돕는 '중간 역할'을 한다.
  • 선언(메서드 선언부)과 구현(메서드 안 내용)을 분리시킬 수 있게 한다.
  • 변경에 유리, 코드가 유연함
class B{									interface I{
	public void method(){ ... }     =>     		public void method();
}											}

실습

class A{
    public void method(I i){            // 인터페이스 객체를 받음
        i.method();
    }
}

interface I{            // 인터페이스로 method를 따로 뺌
    void method();      
}

class B implements I{
    public void method(){
        System.out.println("B클래스의 메서드");
    }
}

class C implements I{
    public void method(){
        System.out.println("C클래스의 메서드");
    }
}

public class interfaceTest2 {
    public static void main(String[] args) {
        A a = new A();
        a.method(new B());
        a.method(new C());
    }
}
---------------------------- 설명 --------------------------
- 공통 메서드를 인터페이스를 통해 따로 빼냄
- B,C클래스에서 자신에 맞게끔 오버라이딩 함
- A클래스에서는 상황에 맞는 객체를 불러오게 하기 위해 인터페이스 객체를 받음
- 메인 메서드에서 필요한 객체를 a.method(객체); 넣어 필요한 값을 출력함 (new B()new C()의 값은 다름)

※ 만약 인터페이스를 사용하지 않으면 A클래스에서 B의 값과 C의 값을 출력할때 각각 작성해줘야함

5. 인터페이스 장점(2)

  • 개발 시간을 단축할 수 있다.
  • 표준화 가능(JDBC - 인터페이스 집합 / JDBC를 토대로 개발을 함)
    즉, 규칙처럼 한번 만들어 놓으면 계속 가져다 사용이 가능함
  • 서로 관계없는 클래스들을 관계를 맺어줄 수 있다.
interface Repairable{}		// 관계없는 클래스들을 묶어주기 위한 공통점 인터페이스

class GroundUnit extends Unit{ }
class AirUnit extends Unit{ }

class SCV extends GroundUnit implements Repairable{ ... }
// GrountUnit을 상속받은 클래스
class Tank extends GroundUnit implements Repairable{ ... }
// GrountUnit을 상속받은 클래스
class Dropship extends AirUnit implements Repairable{ ... }
// AirUnit을 상속받은 클래스

void repair(Repairable r){		
// Repairable 인터페이스를 사용하는 객체만 입력가능
		if(r instanceof Unit){	
// Repairable 인터페이스를 사용한 객체중 Unit을 상속 받았는지 확인
        	Unit u = (Unit) r;		// r안의 값을 사용하기 위해 다형성
            while(u.hitPoint != u.MAX_HP){	
            		u.hitpoint++;
            }
        }
}
---------------------------- 설명 --------------------------
- SCV,Tank,Dropship의 부모클래스의 부모클래스는 Unit으로 관계가 있지만 실질적으로 
SCV,TankDropship은 서로 다른 클래스를 상속받아 관계가 없는 클래스다 하지만,
Repairable이란 인터페이스를 공통으로 받게 되면 관계를 맺어줄 수 있다.

- 공통 메서드인 repair(Repairable r)을 만들어 Repairable 인터페이스를 사용하는
객체만이 접근할 수 있도록 하고 그 중에서 Unit을 상속받아 다형성이 가능한지 확인한다

- 다형성이 가능하다면 SCV, Tank, Dropship 메서드안의 값을 사용하기 위해
최상위 클래스를 다형성 시켜 값을 불러올 수 있도록 한다.

6. 디폴트/static 메서드

  • 인터페이스에 디폴트 메서드, static 메서드 추가 가능(JDK 1.8부터)
  • 인터페이스에 새로운 메서드(추상 메서드)를 추가하기 어려움
    해결책 => 디폴트 메서드
  • 디폴트 메서드는 인스턴스 메서드(인터페이스 원칙 위반)
interface MyInterface{					interface MyInterface{
	void method();				=>  		void method();
    void newMeethod();				 		default void newMethod(){...}
}										}
  • 위처럼 인터페이스 안 메소드에 default를 붙여주게 되면 값을 넣을 수 있는 인스턴스 메서드를 생성 가능함(필요도 없는 메서드 까지 가져갈 필요 없게 하기 위해)
  • 하지만 default로 메서드를 생성시 implement과정에서 충돌 오류 발생
    (1) 여러 인터페이스의 디폴트 메서드 간의 충돌
    => 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩 한다.
    (2) 디폴트 메서드와 조상 클래스의 메서드 간의 충돌
    => 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.

7. 의존성 및 다형성을 통한 예제

(1) Calculator.class

public class Calculator {

    NumberGenerator numberGenerator;

		//생성자
    public Calculator(NumberGenerator numberGenerator) {
        this.numberGenerator = numberGenerator;
    }
		
		//더하여 출력
    public void plus(){
        System.out.println(10+ numberGenerator.generate(10));
    }
}

(2) RandomNumberGenerator.class

public class RandomNumberGenerator implements NumberGenerator{

		//NumberGenerator 인터페이스의 메소드 오버라이드
    @Override
    public int generate(int num) {
        num = (int)(Math.random()*10);
        return num;
    }
}

(3) SpecificNumberGenerator.class

public class SpecificNumberGenerator implements NumberGenerator{

		//NumberGenerator 인터페이스의 메소드 오버라이드
    @Override
    public int generate(int num) {
        return 2000 * num;
    }
}

(4) NumberGenerator.interface

public interface NumberGenerator {
		//인터페이스: 메소드 내용이없는 껍데기
		//선언만 해줌
    int generate(int num);

}

(5) Main.class

public class Main {
    public static void main(String[] args) {

				//1.
        NumberGenerator randomNumberGenerator = new RandomNumberGenerator();
        Calculator randomNumberCalculator = new Calculator(randomNumberGenerator);
        randomNumberCalculator.plus();

				//2.
        Calculator specificNumberCalculator = new Calculator(new SpecificNumberGenerator());
        specificNumberCalculator.plus();

    }
}
profile
Web Developer

0개의 댓글