다잘하고싶어

자바 인터페이스 본문

이론학습/JAVA

자바 인터페이스

챙영잉 2023. 2. 6. 14:40

추상클래스는 다중상속이 가능할까?

⇒ 가능하지 않다. 추상클래스도 클래스이므로

⇒ 다중상속을 하기 위해서는? 인터페이스를 이용하기

인터페이스

인터페이스에는 추상메서드만 존재한다 = 다중상속이 가능함.

interface = a point where two systems meet and interact

→ 만나는 것 뿐 아니라 상호작용까지 하려면? 공통의 약속이 있어야함!

ex. USB, HDMI

자바에서는 객체와 객체가 인터페이스를 통해서 상호작용한다.

인터페이스의 정의

완벽하게 추상화된 설계도 : 모든 메서드가 추상메서드

모든 메서드가 public abstract 이며 생략 가능

모든 멤버변수가 public static final (상수) 이며 생략 가능

interface 키워드를 사용

클래스에서는 해당 인터페이스를 implements 키워드를 이용하여 구현

[사용예시]

public interface MyInterface{
	public static final int MEMBER1 = 10;
	int MEMBER2 = 20;

	public abstract void method(int param);
	void methos2(int param2);
}

클래스는 인터페이스를 구현 = 인터페이스는 클래스에 의해 구현됨

  • 클래스는 구현하는 인터페이스의 모든 추상메서드를 필수로 오버라이드해야한다.

⇒ 오버라이드 하지 않아서 생기는 에러

 

인터페이스의 특징

  • interface 키워드를 이용하여 선언
  • 선언되는 변수는 모두 상수로 적용
  • 선언되는 메소드는 모두 추상메소드로 적용
  • 인터페이스 extends 를 이용하여 상속가능( 다중상속 가능)
  • 객체 생성이 불가능 ( 추상클래스와 동일한 특성)
  • 클래스가 인터페이스를 상속할 경우에는 extends 키워드가 아닌 implements 키워드를 사용
    • 여러개의 interface implements 가능
  • 인터페이스를 구현하는 하위클래스는 추상메소드를 반드시 오버라이딩 해야한다.
    • 구현하지 않을 경우 abstract 클래스로 표시
  • 인터페이스 다형성 적용

→ 인터페이스의 타입으로 인터페이스를 구현한 클래스의 객체

인터페이스 사용예시

[ HDMIOutput 인터페이스 ]

public interface HdmiOutput {
	void output(); //출력메소드
}

[ HDMIInput 인터페이스 ]

public interface HdmiInput {
	
	void setOutput(HdmiOutput device); //어느 출력장치에 넣을 것인가?
  

	void show();
}
  • 이때의 device는? HdmiOutput 인터페이스를 구현한 클래스의 객체

[ Computer 클래스 (HDMIInput 를 구현) ]

 

//인풋장치
public class Computer implements HdmiInput{
	
	private HdmiOutput outputDevice; 	// 컴퓨터는 hdmi 출력 장치에 의존

	@Override
	public void setOutput(HdmiOutput device) { 
		outputDevice = device;
	}

	@Override
	public void show() { 
		System.out.print("컴퓨터 화면을 ");
		outputDevice.output(); 
	}

}
  • outputDevice.output() ⇒ HdmiOutput 의 output() 메소드를 가져온다. 단, HdmiOutput 는 인터페이스이므로, HdmiOutput 을 구현한 클래스 안의 output() 메소드를 사용한다.

[ SuperComputer 클래스 (HDMIInput 를 구현) ]

public class SuperComputer implements HdmiInput{
	
	private HdmiOutput device;

	@Override
	public void setOutput(HdmiOutput device) { 
		this.device = device;
	}

	@Override
	public void show() { 
		System.out.print("슈퍼컴퓨터의 화면을 ");
		device.output();
	}

}

[ Television 클래스 ( HdmiOutput 인터페이스 구현) ]

//출력장치
public class Television implements HdmiOutput{

	@Override
	public void output() { 
		System.out.println("TV 화면을 출력합니다");
	} 

}

[ Monitor클래스 ( HdmiOutput 인터페이스 구현) ]

public class Monitor implements HdmiOutput {

	@Override
	public void output() { 
		System.out.println("모니터 화면에 출력합니다.");
	}
}

Test 클래스

public class Test {
	public static void main(String[] args) {
		//출력장치
		//인터페이스는 객체를 생성할 수는 없지만
		//해당 인터페이스를 구현한 클래스로 객체 생성이 가능하다.
		//인터페이스 타입으로 특정 객체를 참조하고 있다.
		HdmiOutput monitor = new Monitor(); //다형성
		HdmiInput computer = new Computer(); 
		computer.setOutput(monitor);
		computer.show();
		
		
		HdmiOutput television = new Television();
		computer.setOutput(television);
		computer.show();
		
		HdmiInput superComputer = new SuperComputer();
		superComputer.setOutput(monitor);
		superComputer.show();
		
	} 
}

 

 

