DevOps

Java 101 : 자바 인터페이스 - 재사용 가능한 Java 인터페이스

IT오이시이 2017. 6. 20. 22:52
728x90
JAVA 101: FOUNDATIONS

Java 101: Interfaces in Java

Extract class interfaces into reusable Java interfaces


http://www.javaworld.com/article/3171300/java-language/java-101-interfaces-in-java.html



인터페이스 란 무엇입니까?

인터페이스는 두 개의 시스템이 만나 상호 작용하는 점이다. 예를 들어, 자동 판매기 인터페이스는 사용자가 항목을 선택하고, 지불하고, 원하는 음식이나 음료를받을 수있게하는 메커니즘입니다. 프로그래밍 관점에서 인터페이스는 소프트웨어 구성 요소 사이에 위치합니다. 메서드 헤더 (메서드 이름, 매개 변수 목록 등) 인터페이스는 메서드를 호출하는 외부 코드와 호출의 결과로 실행될 메서드 내의 코드 사이에 위치한다고 가정합니다. 다음은 그 예입니다.


System.out.println(average(10, 15));
double average(double x, double y) // interface between average(10, 15) call and return (x + y) / 2;
{
   return (x + y) / 2;
}

자바 초보자에게 혼란스러운 것은 클래스에도 인터페이스가 있다는 것입니다. Java 101 에서 설명했듯이 Java의 클래스와 객체 는 인터페이스가 외부에있는 코드에서 액세스 할 수있는 클래스의 일부입니다. 클래스의 인터페이스는 메소드, 필드, 생성자 및 기타 엔티티의 일부 조합으로 구성됩니다. Listing 1을 살펴 보자.

Listing 1. Account 클래스 선언하기


class Account
{
   private String name;
   private long amount;
   Account(String name, long amount)
   {
      this.name = name;
      setAmount(amount);
   }
   void deposit(long amount)
   {
      this.amount += amount;
   }
   String getName()
   {
      return name;
   }
   long getAmount()
   {
      return amount;
   }
   void setAmount(long amount)
   {
      this.amount = amount;
   }
}

Account(String name, long amount)생성자와는 void deposit(long amount)String getName()long getAmount(), 및 void setAmount(long amount)방법은 형성 Account클래스의 인터페이스를 : 그들은 외부 코드에 액세스 할 수 있습니다. private String name;및 private long amount;필드는 액세스 할 수 없습니다.

메서드 또는 클래스 인터페이스 (예 : 클래스의 비공개 필드)를 지원 하는 코드 를 구현 코드 라고 합니다 . 구현 코드는 외부 코드로부터 숨겨져 있어야하므로 진화하는 요구 사항을 충족시키기 위해 변경할 수 있습니다.

노출 된 구현 코드는 소프트웨어 구성 요소 간의 원하지 않는 상호 종속성을 초래할 수 있습니다. 예를 들어 메소드 코드가 외부 변수에 의존하거나 클래스의 사용자가 숨겨져 야 할 필드에 의존하게 될 수 있습니다. 이 결합 은 소프트웨어의 초기 반복에 대해서는 문제가되지 않지만, 구현이 진화되어야 할 때 문제가 발생할 수 있습니다.

Java 개발자는 인터페이스 언어 기능을 사용하여 클래스 인터페이스를 추상화하므로 클래스를 사용자와 분리 합니다. 클래스 대신 Java 인터페이스에 중점을두면 소스 코드에서 클래스 이름에 대한 참조 수를 최소화 할 수 있습니다. 이렇게하면 소프트웨어가 성숙 될 때마다 한 클래스에서 다른 클래스로 쉽게 변경할 수 있습니다 (성능 향상을 위해). 다음은 그 예입니다.


List names = new ArrayList<>()
void print(List names)
{
 // ...
}

이 간단한 프로그램은 names문자열 이름 목록을 저장하는 필드를 선언하고 초기화 합니다. 프로그램 print()은 문자열 목록의 내용을 출력 하는 메서드를 선언합니다.이 메서드는 줄 당 하나의 문자열 일 수 있습니다. 간결함을 위해 메서드 구현을 생략했습니다.

List객체의 순차 수집을 설명하는 Java 인터페이스입니다. ArrayList는 ListJava 인터페이스 의 배열 기반 구현을 설명하는 클래스입니다 . ArrayList클래스 의 새 인스턴스를 가져 와서 List변수에 할당 합니다 names. ( List그리고 ArrayList표준 클래스 라이브러리의 java.util패키지에 저장 됩니다.)

