인터페이스
프로그래밍 관점 에서의 인터페이스는 추상 메서드의 집합을 말한다.
- 상수(final)만을 정의할수 있다.
- 다중 상속이 가능하다.(추상 메서드는 충돌해도 문제 없음)
- 모든 멤버가 public이며 [public static final / public abstract] 제어자는 생략할 수 있다.
- 인터페이스의 조상은 인터페이스만 가능하다.일반 클래스와 달리 Object가 최고 조상이 아니다.
- static 메서드. 상수, 디폴트 메서드들도 포함에 되지만 부수적인 것에 불과하다. (jdk 1.8부터)
- 구현된 것이 전혀 없는 설계도.(껍데기)
객체 내부의 원이 데이터, 바깥을 구상하는 것이 메서드이다. 데이터를 보호하기 위해 메서드를 통해서만 데이터에 접근(캡슐화)한다. 이는 데이터를 보호하기 위함이다.
메서드 중 인터페이스는 가장자리에 있는 메서드를 말한다. (노출되어 있기 때문에 public이다.) 데이터에 접근 하기 위해선 인터페이스를 통해야만 하게 된다.
인터페이스의 정의
추상 클래스는 일반 클래스 인데 추상 메서드를 가지는 것이지만 인터페이스는 오직 추상 메서드를 가지는 클래스이다. 인터페이스를 정의하는 것은 추상 클래스를 정의하는 것과 비슷하다.
interface InterfaceName{
public static final 타입 상수이름 = 값; // 상수
public abstract 메서드이름(매개변수); // 추상 메서드
}
클래스를 선언과 비슷하지만 interface키워드를 사용한다. 인터페이스의 모든 멤버는 public, 메서드는 전부 추상 메서드이며 변수는 가질수 없지만 상수(final)를 가질 수 있다.
interface InterfaceName{
public static final int finalnum1 = 4;
static final int finalnum2 = 4;
final int finalnum3 = 4;
int finalnum4 = 4;
public abstract void abstractMethod1();
abstract void abstractMethod2();
void abstractMethod3();
}
메서드 선언시 public과 abstract를 생략할 수 있다. 인터페이스에 정의된 모든 멤버의 메서드는 항상 [public abstract]. 상수도 마찬가지로 항상 [public static final] 이기 때문에 생략이 가능하다. (생략된 제어자는 컴파일러가 자동으로 추가)
인터페이스 구현
인터페이스도 추상 메서드와 마찬가지로 인터페이스 자체 만으로 인스턴스를 생성할 수 없다. 추상 클래스의 상속을 통해 완성하는 것처럼 인터페이스에 정의된 추상 메서드를 완성하는 것을 인터페이스의 구현이라 한다.
class ClassName implements InterfaceName {
//인터페이스에 정의된 추상 메서드를 구현해야한다.
}
- implements(구현) 키워드를 사용하여 추상 메서드를 구현한다.
class ClassName implements InterfaceName {
public void abstractMethod1() {};
public void abstractMethod2() {}
public void abstractMethod3() {}
}
클래스에 extends(상속) 키워드를 사용하여 추상 메서드를 구현하는 추상 클래스와 다른 키워드를 사용하지만 사용하는 방법은 동일하다.
인터페이스를 오버라이딩을 통해 구현할 때, 추상메서드의 접근 제어자는 모두 public 이기 때문에 구현부의 제어자를 부모 메서드보다 넓은 범위의 접근제어로 지정해 줘야한다.(오버라이딩 규칙)
- 다중 상속이 가능하다.(추상 메서드는 충돌해도 문제 없음)
abstract class ClassName implements InterfaceName1, InterfaceName2 {
}
클래스가 두 부모에게 선언부가 같고 구현부가 다른 메서드를 상속 받을 경우 어느 메서드를 상속 받을지 정하기 어렵다. 하지만 인터페이스는 추상메서드의 집합이기 때문에 같은 메서드를 가지는 인터페이스를 상속 받더라도 추상 메서드 이기 때문에 구현부가 작성되어 있지 않다. 따라서 같은 선언부를 가지를 메서드를 상속 받아도 충돌의 문제가 생가지 않는다.일반적으로 자바는 충돌 문제로 인해 단일 상속이다. 하지만 인터페이스 충돌 문제가 발생하지 않아 다중 상속을 지원한다.
- extends(상속) 키워드와 implements(구현)키워드 를 동시 사용이 가능하다.
class ClassName extends AbstractClass implements InterfaceName {
}
동시에 사용 해도 다중 상속의 문제(충돌)가 발생하지 않아 같이 사용함으로 다중 상속과 비슷한 효과를 얻을 수 있다. 상속(extends)은 클래스간의 관계를 연관시키는데 중점을 둔다면, 구현(implements)은 클래스를 확장시키는데 중점을 두기 때문에 다른 키워드를 사용한다.
- 인터페이스 끼리의 상속(extends)이 가능하다.
interface Interfacechild1{
public abstract void abstractMethod1();
}
interface Interfacechild2{
public abstract void abstractMethod2();
}
interface InterfaceName extends Interfacechild1, Interfacechild2{
void abstractMethod3();
}
인터페이스의 조상은 인터페이스만 가능하다. 인터페이스는 일반 클래스와 달리 Object가 최고 조상이 아니기 때문에 인터페이스에 클래스를 상속(extends)하는 것은 불가능하다.
- 인터페이스의 상수는 상속을 해도 독립적이다.
interface Interfacechild1{
int a = 10; // public static final이 생략 되었다.
public abstract void abstractMethod1();
}
interface InterfaceName extends Interfacechild1{
int a = 20; // public static final이 생략 되었다.
void abstractMethod2();
}
class ClassName implements InterfaceName {
int a = 30; // 인스턴스 변수
public void abstractMethod1() {};
public void abstractMethod2() {}
}
인터페이스의 상수의 접근 제어자는 모두 [public static final]이기 때문에 상속을 통해 값이 바뀌지 않고 독립적이다.
public class Main {
public static void main(String[] args) {
ClassName cn = new ClassName();
System.out.println(cn.a); // 30, 단순히 인스턴스 변수가 출력된다
// 인터페이스 타입 참조변수로 객체를 참조하면 인터페이스의 상수로 접근이 가능하다.
// 하지만 좋지 않은 방법이다.
InterfaceName ifn = new ClassName();
System.out.println(ifn.a);
// 바람직한 방법, 클래스 변수를 사용하듯 접근한다.
System.out.println(Interfacechild1.a);
}
}
- 인터페이스를 일부만 구현할 수 있다.
abstract class ClassName implements InterfaceName { // 일부 추상 메서드를 구현하지 않아 abstract
// abstractMethod1() 추상 메서드가 구현되지 않았다.
// public abstract void abstractMethod1();
public void abstractMethod2() {}
public void abstractMethod3() {}
}
추상 클래스와 마찬가지로 인터페이스의 추상 메서드의 일부를 미구현 했을 경우 추상메서드를 가진 추상 클래스가 되기 때문에 클래스 앞에 abstract를 붙여야 한다.
인터페이스의 디폴트 메서드와 static 메서드
기존에는 인터페이스에 사용할 수 없었던 디폴트 메서드와 스태틱 메서드를 java 1.8부터 사용이 가능해졌다. java 1.8부터 추가된 람다 표현식을 사용하여 자바에서도 함수형 프로그래밍을 할 수 있게 되었는데 이전 인터페이스를 사용하여 람다 표현식 기능을 활용할 수 있도록 이전 버전과의 호환성을 위해 추가 되었다.
관련 내용 추가 예정
람다식, 스트림, 익명클래스
인터페이스에 새로운 기능을 추가하기 위해 추상 메서드를 추가 헀을 경우 기존에 해당 인터페이스를 구현 했던 모든 클래스는 추가된 추상 메서드를 구현해야 하지만 디폴트 메서드(구현부가 있는)를 사용하면 메서드를 추가로 구현해야 하는 번거로움을 해결할 수 있다.
static 메서드는 인스턴스와 관계없는 독립적인 메서드로 인터페이스에 추가되어도 문제가 없었다지만 단순함을 중시하는 자바에서 허용되지 않았지만 java 1.8부터 허용 되었다.
디폴트 메서드
인터페이스를 구현한 후, 인터페이스를 구현한 모든 클래스에게 수정 없이 메서드를 만들어줘야 할 때 사용된다.
- default 키워드를 사용하여 디폴트 메서드를 구현한다.
interface InterfaceName{
public static final int num = 0; // 상수
public abstract void abstractMethod();
public default void defaultMethod() {
System.out.println("디폴트"); // 구현부
}; // 디폴트 메서드
}
정의 시 일반 메서드와 마찬가지로 구현부({ })가 있어야 한다. 마찬가지로 접근 제어자는 public이며 생략이 가능하다.
default 메서드를 오버라이딩 하여 재정의가 가능하지만 Object 클래스를 상속받지 않는 인터페이스 특성상 Object가 제공하는 기본 메서드를 사용할 수 없기 때문에 자식 클래스에서 재정의를 해야한다.
class MyClass implements InterfaceName{
public void abstractMethod(){
System.out.println("추상");
}
}
public class Main {
public static void main(String[] args) {
MyClass mc = new MyClass();
mc.abstractMethod();
mc.defaultMethod();
InterfaceName ifn = mc;
ifn.abstractMethod();
ifn.defaultMethod();
}
}
- @implSpec를 사용하여 디폴트 메서드의 역할, 반환값을 작성해야 한다.
interface InterfaceName{
public static final int num = 0; // 상수
public abstract void abstractMethod();
/**
* @implSpec 콘솔창에 "디폴트"를 출력한다.
*/
public default void defaultMethod() {
System.out.println("디폴트");
}; // 디폴트 메서드
}
기존의 인터페이스는 충돌을 피하기 위해 추상 메서드만을 가질 수 있었다. 하지만 디폴트 메서드를 사용해 충돌의 문제가 생기게 되었다.
디폴트 메서드가 기존 메서드와 충돌시 해결책
1. 여러 인터페이스의 디폴트 메서드 간의 충돌
- 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.
interface InterfaceName1{
public abstract void abstractMethod();
public default void defaultMethod() {
System.out.println("InterfaceName1의 디폴트 메서드");
}; // 디폴트 메서드
}
interface InterfaceName2{
public abstract void abstractMethod();
public default void defaultMethod() {
System.out.println("InterfaceName2의 디폴트 메서드");
}; // 디폴트 메서드
}
class MyClass implements InterfaceName1, InterfaceName2{
public void abstractMethod(){
System.out.println("추상 메서드");
}
// 선언부가 같은 인터페이스의 디폴트 메서드를 오버라이딩하여 통합.
public void defaultMethod() {
InterfaceName2.super.defaultMethod();
}
}
2. 디폴트 메서드와 조상 클래스의 메서드 간의 충돌
- 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.
interface InterfaceName1{
public abstract void abstractMethod();
public default void Method() {
System.out.println("InterfaceName1의 디폴트 메서드");
}; // 디폴트 메서드
}
class ClassName1{
public void Method() {
System.out.println("ClassName1의 메서드");
}; // 디폴트 메서드
}
class MyClass extends ClassName1 implements InterfaceName1{
public void abstractMethod(){
System.out.println("추상 메서드");
}
}
public class Main {
public static void main(String[] args) {
MyClass mc = new MyClass();
mc.abstractMethod();
mc.Method();
}
}
인터페이스의 디폴트 메서드는 무시되고 부모 클래스의 매서드가 상속된다.
추상 메서드
ClassName1의 메서드
디폴드 메서드의 super 키워드 사용
기존에는 super 키워드를 부모 클래스로부터 상속받은 멤버(필드나 메소드)를 자식 클래스에서 참조하는 데 사용하는 참조 변수로 [super.멤버명]를 통해 호출 하였다.
- 상속 받은 메서드를 오버라이딩여 재정의 했을 때, super 키워드를 사용하여 부모 메서드를 호출할 수 있다.
class MyClass extends ClassName1 implements InterfaceName1{
public void abstractMethod(){
System.out.println("추상 메서드");
}
public void Method() {
super.Method();
}
}
- 마찬가지로 인터페이스의 디폴트 메서드를 구현한 클래스에서 디폴트 메서드를 재정의 했을 경우 super키워드를 통해 기존의 인터페이스의 디폴트 메서드를 호출할 수 있다.
class MyClass extends ClassName1 implements InterfaceName1{
public void abstractMethod(){
System.out.println("추상 메서드");
}
public void Method() {
InterfaceName1.super.Method();
super.Method();
System.out.println("Method()메서드를 오버라이딩한 메서드");
}
}
기존의 super 키워드의 호출 방법과는 다소 다른 방법으로 호출이 가능하다. [인터페이스명.super.디폴트메서드명]
InterfaceName1의 디폴트 메서드
ClassName1의 메서드
Method()메서드를 오버라이딩한 메서드
static 메서드
- 기존의 클래스의 static 메서드와 다를 게 없는 메서드로 클래스의 static 메서드와 마찬가지로 객채의 구현을 강제하지 않는다.
- 인터페이스 타입으로 접근하여 사용할 수 있다. [인터페이스명.static메서드명]
- 인터페이스에서 helper 메서드로의 역할을 하기도 한다. helper 메서드는 해당 타입의 객체를 돕기 위해서 특정 목적으로 만들어진 메서드를 말한다.
- 인터페이스에서 내부적으로 필요한 것을 정의해두고 사용하는데 목적을 둔 유틸리티 메서드 역할을 하기도 한다.
interface InterfaceName1{
public abstract String abstractMethod(); // 추상 메서드
public default String defaultMethod() { // 디폴트 메서드
return "default";
};
public static void Method(String s) {
System.out.println(s + " 메서드 입니다.");
}; // static 메서드
}
class MyClass implements InterfaceName1{
public String abstractMethod(){
return "abstract";
}
}
public class Main {
public static void main(String[] args) {
MyClass mc = new MyClass();
InterfaceName1.Method(mc.abstractMethod());
InterfaceName1.Method(mc.defaultMethod());
}
}
인터페이스를 이용한 다형성
조상 타입 참조 변수로 자손 타입 객체를 다루는 다형성을 인터페이스에서도 적용할 수 있다. 따라서 인터페이스 타입의 참조변수로 인터페이스를 구현한 객체를 참조하는 것이 가능하다. 마찬가지로 인터페이스에 선언된 추상 메서드만 객체에서 사용이 가능하다.
InterfaceName ifn = new ClassName();
클래스가 여러 개의 인터페이스를 구현하게 되면 여러 참조변수의 타입으로 쓰일 수 있게된다. 인터페이스 타입으로 참조변수를 선언하게 되면 사용하는 입장에서는 뒤에 오는 모든 객체는 간단히 인터페이스만 구현한 객체이면 되기 때문에 시스템이 유연해지는 바탕이 된다.
interface InterfaceName1{};
class MyClass1 implements InterfaceName1{}
class MyClass2 implements InterfaceName1{}
class MyClass3 implements InterfaceName1{}
class MyClass4 implements InterfaceName1{}
public class Main {
public static void main(String[] args) {
InterfaceName1[] ifn1 = {
new MyClass1(),
new MyClass2(),
new MyClass3(),
new MyClass1()
};
}
생성자를 생성할 때를 제외하고 적합한 인터페이스가 있다면 매개변수, 반환값, 변수, 필드를 전부 인터페이스 타입으로 선언하여 객체를 클래스가 아닌 인터페이스로 참조하는 습관을 들이는 것이 좋다.
- 메서드 매개변수의 타입이 인터페이스인 경우 인터페이스를 구현한 클래스의 객체만을 저장할 수 있다.
void abstractMethod1(InterfaceName ifn){}
- 인터페이스를 메서드의 리턴타입으로 지정할 수 있다. 인터페이스를 구현한 클래스의 객체를 반환함을 의미한다.
InterfaceName method() {
return new ClassName();
// 인터페이스를 구현한 ClassName클래스의 객체를 반환한다.
// 조상-자손 관계의 참조변수는 서로 형변환이 가능하기 때문
}
//....
InterfaceName ifn = method();
// 반환하는 타입과 일치하거나 자동 형변환이 가능한 타입의 변수에 저장해야 한다.
- 참조 변수의 타입이 인터페이스인 경우 참조 변수에 저장된 객체를 다른 클래스의 인스턴스로 교체하고자 할 때 새 클래스의 생성자를 호출해주기만 하면 된다.
InterfaceName1 ifn1 = new MyClass1();
InterfaceName1 ifn1 = new MyClass1();
ifn1 = new MyClass2();
인터페이스는 변수 선언 타입, 매개변수, 리턴 타입등 여러 부분에서 사용된다. 추상 클래스의 상속과 차이는 없지만 인터페이스에 선언된 기능을 구현한 객체면 되기 때문에 더 확장성 있는 구조가 된다.
서로 관계없는 클래스들의 관계를 맺어줄 수 있다.
클래스 상속 구조는 부모 - 자식 관계로만 가능하기 때문에 상속을 통해 아래와 같이 상속 계층 구성하였다.
만약 특정 자식들 사이에 새로운 관계를 맺고 싶다면 또 다른 부모를 두어 부모 - 자식 관계를 만들어 주어야 한다 하지만 자바의 클래스의 상속 구조는 다중 상속을 지원하지 않고 단일 상속이기 때문에 불가능 하다.
서로 다른 부모를 상속하는 Tank클래스와 DropShip클래스의 관계를 형성하고자 할때 관계를 형성할 각 클래스에 인터페이스를 구현해줌으로써 상속 관계와 별도의 관계를 형성할 수 있다.
class Tank extends GrandUnit implements Machine{
public void play() {
System.out.println("탱크입니다.");
}
}
class DropShip extends AirUnit implements Machine{
public void play() {
System.out.println("드랍쉽입니다.");
}
}
인터페이스는 다중 상속에 대한 제약을 받지 않기 때문에, 서로 다른 부모클래스를 상속하고 있는 자식 클래스에 인터페이스를 구현 시켜줌으로써 서로 아무 관계 없는 클래스들을 관계를 맺어줄 수 있다.
public class Main {
public static void main(String[] args) {
play(new Tank());
play(new DropShip());
}
public static void play(Machine m) {
m.play();
}
}
인터페이스를 통해 관계를 맺어 줌으로 타입의 접근 제한 역할을 할 수 있다.
기계인 Tank, SCV, DropShip 클래스에 수리 기능을 추가하고 싶다면 조상 클래스에 오버라이딩을 통해 각 클래스에 기능을 추가해야 한다는 번거로움이 있다.
class Unit{
void repair(Tank t) {};
void repair(DropShip d) {};
//....
}
그렇다고 다형성을 이용해 부모 타입을 파라미터로 받는다면 의도와는 다른 Marine 클래스가 포함되어 의도와는 다른 클래스가 접근이 가능해져 버린다.
class GrandUnit{
void repair(GrandUnit g) {};
// DropShip이 포함되지 않으며 Marine 클래스 타입이 포함되어 버린다.
}
또 다른 부모를 두어 관계를 맺는다면 쉽게 해결할 수 있지만 자바의 클래스는 단일 상속의 원칙을 갖기 때문에 이미 상속을 받아 부모-자식 관계를 형성하고 있어 불가능하다. 별도의 Repairable 인터페이스를 선언한뒤 SCV, Tank, DropShip 클래스에 구현해 준다면 관계가 없던 클래스들에 공통점을 통해 관계가 생기게 된다.
interface Repairable{}
class SCV extends GrandUnit implements Repairable{}
class Tank extends GrandUnit implements Repairable{}
class DropShip extends AirUnit implements Repairable{}
이렇게 별도의 인터페이스를 통해 관계를 맺어줌으로 원하는 타입을 제외한 다른 타입에 대해 접근 제한을 할 수 있게된다.
public class Main {
public static void main(String[] args) {
play(new Tank());
play(new SCV());
play(new DropShip());
}
public static void play(Repairable r) { // 인터페이스를 구현한 객체를 매개변수로 받는다.
r.repair();
}
}
인터페이스 다중 상속을 통해 메서드 사용에 제한을 할 수 있다.
여러 인터페이스를 구현한 클래스의 객채 생성 시 참조변수선언을 특정 인터페이스로 한다면 다른 인터페이스에 정의된 메서드를 사용하지 못하게 된다.
interface Phone{
void Call();
void message();
};
interface VideoPlayer{
void pause();
void play();
}
class SmartPhone implements Phone, VideoPlayer{
public void Call() {}
public void pause() {}
public void play() {}
public void message() {}
}
참조변수의 변경을 통해 별도의 접근 제한을 하지 않아도 메서드의 접근 제한을 한것과 마찬가지의 효과를 가질 수 있다.
public class Main {
public static void main(String[] args) {
Phone p = new SmartPhone();
p.Call();
p.message();
// 인터페이스 Phone에 정의된 기능을 더이상 사용하지 못한다.
VideoPlayer vp = (VideoPlayer)p;
vp.pause();
vp.play();
}
}
이와 같이 상속에 기반을 두어 제약이 많은 클래스의 다형성에 비해 다중 상속을 통해 자유로운 상속관계를 형성할 수 있어 자유로운 것이 인터페이스 다형성의 특징이다.
인터페이스의 장점
의존성을 제거하여 변경에 유리한 설계가 가능하다.
상속을 통해 관계를 확장하게 된다면 강한 의존성이 생기게 되어 변경에 불리해 지게 된다.
두 대상(객체) 간의 '연결, 대화, 소통'을 돕는 '중간 역할'을 하는 인터페이스는 선언와 구현을 분리시킬 수 있게 한다.
인터페이스의 구현을 통해 관계를 확장시킨다면 객체간의 의존성이 줄어들어 변화에 강한 클래스를 작성할 수 있다.
다른 객체와 소통하기 위한 반환 타입, 매개변수 타입으로 인터페이스의 타입을 사용한다면 객체간의 의존성이 줄어들어변화에 강한 클래스를 만들수 있게 된다.
직접적인 관계의 두 클래스(A - B, 강한 결합)
class A {
public void methodA(B b) { // methodA메서드 가 B의 객체를 매개변수로 받아
b.methodB(); // B클래스의 매서드를 호출한다.
}
}
class B {
public void methodB() { //A클래스에서 직접 호출
System.out.println("B클래스");
}
}
public class Main {
public static void main(String[] args) {
A a = new A(); // A 클래스의 객체를 생성
a.methodA(new B()); // methodA메서드의 인수를 B의 객체로 한다.
}
}
- B와 직접적인 관계를 가진 A클래스에 새로운 클래스C 와의 관계로 변경하고자 한다면 A를 변경해야 한다.
class C implements I{
public void methodB() {
System.out.println("C클래스");
}
}
class A {
// public void methodA(B b) {
public void methodA(C c) { // 변경되었다.
c.methodB();
}
}
간접적인 관계의 두 클래스(A - I - B, 느슨한 결합)
interface I { void methodB();}
class B implements I{
public void methodB() {
System.out.println("B클래스");
}
}
class A {
public void methodA(I i) { // 인터페이스를 통한 관계를 형성한다.
i.methodB();
}
}
- 인터페이스를 통해 간접적인 관계를 형성하면 A와 B의 직접적인 관계가 없어진다.
class C implements I{
public void methodB() {
System.out.println("C클래스");
}
}
public class Main {
public static void main(String[] args) {
A a = new A();
a.methodA(new C()); //C와의 관계를 형성한다.
}
}
A와 B의 관계가 없어졌기 때문에 A클래스의 변경할 필요가 없어졌다. methodA메서드의 매개변수를 I의 인수로 인터페이스를 구현한 클래스의 객체를 받아 사용함으로 B의 객체를 매개변수로 받든 C의 객체를 매개변수로 받든 상관이 없어졌기 때문이다.
직접적인 관계를 가진 클래스는 유연하지 않고 변경에 불리 하지만 간접적인 관계를 가지는 클래스는 클래스의 선언부와 구현부를 분리 함으로 변경에 유리하고 유연해진다.
개발 시간을 단축할 수 있다.
인터페이스를 사용하여 클래스의 구현과 선언을 분리하였다면 독립적인 프로그래의 작성이 가능해진다.
interface I { void methodB();}
// B는 구현되지 않았다.
class A {
public void methodA(I i) { // 인터페이스를 통한 관계를 형성한다.
i.methodB();
}
}
A와 B가 직접적인 관계를 가졌을 경우 A는 B를 호출하기 때문에 B가 완성될 때 까지 기다린뒤 A의 작성이 가능해진다. 만약 간접적인 관계를 가졌다면 인터페이스만 구현되면 되기 때문에 B가 완성되지 않았아도 B가 완성되었다고 가정하고 A코드를 작성이 가능하다.B가 구현되지 않아도 A를 개발할 수 있고 A의 개발이 완료된 이후 B를 구현하거나 동시에 개발을 함으로 개발 시간을 단축할 수 있게 된다.
표준화가 가능하다.
인터페이스를 작성한뒤 인터페이스를 구현하도록 하면 정형화된 프로그램의 개발이 가능해진다. 예를 들어 설명하자면 자바 어플리케이션과 데이터베이스 사이의 인터페이스의 집합인 JDBC이 있다.
만약 JDBC가 없다면 자바 어플리케이션에서 데이터베이스의 연결 코드를 작성해야 하며 데이터베이스를 변경한다면 변경할 데이터베이스의 연결 코드를 완전히 바꿔야 할지도 모른다. 하지만 JDBC는 자바 어플리케이션에서 데이터베이스를 변경하더라도 모든 종류의 데이터베이스는 JDBC를 통해 통신하기 때문에 데이터베이스가 변경되더라도 많은 수정이 필요로 하지 않는다. 데이터베이스 개발사는 인터페이스인 JDBC를 구현한 클래스들을 제공한다.
'Java' 카테고리의 다른 글
[JAVA] 자바의 에러(error)와 예외(exception) (0) | 2023.10.25 |
---|---|
[JAVA] 내부 클래스(Inner Class) (0) | 2023.10.25 |
[JAVA] 추상 클래스(Abstract class) (0) | 2023.09.02 |
[JAVA]객체 지향 프로그래밍(Object Oriented Programming) (0) | 2023.08.30 |
[JAVA] 배열(Array) (0) | 2023.08.16 |