자바의 인터페이스
2024. 2. 4. 13:49ㆍJava
반응형
인터페이스 (Interface) 란 무엇인가
인터페이스는 자바의 추상화 (abstraction) 개념을 구체화하기위한 산물이다.
클래스의 추상 메서드와 변수를 가지고 있고, 클래스와 IS-A 관계가 성립한다.
어떤 엔티티(실체)를 그것의 속성으로 표현하는 것이 아닌 행동(behavior)로 표현하고 싶다면 인터페이스를 사용한다.
인터페이스의 기본 문법
인터페이스를 정의하기 위해서는 인터페이스를 선언하고, 모든 구성요소를 추상화 해야한다.
즉, 인터페이스 내 모든 메서드는 구문이 존재하지 않아야하고 변수는 public, static 으로 선언되어 다중으로 상속할 수 있도록 해야한다. (이 부분은 JDK 8 이후 변화가 있음)
인터페이스를 상속하기 위해서는 implements 키워드를 사용하고 내부에 선언된 모든 메서드를 구현해야한다.
interface {
// constant field
// abstract method
}
인터페이스 구현체의 특징
- 추상화 되어있다.
- 클래스의 다중 상속은 허용되지 않지만, 인터페이스는 무제한 다중 상속 가능하다.
- 코드 간 결합도가 낮다.
추상 클래스와의 차이점
추상 클래스 (abstract class) 는 final 이 아닌 변수를 가지고 있지만, 인터페이스의 변수는 public static final, 즉 상수이다.
interface Developer {
final int id = 10;
int coding();
}
인터페이스와 클래스 간 상속
- Class extends Class : 가능
- Class implements Interface : 가능
- Interface extends Interface : 가능
- Interface extends Class : 불가능
인터페이스와 클래스의 차이점
- 인터페이스는 변수를 초기화하거나 객체 생성이 불가능하지만, 클래스는 변수 초기화와 객체 생성이 가능하다.
- 인터페이스는 구현된 (implement) 고정된 (concrete) 메서드를 갖는 것이 불가능하지만, 클래스는 구현되고 고정된 메서드를 가질 수 있다.
- 인터페이스는 public 접근 제어자만 가질 수 있지만, 클래스는 public, protected, private 접근 제어자를 가질 수 있다.
인터페이스 사용의 장점
- 구현 부분의 코드를 추상화하여 감출 수 있다.
- 객체 지향의 개념 특성상 다중 상속이 불가능하나, 인터페이스를 사용하면 다중 상속이 가능하다.
public interface DevInterface1 {
int dev1 = 10;
void method1(int a);
void method2(int b);
// 기본 구현 메서드 정의 가능 (JDK 8 이후)
default void method5() {
System.out.println("default interface method");
}
}
public interface DevInterface2 {
void method3(int c);
void method4(int d);
// 정적 기본 메서드 구현 가능 (JDK 8 이후)
static void method6() {
System.out.println("static method");
}
}
public interface DevInterface3 extends DevInterface1, DevInterface2 {
// 다중 상속, 이중 상속 가능
void method7();
}
public class DevClass1 implements DevInterface1, DevInterface2 {
// 메서드 구현
@Override
public void method1(int a) {
System.out.println(a);
}
@Override
public void method2(int b) {
System.out.println(b);
}
// 다중 상속
@Override
public void method3(int c) {
System.out.println(c);
}
@Override
public void method4(int d) {
System.out.println(d);
}
public static void main(String[] args) {
DevClass1 dc1 = new DevClass1();
dc1.method1(1); // 1
dc1.method2(2); // 2
dc1.method3(3); // 3
dc1.method4(4); // 4
dc1.method5(); // default interface method
DevInterface2.method6(); // static method
}
}
public class DevClass2 implements DevInterface1 {
// 다른 구현
@Override
public void method1(int a) {
System.out.println(a + 1);
}
@Override
public void method2(int b) {
System.out.println(b + 1);
}
public static void main(String[] args) {
DevClass2 dc2 = new DevClass2();
dc2.method1(1); // 2
dc2.method2(2); // 3
}
}
public class DevClass3 implements DevInterface3 {
@Override
public void method1(int a) {
System.out.println(a);
}
@Override
public void method2(int b) {
System.out.println(b);
}
@Override
public void method3(int c) {
System.out.println(c);
}
@Override
public void method4(int d) {
System.out.println(d);
}
@Override
public void method7() {
System.out.println("method 7");
}
public static void main(String[] args) {
DevClass3 dc3 = new DevClass3();
dc3.method1(1); // 1
dc3.method2(2); // 2
dc3.method3(3); // 3
dc3.method4(4); // 4
dc3.method7(); // method 7
}
}
코드 추상화 구현의 단계
- 인터페이스에는 여러 개의 추상 메서드를 만들어 둘 수 있다.
- 만약 인터페이스에 있는 모든 추상 메서드를 구현할 수 없다면, 추상 클래스로 일부를 구현하고 본 클래스에 구현의 책임을 넘길 수 있다.
- 그 후 상속받은 클래스에서 모든 메서드를 구현한다.
- 구현된 코드를 main() 메서드에서 실행한다.
public interface Dev2Interface {
void method1();
void method2();
void method3();
void method4();
// JDK 9 이후 private, static 메서드 사용 가능
// default 메서드에서 private 실행 가능
default void method8() {
System.out.println("default method");
method6();
}
// static 메서드에서 private static 실행 가능
static void method5() {
System.out.println("static method");
method7();
}
// private 메서드는 default 메서드에서 사용 가능
private void method6() {
System.out.println("private method");
}
// private static 메서드는 static 메서드에서 사용 가능
private static void method7() {
System.out.println("private static method");
}
}
abstract class Dev2AbClass1 implements Dev2Interface {
@Override
public void method1() {
System.out.println("method1 on abstract class 1");
}
}
abstract class Dev2AbClass2 extends Dev2AbClass1 {
@Override
public void method2() {
System.out.println("method 2 on abstract class 2");
}
}
public class Dev2Class extends Dev2AbClass2{
@Override
public void method3() {
System.out.println("method 3");
}
@Override
public void method4() {
System.out.println("method 4");
}
public static void main(String[] args) {
// 인스턴스 생성
Dev2Class d2c = new Dev2Class();
// 상속 메서드
d2c.method1(); // method1 on abstract class 1
d2c.method2(); // method2 on abstract class 2
// 구현 메서드
d2c.method3(); // method3
d2c.method4(); // method4
// static 메서드
Dev2Interface.method5(); // static method, private static method
// default 메서드
d2c.method8(); // default method, private method
}
}
정리
- 인터페이스는 자체적으로 객체를 생성해 낼 수는 없지만, 클래스에서 구현(implements) 할 수 있다.
- 클래스는 복수의 인터페이스를 구현할 수 있다.
- 인터페이스는 다수의 인터페이스를 상속받을 수 있다.
- 인터페이스를 상속한 클래스는 인터페이스 내 모든 메서드를 구현해야 한다.
- JDK 8, 9 이후에는 변화가 있지만 기본적으로 메서드는 public abstract 즉 공개, 비어있음. 변수는 public static final 즉 상수
- 클래스는 못하는 다중 상속을 할 수 있다.
- 코드가 추상화되어 있으므로 결합도가 낮아진다.
- 인터페이스 내의 변수는 상수이므로 인스턴스 변수는 선언할 수 없다.
- 인터페이스에서는 생성자 (Constructor) 를 사용할 수 없다.
- 인터페이스에서는 main() 메서드를 사용할 수 없다.
Resources
반응형