클라이언트 코드가 상호 작용할 때, 클라이언트 코드 names는에 의해 선언되고에 의해 List구현되는 메소드를 호출 합니다 ArrayList. 클라이언트 코드는 직접 상호 작용하지 않습니다 ArrayList. 따라서 다음과 같은 다른 구현 클래스 LinkedList가 필요할 때 클라이언트 코드가 중단되지 않습니다.


List names = new LinkedList<>()
// ...
void print(List names)
{
 // ...
}

때문에 print()메소드 매개 변수 유형이 ,이 방법의 구현은 변경하지 않습니다. 그러나 형식이있는 경우 형식을로 변경해야 합니다. 두 클래스가 모두 고유 한 메서드를 선언한다면 구현 을 크게 변경해야 할 수도 있습니다 .ListArrayListLinkedListprint()

클래스의 구현을 변경하지 않아도 List되는 코드를 분리 ArrayList하고 LinkedList작성할 수 있습니다. Java 인터페이스를 사용하면 구현 클래스에 의존하여 발생할 수있는 문제를 피할 수 있습니다. 이 디커플링은 Java 인터페이스를 사용하는 주된 이유입니다.

인터페이스 선언

본문을 따르는 머리글로 구성된 클래스와 유사한 구문을 고수함으로써 인터페이스를 선언합니다. 최소한 헤더는 키워드 interface와 인터페이스를 식별하는 이름으로 구성됩니다 . 본문은 열린 중괄호 문자로 시작하고 닫는 중괄호로 끝납니다. 이러한 구분 기호 사이에는 상수 및 메서드 머리글 선언이 있습니다.


interface identifier
{
   // interface body
}

규칙에 따라 인터페이스 이름의 첫 글자는 대문자로 표시되며 이후 문자는 소문자로 표시됩니다 (예 :) Drawable. 이름이 여러 단어로 구성된 경우 각 단어의 첫 글자는 대문자로 표시됩니다 (예 :) DrawableAndFillable. 이 명명 규칙은 CamelCasing 으로 알려져 있습니다 .

Listing 2는 명명 된 인터페이스를 선언한다 Drawable.

Listing 2. Drawable 인터페이스 선언하기


interface Drawable
{
   int RED = 1;
   int GREEN = 2;
   int BLUE = 3;
   int BLACK = 4;
   int WHITE = 5;
   void draw(int color);
}

Drawable색상 상수를 식별하는 5 개의 필드를 선언합니다. 또한이 인터페이스는 draw()외곽선을 그리는 데 사용되는 색을 지정하기 위해 이러한 상수 중 하나로 호출해야하는 메서드 의 머리글을 선언합니다 . (어떤 정수 값을 전달할 수 있기 때문에 정수 상수를 사용하는 것은 좋은 생각이 아니지만 draw()간단한 예제로 충분합니다.)

Drawable무엇을 할 것인가 (무언가를 그리는)를 지정하지만 그것을하는 방법을 지정하지 않는 참조 유형을 식별합니다. 구현 세부 정보는이 인터페이스를 구현하는 클래스에 전달됩니다. 이러한 클래스의 인스턴스는 drawable로 알려져 있습니다. 왜냐하면 그들은 자신을 그리는 방법을 알고 있기 때문입니다.

인터페이스 구현하기

클래스는 Java implements키워드 뒤에 클래스 이름에 쉼표로 구분 된 인터페이스 이름 목록을 추가하고 클래스의 각 인터페이스 메소드를 코딩하여 인터페이스를 구현합니다. Listing 3은 Listing 2의 Drawable인터페이스 를 구현하는 클래스이다 .

Listing 3. Drawable 인터페이스를 구현하는 Circle


class Circle implements Drawable
{
   private double x, y, radius;
   Circle(double x, double y, double radius)
   {
      this.x = x;
      this.y = y;
      this.radius = radius;
   }
   @Override
   public void draw(int color)
   {
      System.out.println("Circle drawn at (" + x + ", " + y + 
                         "), with radius " + radius + ", and color " + color);
   }
   double getRadius()
   {
      return radius;
   }
   double getX()
   {
      return x;
   }
   double getY()
   {
      return y;
   }
}

