기본 메소드는 JVM의 명령어 세트에 아주 좋은 기능을 추가합니다. 기본 메소드를 사용한 후 라이브러리의 인터페이스에 새 메소드가 추가되면이 인터페이스를 구현하는 사용자 클래스는이 메소드의 기본 구현을 자동으로 얻을 수 있습니다. 사용자가 구현 클래스를 업데이트하려면이 기본 메소드를 무시하고 특정 시나리오에서 더 의미있는 구현으로 바꾸십시오. 더 좋은 점은 사용자가 다시 작성된 메소드에서 인터페이스의 기본 구현을 호출하여 몇 가지 추가 기능을 추가 할 수 있다는 것입니다.
지금까지 모든 것이 꽤 좋습니다. 그러나 기존 Java 인터페이스에 기본 메소드를 추가하면 코드 비 호환성이 발생할 수 있습니다 . 예를 살펴보면 이해하기 쉽습니다. 사용자가 인터페이스 중 하나를 입력으로 구현 해야하는 라이브러리가 있다고 가정합니다.
인터페이스 simpleInput {void foo (); void bar ();} 추상 클래스 SimpleInputAdapter는 simpleInput {@override public void bar () {// 일부 기본 동작 ...}}을 구현합니다.Java 8 이전에, 위의 인터페이스와 해당 어댑터 클래스의 조합은 Java 언어에서 매우 일반적인 패턴이었다. 클래스 라이브러리 개발자는 도서관 소비자의 인코딩 양을 줄이기위한 어댑터를 제공합니다. 그러나이 인터페이스를 제공하는 목적은 실제로 다중 상속과 유사한 관계를 달성하는 것입니다.
사용자 가이 어댑터를 사용한다고 가정 해 봅시다.
Class MyInput 확장 SimpleInputAdapter {@Override public void foo () {// Something ...} @override public void bar () {super.bar (); // 추가로 수행 ...}}이 구현을 통해 사용자는 라이브러리와 상호 작용할 수 있습니다. 이 구현이 기본 구현에 추가 기능을 추가하기 위해 BAR 메소드를 대체하는 방법에 유의하십시오.
그렇다면이 도서관이 Java 8으로 마이그레이션되면 어떻게 될까요? 우선,이 라이브러리는 어댑터 클래스를 버리고이 기능을 기본 메소드로 마이그레이션 할 수 있습니다. 결국,이 인터페이스는 다음과 같습니다.
인터페이스 simpleInput {void foo (); 기본 void bar () {// 일부 기본 동작}}}이 새로운 인터페이스를 사용하면 사용자는 어댑터 클래스 대신이 기본 메소드를 사용하기 위해 코드를 업데이트해야합니다. 어댑터 클래스 대신 새 인터페이스를 사용하면 가장 큰 이점 중 하나는 사용자 가이 어댑터 클래스 대신 다른 클래스를 상속받을 수 있다는 것입니다. 연습을 시작하고 MyInput 클래스를 기본 메소드를 사용하여 변환합시다. 이제 다른 클래스를 상속받을 수 있으므로 추가 타사 기본 클래스를 확장하려고합니다. 이 기본 클래스가하는 일은 여기서 중요하지 않습니다. 이것이 우리의 사용 사례에 적합하다고 가정 해 봅시다.
Class MyInput은 ThirdPartyBaseClass를 확장합니다. SimpleInput {@override public void foo () {// do do something ...} @override public void bar () {simpleinput.super.foo (); // 추가로 수행 ...}}원래 클래스와 동일한 함수를 달성하기 위해 새로운 Java 8 구문을 사용하여 인터페이스의 기본 메소드를 호출했습니다. 마찬가지로, 우리는 MyMethod의 논리를 기본 클래스 Mybase에 넣었습니다. 어깨를 두드린 후에 휴식을 취할 수 있습니다. 리팩토링 후 굉장했습니다!
우리가 사용하는이 라이브러리는 크게 향상되었습니다. 그러나 유지 보수 담당자는 추가 기능을 구현하기 위해 다른 인터페이스를 추가해야합니다. 이 인터페이스를 CompExinput이라고하며 SimpleInput 클래스를 상속하고 추가 메소드를 추가합니다. 일반적으로 기본 메소드를 자신있게 추가 할 수 있다고 여겨지기 때문에 유지 보수 직원은 SimpleInput 클래스의 기본 메소드를 무시하고 사용자에게 더 나은 기본 구현을 제공하기 위해 몇 가지 추가 작업을 추가했습니다. 결국, 이것은 어댑터 클래스를 사용할 때 매우 일반적입니다.
인터페이스 complexInput 확장 simpleInput {void qux (); @override default void bar () {simpleinput.super.bar (); // 너무 복잡해서 더 많은 일을해야합니다 ...}}이 새로운 기능은 매우 좋아 보이므로 ThirdPartyBaseClass 클래스의 관리자 도이 라이브러리를 사용하기로 결정했습니다. 이를 달성하기 위해 그는 ComplexInput 인터페이스에 ThirdPartyBaseClass 클래스를 구현했습니다.
그러나 이것이 MyInput 클래스의 의미는 무엇입니까? ThirdPartyBaseClass 클래스를 상속하기 때문에 ComplexInput 인터페이스는 기본적으로 구현됩니다. 이런 식으로 SimpleInput의 기본 메소드를 호출하는 것은 합법적이지 않습니다. 결과적으로 사용자의 코드는 결국 컴파일 할 수 없습니다. 또한 Java는이 슈퍼 서퍼 방법을 간접 부모 클래스를 불법으로 호출하는 것으로 간주하기 때문에이 방법은 전화가 완전히 불가능합니다. ComplexInput 인터페이스의 기본 메소드 만 호출 할 수 있습니다. 그러나 먼저 MyInput 클래스 에서이 인터페이스를 명시 적으로 구현해야합니다. 이 라이브러리 사용자의 경우 이러한 변경 사항은 완전히 예상치 못한 것입니다.
(참고 : 간단히 말하면 실제로는 다음과 같습니다.
인터페이스 a {default void test () {}} 인터페이스 b는 {default void test () {}} public class test 구현 b {public void test () {b.super.test (); //a.super.test (); 오류}}물론이 글을 쓰면 사용자는 적극적으로 B 인터페이스를 구현하기로 결정했습니다. 이 기사의 예제는 기본 클래스를 소개 했으므로 라이브러리와 기본 클래스에서 겉보기에는 실질적인 변경이 이루어졌지만 실제로 사용자 코드를 컴파일 할 수 없었습니다).
이상하게도 Java는 런타임에이를 구별하지 않습니다. JVM의 유효성 검사기를 사용하면 컴파일 된 클래스가 SimpleInput :: Foo 메소드를 호출 할 수 있지만,로드 된 클래스는 업데이트 된 3 분기 버전의 ThirdPartyBaseClass를 상속하고 ComplexInput 인터페이스를 암시 적으로 구현합니다. 비난을 원한다면 컴파일러를 비난 할 수 있습니다. (참고 : 컴파일러 및 런타임 동작이 일관성이 없습니다)
그래서 우리는 그것으로부터 무엇을 배웠습니까? 간단히 말해서 다른 인터페이스에서 원래 인터페이스의 기본 메소드를 무시하지 마십시오. 다른 기본 메소드로 다시 작성하지 말고 약간의 추상 방법으로 다시 작성하지 마십시오. 요컨대, 기본 메소드를 사용할 때는 매우 신중해야합니다. 비록 Java의 기존 컬렉션 라이브러리의 인터페이스를 개선하기가 더 쉬워 지지만 클래스의 상속 구조에서 메소드 호출을 할 수 있으므로 본질적으로 복잡성을 증가시킬 수 있습니다. Java 7 이전에는 선형 클래스 계층을 가로 지르고 실제 통화 코드를 살펴 봐야했습니다. 실제로 필요하다고 생각되면 기본 메소드를 사용하십시오.
위의 내용은 왜 Java 8의 기본 메소드를주의해서 사용해야하는지에 대한 자세한 설명입니다. 모든 사람의 학습에 도움이되기를 바랍니다.