728x90
인터페이스 상수
- 인터페이스는 추상 메서드로 이루어지므로 인스턴스를 생성할 수 없으며 멤버 변수도 사용할 수 없습니다.
- 인터페이스에 다음과 같이 변수를 선언해도 오류가 나지 않습니다.
double PI = 3.14;
int ERROR = -99999;
- 위와 같이 하여도 오류가 발생하지 않는 이유는 컴파일러가 자동으로 상수로 변환해주기 때문입니다.
- 컴파일러는 public static final double PI =- 3.14; 로 선언합니다.
디폴트 메서드와 정적 메서드
- 자바 7까지는 인터페이스에서 추상 메서드와 상수, 이 두 가지 요소만 선언해서 사용할 수 있었습니다.
- 그런데, 이 추상 메서드와 상수 두 가지만 있는 인터페이스는 다음과 같은 불편한 사항들이 있었습니다.
- 1. 한 인터페이스를 구현한 여러 클래스에서 공통으로 갖는 메서드가 있을 수 있는데, 기존 인터페이스에서는 추상 메서드를 가질 수밖에 없기 때문에 공통으로 갖는 메서드를 만들 수가 없습니다.
- 자바 8부터는 이런 부분에서 인터페이스 활용성을 높이기 위해 디폴트 메서드와 정적 메서드 기능을 제공합니다.
- 디폴트 메서드는 인터페이스에서 구현 코드까지 작성한 메서드입니다.
- 인터페이스를 구현한 클래스에 기본적으로 제공할 메서드인 것이죠.
- 정적 메서드는 인스턴스 생성과 상관없이 사용할 수 있는 메서드입니다.
- 하지만 디폴트 메서드나 정적 메서드를 추가했다고 해서 인터페이스가 인스턴스를 생성할 수 있는 것은 아닙니다.
- 그러면 인터페이스에 구현하는 디폴트 메서드와 정적 메서드가 무엇인지, 어떻게 호출하고 사용하는지 자세히 살펴보겠습니다.
디폴트 메서드
- 디폴트 메서드란 말 그대로 기본으로 제공되는 메서드입니다.
- 디폴트 메서드는 인터페이스에서 구현하지만, 이후 인터페이스를 구현한 클래스가 생성되면 그 클래스에서 사용할 기본 기능입니다.
- 디폴트 메서드를 선언할 때는 default 예약어를 사용합니다.
- 그러면 예를 통해서 디폴트 메서드 기능을 더 자세하게 알아봅시다.
ublic interface Calc {
double PI = 3.14; // public static final 이 생략되어 있습니다. 인터페이스에서 선언한 변수는 컴파일 과정에서 자동으로 상수로 변환됨
int ERROR = -99999;
int add(int num1, int num2); // public abstract 이 생략되어 있다. 인터페이스에서 선언한 메서드는 컴파일 과정에서 자동으로 추상 메서드로 변환됨
int substract(int num1, int num2);
int times(int num1, int num2);
int divide(int num1, int num2);
default void description() {
System.out.println("정수 계산기를 구현합니다.");
}
}
- 디폴트 메서드는 일반 메서드완 똑같이 구현하면 되고, 메서드 자료형 앞에 default 예약어만 써 주면 됩니다.
- 새로 구현한 description( ) 디폴트 메서드를 사용하려면 다음 코드와 같이 인터페이스를 구현한 클래스의 인스턴스를 만들어서 사용해야합니다.
public class CalculatorTest {
public static void main(String[] args) {
int num1 = 10;
int num2 = 5;
CompleteCalc calc = new CompleteCalc();
System.out.println(calc.add(num1, num2));
System.out.println(calc.substract(num1, num2));
System.out.println(calc.times(num1, num2));
System.out.println(calc.divide(num1, num2));
calc.showInfo();
calc.description();
}
}
- 디폴트 메서드는 인터페이스에 이미 구현되어 있으므로 인터페이스를 구현한 추상 클래스 Calculator 나 추상 클래스를 상속받은 CompleteCalc 클래스에서 코드를 구현할 필요가 없습니다.
디폴트 메서드 재정의하기
- 만약 이미 인터페이스에 구현되어 있는 디폴트 메서드가 새로 생성한 클래스에서 원하는 기능과 맞지 않는다면, 하위 클래스에서 디폴트 메서드를 재정의할 수 있습니다.
- 디폴트 메서드의 재정의는 인터페이스를 구현한 클래스나 구현한 클래스를 상속받은 클래스에서도 재정의 가능합니다.
- 재정의 하는 방법은 기존 메서드의 재정의와 완벽히 동일합니다.
정적 메서드
- 정적 메서드는 static 예약어를 사용하여 선언하며 클래스 생성과 무관하게 사용할 수 있습니다.
- 정적 메서드를 사용할 때는 당연스럽게 인터페이스 이름으로 직접 참조하여 사용합니다. (기존 클래스와 같음)
public interface Calc {
double PI = 3.14; // public static final 이 생략되어 있습니다. 인터페이스에서 선언한 변수는 컴파일 과정에서 자동으로 상수로 변환됨
int ERROR = -99999;
int add(int num1, int num2); // public abstract 이 생략되어 있다. 인터페이스에서 선언한 메서드는 컴파일 과정에서 자동으로 추상 메서드로 변환됨
int substract(int num1, int num2);
int times(int num1, int num2);
int divide(int num1, int num2);
default void description() {
System.out.println("정수 계산기를 구현합니다.");
}
static int total(int[] arr) {
int total = 0;
for (int i : arr) {
total += i;
}
return total;
}
}
- 사용할 때는 인터페이스 이름으로 직접 참조하여 사용합니다.
private 메서드
- 자바 9 부터는 인터페이스에 private 메서드를 구현할 수 있습니다.
- private 메서드는 인터페이스를 구현한 클래스에서 사용하거나 재사용할 수 없습니다.
- 따라서 기존에 구현된 코드를 변경하지 않고 인터페이스를 구현한 클래스에서 공통으로 사용하는 경우에 private 메서드로 구현하면 코드 재사용성을 높일 수 있습니다.
- 또한 클라이언트 프로그램에 제공할 기본 기능을 private 메서드로 구현하기도 합니다.
- private 메서드는 코드를 모두 구현해야 하므로 추상 메서드에 private 예약어를 사용할 수는 없지만, static 예약어는 함께 사용할 수 있습니다.
- private static 메서드는 정적 메서드처럼 호출하여 사용합니다.
- 그러면 Calc 인터페이스에 private 메서드와 private static 메서드를 구현하고 이를 디폴트 메서드와 정적 메서드에서 호출하여 사용해보겠습니다.
public interface Calc {
double PI = 3.14; // public static final 이 생략되어 있습니다. 인터페이스에서 선언한 변수는 컴파일 과정에서 자동으로 상수로 변환됨
int ERROR = -99999;
int add(int num1, int num2); // public abstract 이 생략되어 있다. 인터페이스에서 선언한 메서드는 컴파일 과정에서 자동으로 추상 메서드로 변환됨
int substract(int num1, int num2);
int times(int num1, int num2);
int divide(int num1, int num2);
default void description() {
System.out.println("정수 계산기를 구현합니다.");
myMethod(); // 디폴트 메서드에서 private 메서드 호출
}
static int total(int[] arr) {
int total = 0;
for (int i : arr) {
total += i;
}
myStaticMethod(); // 정적 메서드에서 private static 메서드 호출
return total;
}
private void myMethod() { // private 메서드
System.out.println("private 메서드입니다.");
}
private static void myStaticMethod() { // private static 메서드
System.out.println("private static 메서드입니다.");
}
}
public class CalculatorTest {
public static void main(String[] args) {
int num1 = 10;
int num2 = 5;
CompleteCalc calc = new CompleteCalc();
System.out.println(calc.add(num1, num2));
System.out.println(calc.substract(num1, num2));
System.out.println(calc.times(num1, num2));
System.out.println(calc.divide(num1, num2));
calc.showInfo();
calc.description(); // 디폴트 메서드 + 디폴트 메서드에 포함된 private 메서드 실행됨
int[] arr = {1, 2, 3, 4, 5};
Calc.total(arr); // default(정적, static) 메서드에서 private static 실행
}
}