Listing 3의 Circle클래스는 원을 중심점과 반지름으로 설명한다. 뿐만 아니라 적절한 게터 생성자 메소드를 제공하는 등, Circle유단 Drawable부가함으로써 인터페이스를 implements Drawable받는 Circle, 헤더 (의해 지시 된 바와 같이 대체하여 @Override주석) Drawable의 draw()방법 헤더.

Listing 4는 두 번째 예제 인 Rectangle구현 하는 클래스이다 Drawable.

Listing 4. 사각형 컨텍스트에서 Drawable 인터페이스 구현하기


class Rectangle implements Drawable
{
   private double x1, y1, x2, y2;
   Rectangle(double x1, double y1, double x2, double y2)
   {
      this.x1 = x1;
      this.y1 = y1;
      this.x2 = x2;
      this.y2 = y2;
   }
   @Override
   public void draw(int color)
   {
      System.out.println("Rectangle drawn with upper-left corner at (" + x1 + 
                         ", " + y1 + ") and lower-right corner at (" + x2 +
                         ", " + y2 + "), and color " + color);
   }
   double getX1()
   {
      return x1;
   }
   double getX2()
   {
      return x2;
   }
   double getY1()
   {
      return y1;
   }
   double getY2()
   {
      return y2;
   }
}

Listing 4의 Rectangle클래스는이 셰이프의 왼쪽 위 및 오른쪽 아래 모서리를 나타내는 점 쌍으로 사각형을 설명합니다. 와 같이 CircleRectangle생성자 적당한 게터 방법을 제공하고, 또한 구현하는 Drawable인터페이스.

인터페이스 타입의 데이터 값은 클래스가 인터페이스를 구현하고 그 행동이 인터페이스의 메소드 헤더에 의해 지정된 것입니다. 이 사실은 객체의 클래스가 인터페이스를 구현하는 경우 인터페이스 유형의 변수에 객체의 참조를 할당 할 수 있음을 의미합니다. Listing 5에 나와있다.

Listing 5. 서클 및 사각형 오브젝트를 Drawable로 앨리어싱하기


class Draw
{
   public static void main(String[] args)
   {
      Drawable[] drawables = new Drawable[] { new Circle(10, 20, 15), 
                                              new Circle(30, 20, 10),
                                              new Rectangle(5, 8, 8, 9) };
      for (int i = 0; i < drawables.length; i++)
         drawables[i].draw(Drawable.RED);
   }
}

때문에 Circle와은 Rectangle구현 DrawableCircle그리고 Rectangle객체가 Drawable자신의 클래스 유형 이외에 유형입니다. 따라서 각 객체의 참조를 Drawables 의 배열에 저장하는 것은 합법적 입니다. 루프는이 배열을 반복하며 각 Drawable객체의 draw()메서드를 호출 하여 원 또는 사각형을 그립니다.

이 목록하는 것은 A의 저장된다고 가정 Drawable.java과 같은 디렉토리에있는 소스 파일 Circle.javaRectangle.java및 Draw.java(각각 저장소, 목록 3 목록 4, 5 목록) 소스 파일, 다음 명령 줄 중 하나를 통해이 소스 파일을 컴파일 :


javac Draw.java
javac *.java

Draw다음과 같이 응용 프로그램을 실행하십시오 .


java Draw

다음 출력을 관찰해야합니다.


Circle drawn at (10.0, 20.0), with radius 15.0, and color 1
Circle drawn at (30.0, 20.0), with radius 10.0, and color 1
Rectangle drawn with upper-left corner at (5.0, 8.0) and lower-right corner at (8.0, 9.0), and color 1

다음 main()메소드 를 지정하여 동일한 출력을 생성 할 수도 있습니다 .


public static void main(String[] args)
{
   Circle c = new Circle(10, 20, 15);
   c.draw(Drawable.RED);
   c = new Circle(30, 20, 10);
   c.draw(Drawable.RED);
   Rectangle r = new Rectangle(5, 8, 8, 9);
   r.draw(Drawable.RED);
}

보시다시피, 각 객체의 draw()메소드 를 반복적으로 호출하는 것은 지루합니다 . 게다가 이렇게하면 Draw클래스 파일에 바이트 코드가 추가 됩니다. 생각으로 Circle하고 Rectangle로 Drawable의, 당신은 배열과 코드를 단순화하는 간단한 루프를 활용할 수 있습니다. 이것은 클래스에 비해 인터페이스를 선호하는 코드를 설계 할 때 얻을 수있는 추가 이점입니다.