왜 인터페이스를 사용해야할까?

  • 기술이 발전할수록 설계도(클래스)는 달라짐
  • 클래스가 바뀔때마다 코드를 수정하지 않고 계속해서 사용하기 위해서
  • 모듈화를 쉽게 하기위해서
  • 인터페이스를 구현하여 어떤 클래스의 객체든 사용할 수 있게 해서 이미 사용중인 코드를 수정할 필요없게 함.

인터페이스_다중구현

  • , 를 찍고 나열한다
public interface AbleToFly {
	void fly();
} 

public interface AbleToHunt {
	void hunt(); 
}
public class Eagle implements AbleToFly, AbleToHunt{

	@Override
	public void hunt() {  
	}

	@Override
	public void fly() { 
	} 

}
public class Duck implements DuckInterface{

	@Override
	public void hunt() { 
		
	}

	@Override
	public void swim() { 
		
	}

	@Override
	public void fly() { 
		
	}
}

⇒ Duck d = new Duck(); → Duck으로 선언했으므로, 상속받은 모든 인터페이스의 메소드 사용가능

⇒ AbleToFly 로 제한했으므로 AbleToFly 내부의 fly() 메소드만 사용가능

public interface DuckInterface extends AbleToFly, AbleToSwim, AbleToHunt{
	
	void playInnocent();

}

제네릭

  • 타입 파라미터를 이용하여 클래스, 인터페이스, 메서드를 다양한 타입으로 처리할 수 있도록 작성하는 기법
  • 타입파라미터란? <String> Integer
  • 사용예시
class GenericBox<T>{
	private T some;

	publc T getSome{
	 return some;
}

	public void setSome(T Some){
		this.some = some;
  }
}

이후에 T를 지정해주면 된다

제네릭클래스

위 : 담을때는 편하지만 뺄 때 불편

아래 : 담을때는 불편하지만 뺄 때 편함

표현

  • 클래스 또는인터페이스 선언 시 <> 에 타입 파라미터 표시
  • ClassName : Raw Type
  • ClassName<T> : Generic Type

public class NormalBox {
	private Object data;

	public Object getData() {
		return data;
	}

	public void setData(Object data) {
		this.data = data;
	} 

}

→ 에러뜬다 → 형변환해줘야한다

⇒ 제네릭을 사용하면 이러한 불편함을 해소할 수 있다.

클래스를 제네릭으로 만들기 위해서는?

  • 다양한 타입을 처리할 수 있도록 타입 파라미터 가 있어야 한다
public class GenericBox<T>{
	private T data;

	public T getData() {
		return data;
	}

	public void setData(T data) {
		this.data = data;
	} 
	
}

 

 

  • new 키워드 이후에 생성자를 호출할 때 <> 안의 타입은 생략가능 → 컴파일러가 문맥에서 유추가능
  • <> : 다이아몬드

제네릭메소드

  • 타입 파라미터가 있는 메소드
  • 타입파라미터를 메소드 내부에서 타입처럼 사용가능
  • 제네릭 메소드의 타입파라미터는 메소드 내부로만 범위가 한정
public class GenericBox<T>{
	private T data;
 
	public <K> void genericMethod(K k) { 
		System.out.println("T : " + data.getClass().getName());
		System.out.println("K : " + k.getClass().getName());
		
	}
}

public class Test {
	public static void main(String[] args) {
		//제네릭 클래스의 변수를 선언
		//제네릭 클래스로 객체를 만듦
		//선언과 객체 생성 시 타입을 지정
		GenericBox<String> strBox = new GenericBox<String>();
		strBox.setData("Hello");
		System.out.println(strBox.getData());
		strBox.genericMethod(123);
		
	}

}

타입파라미터의 제한

  • 필요에 따라 구체적인 타입 제한 필요
  • ex. 계산기 프로그램 구현 시 Number (Byte, short, Integer..) 이하의 타입으로만 제한
  • type parameter 선언 뒤 extends 와 함께 상위 타입 명시
public class NumberBox<T extends Number>{
	private T data; 
	
	public <K> void genericMethod(K k) { 
		System.out.println("T : " + data.getClass().getName());
		System.out.println("K : " + k.getClass().getName()); 
	}
}

Test 파일에 에러가 뜨는 이유는?

타입변수를 Number 하위의 자료형만 사용할 수 있도록 제한해두었기 때문에

와일드카드

  • 객체를 할당받을 때 와일드카드 이용
  • generic type 에서 구체적인 타입 대신 사용