객체지향 프로그래밍 - 인터페이스, 제네릭

생성 일시: 2023년 7월 24일 오후 8:22

🌍TISTORY

  • 인터페이스
  • 인터페이스 vs 클래스
  • Generic

인터페이스 Interface


인터페이스란?

서로 다른 장치들을 연결시켜 주는 규격

인터페이스

  • 완전히 추상화된 설계도
  • 클래스와 유사하게 작성이 가능 (class 대신 interface 키워드 사용)
  • 모든 메서드가 추상 메서드 (JDK8부터 default method, static method 추가)
public interface 인터페이스이름 {
	public static final 타입 상수이름1 = 10;
	(public static final 생략가능) 타입 상수이름 상수이름2 = 10;

	public abstract void 메서드이름1(타입 매개변수...);
	(public abstract 생략가능) void 메서드이름2(타입 매개변수...);
}

인터페이스 구현

  • 인터페이스는 그 자체로 인스턴스를 생성할 수 없음 (메서드 자체에 구현부 존재 x)
    interface MyInterface {}
    public class Main {
    	MyInterface m = new MyInterface(); --> 이거 안됨
    }
    
  • 인터페이스 내에 있는 메서드를 구현할 클래스가 필요함
  • extends 대신 implements 키워드를 사용하여 구현 클래스 작성
    interface Shape{}
    class Circle extends Shape{} --> (X)
    Circle extends Shape{} --> 이건  된다는 
    class Circle implements Shape{} --> 여러 개의 interface implements 가능
    

  • 인터페이스를 구현하는 구현 클래스로 사용하겠다
  • 인터페이스는 그 자체로 미완성된 설계도이므로 우리가 인스턴스를 생성할 수 없음
  • extends 대신에 implements 라고 하는 키워드를 이용한다
package interface01;

public abstract MyClass implements MyInterface {
	@Override
	public void method1() {
		System.out.println("메소드1이야");
	}

	@Override
	public void method2() {
		System.out.println("메소드2야");
	}
}
  • 인터페이스를 구현하는 클래스는 추상 메소드를 반드시 오버라이딩(재정의)해야 한다. (구현하지 않을 경우 abstract 클래스로 표시해야 함)
interface Chef {
	void cook();
}
class KFoodChef implements Chef {
	@Override
	public void cook() {
		System.out.println("한식을 요리한다.");
	}

// or 이렇게 작성

abstract class JFoodChef implements Chef {

}
  • 다형성 적용
    public static void main(String[] args) {
    	Chef chef = new KFoodChef();
    }
    

인터페이스 상속

  • extends를 이용하여 상속이 가능
  • 다중 상속이 가능 (클래스의 다중 상속에서의 문제점 없음) → 왜? 메소드가 겹치더라도 최종 구현 부분은 구현 객체에서 이루어지기 때문에 (클래스는 다중 상속이 안 되는 이유가 이름이 같을 경우 모호성을 해결하지 못해서 였음~)

    interface Movable {
    	public abstract void move();
    }
    
    interface Cookable {
    	public abstract void cook();
    }
    
    interface Chef extends Movable, Cookable {
    }
    
    class Robot implements Chef {
    	@Override
    	public void move() {}
    
    	@Override
    	public void cook() {}
    }
    

인터페이스의 필요성

  • 표준화(규격) 처리 가능
  • 개발 기간 단축 가능
  • 서로 관계가 없는 클래스들에게 인터페이스를 통해 관계를 맺을 수 있음
  • 인터페이스를 통한 간접적인 클래스 사용으로 손쉬운 모듈 교체 지원
  • 독립적 프로그래밍 가능

default method

  • 인터페이스에 구현부가 있는 메서드를 작성할 수 있음
    • 매번 재정의하기 귀찮은 메서드가 있으니 override 하지 않고 미리 정의해 둘 수도 있음!
  • 메서드 앞에 default라는 키워드를 작성해야 함
  • public 접근제한자를 사용해야 생략 가능
interface Chef extends Movable, Cookable {
	public void info();
}

조상 클래스에도 동일한 이름의 method가 있다면 충돌! → 그래서 인터페이스의 default method 가 우선, 그냥 구현부에서 override하면 됨

⬇️

interface Chef extends Movable, Cookable {
	public default void info() { /* 구현 내용 */ };
}

static method

  • 클래스의 static 메서드와 사용방법이 동일함
  • 인터페이스 이름으로 메서드에 접근하여 사용

    interface Chef extends Movable, Cookable {
    	public default void info() { /* 구현내용 생략 */ };
    	public static void sound() {
    		System.out.println("위잉~ 치킨");
    	};
    }
    
    public class RobotTest {
    	public static void main(String[] args) {
    		Chef.sound();
    	}
    }
    

인터페이스 vs 클래스


클래스와 인터페이스 비교