다중 인터페이스 구현하기

앞서 클래스가 여러 인터페이스를 구현할 수 있다고 언급했습니다. 각 인터페이스의 이름은 implements키워드 다음에 오는 쉼표로 구분 된 이름 목록의 일부로 지정됩니다 . Listing 6은 class C가 인터페이스 A와를 구현 하는 간단한 예제 B이다.

Listing 6. 다중 인터페이스 구현하기


interface A
{
   // appropriate constants and/or method headers
}
interface B
{
   // appropriate constants and/or method headers
}
class C implements A, B
{
   // override A's and B's method headers
}

여러 인터페이스를 구현할 때 이름 충돌의 가능성에주의하십시오. 이것은 동일한 상수 이름이 각 인터페이스에 표시 될 때 가능하며 유형 및 / 또는 기타 정보가 다를 수 있으며 클래스에서 액세스됩니다. 이름 충돌이 발생하면 컴파일러는 오류를보고합니다 (Listing 7).

Listing 7. 충돌 상수 표시하기


interface A
{
   int CONSTANT = 2;
   void method();
}
interface B
{
   int CONSTANT = 3;
   int method(int x);
}
class C implements A, B
{
   int x = CONSTANT;
   @Override
   public void method()
   {
   }
   @Override
   public int method(int x)
   {
      return x;
   }
}

여기에서 class C는 CONSTANT두 개의 서로 다른 값으로 초기화되는 두 개의 다른 상수를 상속 합니다. Java 컴파일러는 어떤 상수가 상속되어야 하는지를 판별 할 수 없으며 C(각 상수에 동일한 값이 지정된 경우 동일한 문제점이 발생 함) 다음 오류 메시지를보고합니다.


C.java:15: error: reference to CONSTANT is ambiguous
   int x = CONSTANT;
           ^
  both variable CONSTANT in A and variable CONSTANT in B match
1 error

인터페이스 확장하기

인터페이스를 구현하는 클래스는 인터페이스 상속을 나타냅니다 . 이 클래스는 인터페이스의 상수와 메소드 헤더를 상속합니다. 예를 들어, each of Circle와 Rectangleandherit Drawable의 5 개의 정수 상수와 draw()메소드 헤더를 상속받습니다 .

인터페이스 상속은 인터페이스가 다른 인터페이스를 확장 할 때도 시연됩니다. 하위 클래스가 예약어를 통해 수퍼 클래스를 확장 할 수있는 것처럼 extends이 예약어를 사용하여 하위 인터페이스가 수퍼 인터페이스를 확장하도록 할 수 있습니다. Listing 8을 참조하십시오.

Listing 8. Drawable 슈퍼 인터페이스를 확장하는 채우기 가능한 서브 인터페이스 선언하기


interface Fillable extends Drawable
{
   void fill(int color);
}

Fillable연장 Drawable색 상수 및 상속 draw()방법 헤더. Fillable또한 fill()내부를 채우는 데 사용되는 색상을 지정하기 위해 이러한 상수 중 하나로 호출해야하는 메소드 의 헤더를 선언합니다 . ( 외곽선 그리기 및 내부 채우기를 지원하도록 Fillable연장됨 Drawable)

다음 단계를 수행하여 이전 Circle및 Rectangle클래스를 지원하도록 개조 할 수 Fillable있습니다.

  1. 로 변경 implements Drawable하십시오 implements Fillable. 이 중 하나를 지정할 필요가 없습니다 implements Drawable, Fillable나 implements Fillable, Drawable때문에 Fillable모두 포함 Drawable확장자.
  2. fill()메소드 헤더를 오버라이드 (override)하는 것과 같은 방법으로 draw()메소드 헤더 를 오버라이드 (override)합니다 .

Listing 9는 인터페이스 Fill를 보여주는 동등한 애플리케이션을 보여준다 Fill.

Listing 9. 원 및 사각형 오브젝트를 Fillables로 앨리어싱하기


class Fill
{
   public static void main(String[] args)
   {
      Fillable[] fillables = new Fillable[] { new Circle(10, 20, 15), 
                                              new Circle(30, 20, 10),
                                              new Rectangle(5, 8, 8, 9) };
      for (int i = 0; i < fillables.length; i++)
      {
         fillables[i].draw(Drawable.RED);
         fillables[i].fill(Fillable.BLACK);
      }
   }
}

