Java Language
기본 메소드
수색…
소개
Java 8에 도입 된 Default Method 는 개발자가이 인터페이스의 기존 구현을 깨지 않고 인터페이스에 새로운 메소드를 추가 할 수있게 해줍니다. 인터페이스를 구현하는 클래스가 그 메소드의 구현을 제공하지 못할 때, 인터페이스가 디폴트로서 사용되는 구현을 정의 할 수있는 유연성을 제공합니다.
통사론
- 공용 기본 무효 methodName () {/ * 메서드 본문 * /}
비고
기본 메소드
- 인터페이스 내에서 사용할 수 있으므로 기존 서브 클래스가이를 구현하지 않고도 동작을 도입 할 수 있습니다.
- 하위 클래스 또는 하위 인터페이스로 재정의 할 수 있습니다.
- java.lang.Object 클래스의 메소드를 오버라이드 (override) 할 수 없습니다.
- 둘 이상의 인터페이스를 구현하는 클래스가 각 인터페이스에서 동일한 메소드 서명을 사용하여 기본 메소드를 상속하는 경우 다중 상속을 해결할 때 기본 메소드가 아닌 것처럼 자체 인터페이스를 재정의하고 제공해야합니다.
- 기존 구현을 깨지 않고 동작을 도입하기위한 것이지만 새로 도입 된 기본 메소드와 동일한 메소드 서명을 사용하는 정적 메소드가있는 기존 하위 클래스는 여전히 손상됩니다. 그러나 수퍼 클래스에 인스턴스 메소드를 도입 할 경우에도 마찬가지입니다.
정적 메소드
- 인터페이스 내에서 사용할 수 있으며 주로 기본 메서드의 유틸리티 메서드로 사용됩니다.
- 하위 클래스 또는 하위 인터페이스 (해당 하위 클래스는 숨김)로 재정의 할 수 없습니다. 그러나 지금도 정적 메소드의 경우와 마찬가지로 각 클래스 또는 인터페이스마다 고유 한 메소드가있을 수 있습니다.
- java.lang.Object 클래스의 인스턴스 메소드를 오버라이드 (override) 할 수 없습니다 (현재는 서브 클래스에서도 마찬가지입니다).
다음은 하위 클래스와 수퍼 클래스 간의 상호 작용을 요약 한 표입니다.
- | SUPER_CLASS-INSTANCE-METHOD | SUPER_CLASS-STATIC-METHOD |
---|---|---|
SUB_CLASS-INSTANCE-METHOD | 우선 적용 | 생성 - 컴파일 타임 오류 |
SUB_CLASS-STATIC-METHOD | 생성 - 컴파일 타임 오류 | 숨 깁니다 |
다음은 인터페이스와 구현 클래스 간의 상호 작용을 요약 한 표입니다.
- | 인터페이스 - 기본 메소드 | 인터페이스 - 정적 메소드 |
---|---|---|
IMPL_CLASS-INSTANCE-METHOD | 우선 적용 | 숨 깁니다 |
IMPL_CLASS-STATIC-METHOD | 생성 - 컴파일 타임 오류 | 숨 깁니다 |
참고 문헌 :
- http://www.journaldev.com/2752/java-8-interface-changes-static-method-default-method
- https://docs.oracle.com/javase/tutorial/java/IandI/override.html
기본 메소드의 기본 사용법
/**
* Interface with default method
*/
public interface Printable {
default void printString() {
System.out.println( "default implementation" );
}
}
/**
* Class which falls back to default implementation of {@link #printString()}
*/
public class WithDefault
implements Printable
{
}
/**
* Custom implementation of {@link #printString()}
*/
public class OverrideDefault
implements Printable {
@Override
public void printString() {
System.out.println( "overridden implementation" );
}
}
다음 진술
new WithDefault().printString();
new OverrideDefault().printString();
이 출력을 생성합니다.
default implementation
overridden implementation
기본 메소드 내 다른 인터페이스 메소드 액세스
기본 메소드 내에서 다른 인터페이스 메소드에 액세스 할 수도 있습니다.
public interface Summable {
int getA();
int getB();
default int calculateSum() {
return getA() + getB();
}
}
public class Sum implements Summable {
@Override
public int getA() {
return 1;
}
@Override
public int getB() {
return 2;
}
}
다음 명령문은 3 을 인쇄합니다.
System.out.println(new Sum().calculateSum());
기본 메소드는 인터페이스 정적 메소드와 함께 사용할 수 있습니다.
public interface Summable {
static int getA() {
return 1;
}
static int getB() {
return 2;
}
default int calculateSum() {
return getA() + getB();
}
}
public class Sum implements Summable {}
다음 문은 3을 인쇄합니다.
System.out.println(new Sum().calculateSum());
오버라이드 된 기본 메소드에 클래스 구현시 액세스
클래스에서 super.foo()
는 슈퍼 클래스에서만 볼 수 있습니다. super
인터페이스에서 기본 구현을 호출하려면 super
라는 인터페이스 이름을 Fooable.super.foo()
로 한정해야합니다.
public interface Fooable {
default int foo() {return 3;}
}
public class A extends Object implements Fooable {
@Override
public int foo() {
//return super.foo() + 1; //error: no method foo() in java.lang.Object
return Fooable.super.foo() + 1; //okay, returns 4
}
}
기본 방법을 사용하는 이유는 무엇입니까?
간단한 대답은 기존 구현을 깨지 않고 기존 인터페이스를 발전시킬 수 있다는 것입니다.
예를 들어, 20 년 전에 발행 한 Swim
인터페이스가 있습니다.
public interface Swim {
void backStroke();
}
우리는 훌륭한 일을했으며, 인터페이스는 매우 유명합니다. 전 세계에서 많은 구현이 이루어졌으며 소스 코드를 제어 할 수 없습니다.
public class FooSwimmer implements Swim {
public void backStroke() {
System.out.println("Do backstroke");
}
}
20 년이 지난 후에는 인터페이스에 새로운 기능을 추가하기로 결정했지만 인터페이스가 고정 된 것처럼 보이므로 기존 구현을 깨뜨릴 수 있습니다.
다행스럽게도 Java 8은 Default 메소드 라는 새로운 기능을 도입했습니다 .
이제 Swim
인터페이스에 새로운 메소드를 추가 할 수 있습니다.
public interface Swim {
void backStroke();
default void sideStroke() {
System.out.println("Default sidestroke implementation. Can be overridden");
}
}
이제 인터페이스의 모든 기존 구현이 여전히 작동 할 수 있습니다. 그러나 가장 중요한 것은 새로 추가 된 메서드를 자신의 시간에 구현할 수 있다는 것입니다.
이러한 변화의 가장 큰 이유 중 하나는 자바 컬렉션 프레임 워크에있다. 오라클은 Iterable을 구현 한 기존 코드를 모두 깨지 않으면 서 기존 Iterable 인터페이스에 foreach
메소드를 추가 할 수 없었습니다. 디폴트 메소드를 추가함으로써 기존의 Iterable 구현은 디폴트 구현을 상속받습니다.
클래스, 추상 클래스 및 인터페이스 메소드 우선 순위
추상 선언을 포함한 클래스의 구현은 모든 인터페이스 기본값보다 우선합니다.
- 추상 클래스 메소드는 인터페이스 기본 메소드 보다 우선합니다.
public interface Swim {
default void backStroke() {
System.out.println("Swim.backStroke");
}
}
public abstract class AbstractSwimmer implements Swim {
public void backStroke() {
System.out.println("AbstractSwimmer.backStroke");
}
}
public class FooSwimmer extends AbstractSwimmer {
}
다음 진술
new FooSwimmer().backStroke();
생산 가능
AbstractSwimmer.backStroke
- 클래스 메소드가 인터페이스 기본 메소드 보다 우선 함
public interface Swim {
default void backStroke() {
System.out.println("Swim.backStroke");
}
}
public abstract class AbstractSwimmer implements Swim {
}
public class FooSwimmer extends AbstractSwimmer {
public void backStroke() {
System.out.println("FooSwimmer.backStroke");
}
}
다음 진술
new FooSwimmer().backStroke();
생산 가능
FooSwimmer.backStroke
기본 메소드 다중 상속 충돌
다음 예제를 고려하십시오.
public interface A {
default void foo() { System.out.println("A.foo"); }
}
public interface B {
default void foo() { System.out.println("B.foo"); }
}
여기 선언이 인터페이스입니다 default
방법 foo
같은 서명은.
새로운 인터페이스에서이 두 인터페이스를 extend
하려고 시도하면 Java에서이 충돌을 명시 적으로 해결해야하므로 두 인터페이스 중 하나를 선택해야합니다.
먼저 abstract
와 동일한 시그니처로 메소드 foo
를 선언 할 수 있습니다.이 메소드는 A
와 B
동작을 오버라이드합니다.
public interface ABExtendsAbstract extends A, B {
@Override
void foo();
}
class
ABExtendsAbstract
를 implement
하면 foo
구현을 제공해야합니다.
public class ABExtendsAbstractImpl implements ABExtendsAbstract {
@Override
public void foo() { System.out.println("ABImpl.foo"); }
}
둘째 , 완전히 새로운 default
구현을 제공 할 수 있습니다. 또한 클래스를 구현할 때 재정의 된 기본 메소드 에 액세스 하여 A
및 B
foo
메소드의 코드를 재사용 할 수 있습니다.
public interface ABExtends extends A, B {
@Override
default void foo() { System.out.println("ABExtends.foo"); }
}
class
ABExtends
를 implement
하면 foo
구현을 제공 할 필요가 not
.
public class ABExtendsImpl implements ABExtends {}