 클래스인터페이스
특징class 키워드를 사용하여 정의 필드와 메서드, 생성자로 이루어짐interface 키워드를 사용하여 정의 상수와 추상 메소드 (메소드 선언부) 로 이루어짐
 public static final 생략public abstract 생략
관계인터페이스를 구현함클래스에 의해 구현됨
멤버 변수선언 가능상수만 가능
다중 상속클래스는 하나의 클래스만 상속 가능인터페이스는 여러 개의 인터페이스 상속 가능 (구현부가 없으므로 헷갈리지 않음)
다중 구현클래스는 여러 개의 인터페이스를 다중으로 구현 (implements) 가능 
인스턴스생성 가능생성 불가
타입타입으로 사용 가능타입으로 사용 가능

추상클래스와 인터페이스 비교

공통점: 특정 기능의 구현을 강제하고 싶을

 추상 클래스인터페이스
객체생성불가불가
일반 메소드가능불가
일반 필드가능불가 (상수만 가능)
메서드abstract를 붙여야만 추상 메소드모든 메서드는 추상 메서드
사용- 추상적인 클래스의 성격을 가질 때 (일부 메서드만 미완성인 설계도) 
- 서로 유사한 클래스 사이에 코드를 공유하고 싶을- 서로 관련없는 클래스 사이에 공통으로 적용되는 인터페이스를 구현하기를 원할 때, ex Comparable, Serializable 
- 객체(클래스)의 성격이라기보다 어떤 기능을 구현하고 있다는 약속의 성격이 있을 때  

Generic


제네릭

  • 다양한 종류의 객체들을 다루는 메서드나 컬렉션 클래스에서 컴파일 시 타입을 체크해주는 기능
  • 객체의 타입 안정성을 제공한다
  • 형변환의 번거로움이 없어지므로 코드가 간결해진다 인터페이스

제네릭 클래스

  • 클래스를 정의할 때
  • 클래스 안에서 사용되는 자료형(타입)을 구체적으로 명시하지 않고
  • T와 같이 타입 매개변수를 이용하는 클래 인터페이스 1

제네릭 클래스 선언

  • 클래스 또는 인터페이스 선언 시 <>에 타입 파라미터 표시
    public class ClassName<T>{}
    public interfacec InterfaceName<T>{}
    
  • 타입 파라미터 → 특별한 의미의 알파벳보다는 단순히 임의의 참조형 타입을 말함
    • T: reference Type
    • E: Element
    • K: Key
    • V: Value

제네릭 클래스 객체 생성

  • 변수와 생성쪽의 타입은 반드시 일치해야 함 (상속관계에서도 마찬가지)
    Box<Student> box = new Box<Student>(); // (O)
    Box<Person> box = new Box<Student>(); // (X)
    
  • 추정이 가능한 경우 타입 생략 가능 (생성자 쪽 생략 가능 JDK 1.7부터)
    Box<Student> box = new Box<>();
    
  • 제네릭 타입을 지정하지 않고 생성이 가능하지만 권장 X (자동으로 T는 Object)

제네릭 클래스 실습

class Box {
	private Object obj;
	public Object getObj() {
		return obj;
	}
	public void setObj(Object obj) {
	this.obj = obj;
	}
}
public class BoxText {
	public static void main(String[] args) {
		Box box = new Box();
		box.setObj("Hello");
		box.setObj(new Person());

		Object obj = box.getObj();

		if (obj instanceof Person) {
			Person p = (Person) obj;
			System.out.println("사람");
		} else if (obj instanceof String) {
			String str = (String) obj;
			System.out.println("문자열");
		} else {
			System.out.println("알 수 없음");
		}
	}
}
class Box<T> {
	private T obj;
	public T getObj() {
		return  obj;
	}
	public void setObj(T obj) {
		this.obj = obj;
	}
}
public class BoxTest {
	public static vodi main(String[] args) {
	Box<Person> box1 = new Box<>();
	box1.setObj(new Person());
	Person p = box1. getObj();
	System.out.println("사람");

	Box<String> box2 = new Box<>();
	box2.setObj("Hi");
	String str = box2.getObj();
	System.out.println("문자열");
	}
}

제한된 제네릭 클래스

  • 타입 문자 사용할 타입을 명시하였지만 역시 모든 타입을 사용할 수 있는 문제가 발생
  • 구체적인 타입의 제한이 필요할 때 extends 키워드를 사용할 수 있음 (Person의 자손의 타입지정 가능)

    class Box<T extends Person> {
    	private T obj;
    
    	public T getObj() {
    		return obj;
    	}
    
    	public void setObj(T obj) {
    		this.obj = obj;
    	}
    }
    
  • 클래스가 아닌 인터페이스로 제한할 경우도 extends 키워드 사용
  • 클래스와 함께 인터페이스 제약 조건을 이용할 경우 &로 연

와일드 카드 이용

  • generic type에서 구체적인 타입 대신 사용
표현설명
Generic type<? >타입에 제한이 없음
Generic type<? extends T>T와 T를 상속받은 타입들만 사용 가능
Generic type<? super T>T와 T의 조상 타입만 사용 가능

실습 — 파일 구조

UserManager

→ iUserManager : 쓸 메소드들을 정의만 함

→ UserManagerImpl : 인터페이스를 구현