Circle및 Rectangle구현 Fillable제공 Circle하고 Rectangle객체 Fillable자신의 클래스 유형 이외에 유형입니다. 따라서 각 객체의 참조를 Fillables 의 배열에 저장하는 것은 합법적 입니다. 이 배열을 반복하는 루프가 각 상속 된 메소드 와 Fillable상속 draw()되지 않는 fill()메소드를 호출 하여 원이나 사각형을 그리고 채 웁니다.

목록 2에 저장되어있는 경우 Drawable.java, 같은 디렉토리에있는 등 Circle.javaRectangle.javaFillable.java, 그리고 Fill.java당신이 중 하나를 사용하여 이러한 소스 파일을 컴파일 할 수 있습니다 (각각 3 목록과 목록 4, 업데이트, 목록 8, 저장 9 목록 소스 파일 저장) 다음 명령 줄 중 :


javac Fill.java
javac *.java

Fill다음과 같이 응용 프로그램을 실행하십시오 .


java Fill

다음 출력을 관찰해야합니다.


Circle drawn at (10.0, 20.0), with radius 15.0, and color 1
Circle filled at (10.0, 20.0), with radius 15.0, and color 4
Circle drawn at (30.0, 20.0), with radius 10.0, and color 1
Circle filled at (30.0, 20.0), with radius 10.0, and color 4
Rectangle drawn with upper-left corner at (5.0, 8.0) and lower-right corner at (8.0, 9.0), and color 1
Rectangle filled with upper-left corner at (5.0, 8.0) and lower-right corner at (8.0, 9.0), and color 4

하위 인터페이스는 일종의 수퍼 인터페이스이기 때문에 하위 인터페이스에서 수퍼 인터페이스로 객체의 인터페이스 유형을 업 캐스팅 할 수 있습니다. 예를 들어, 할당 할 수 Fillable참조 Drawable변수를 다음 호출 Drawable의의 draw()변수에 방법 :


Drawable d = fillables[0];
d.draw(Drawable.GREEN);

다중 인터페이스 확장하기

인터페이스 구현과 마찬가지로 여러 인터페이스를 확장 할 수 있습니다. 각 인터페이스의 이름은 extends키워드 다음에 오는 쉼표로 구분 된 이름 목록의 일부로 지정됩니다 . Listing 10은 인터페이스는 간단한 예를 제시 C인터페이스 확장 A및 B.

Listing 10. 다중 인터페이스 확장하기

interface A
{
   // appropriate constants and/or method headers
}
interface B
{
   // appropriate constants and/or method headers
}
interface C extends A, B
{
   // appropriate constants and/or method headers
}

여러 인터페이스를 확장 할 때 이름 충돌의 가능성에주의하십시오. 이것은 동일한 상수 이름이 각 수퍼 인터페이스에 나타나고 다른 유형 및 / 또는 기타 정보로 표시 될 수 있으며 하위 인터페이스에서 액세스 될 때 발생합니다. 이름 충돌이 발생하면 컴파일러는 오류를보고합니다 (Listing 11).

Listing 11. 충돌 상수 표시하기


interface A
{
   int CONSTANT = 2;
   void method();
}
interface B
{
   int CONSTANT = 3;
   int method(int x);
}
interface C extends A, B
{
   int CONSTANT2 = CONSTANT;
}

여기서 인터페이스 C는 서로 다른 CONSTANT두 개의 값으로 초기화 된 두 개의 다른 상수를 상속 합니다. Java 컴파일러는 어떤 상수가 상속되어야 하는지를 판별 할 수 없으며 C(각 상수에 동일한 값이 지정된 경우 동일한 문제점이 발생 함) 다음 오류 메시지를보고합니다.


C.java:15: error: reference to CONSTANT is ambiguous
   int CONSTANT2 = CONSTANT;
                   ^
  both variable CONSTANT in A and variable CONSTANT in B match
1 error

Java 8에서 인터페이스 진화

Java 8은 기본 메소드와 정적 메소드의 두 가지 중요한 인터페이스 향상 기능을 도입했습니다. 이러한 향상된 기능은 용도가 있지만 인터페이스를 클래스와 유사하게 만들어 클래스 대신 인터페이스에서 일부 응용 프로그램을 기반으로 할 수있게합니다.

728x90
반응형