자바 의 기본 방법(Default Methods)

【전】자바 의 기본 방법(Default Methods)
다음으로 전송:http://ebnbin.com/2015/12/20/java-8-default-methods/
자바 8 은 새로운 언어 특성 인 기본 방법(Default Methods)을 도입 했다.
Default methods enable new functionality to be added to the interfaces of libraries and ensure binary compatibility with code written for older versions of those interfaces.
기본 방법 은 기 존 라 이브 러 리 인터페이스 에 새로운 기능 을 추가 할 수 있 으 며,기 존 버 전 인터페이스 로 작 성 된 코드 와 의 바 이 너 리 호환성 을 확보 할 수 있 습 니 다.
기본 방법 은 인터페이스 에 서명 하기 전에 추가 하 는 것 입 니 다.  default  키워드 의 실현 방법.
간단 한 예
  1. interface InterfaceA {
  2. default void foo () {
  3. System . out . println ( "InterfaceA foo" );
  4. }
  5. }
  6. class ClassA implements InterfaceA {
  7. }
  8. public class Test {
  9. public static void main ( String [] args ) {
  10. new ClassA (). foo (); // :“InterfaceA foo”
  11. }
  12. }
ClassA  결코 실현 되 지 않 았 다.  InterfaceA  인터페이스의  foo  방법 인터페이스 에서 제공 되 었 습 니 다.  InterfaceA  방법의 기본 구현 이 므 로 직접 호출 할 수 있 습 니 다.  foo  클래스  ClassA  방법
왜 기본 적 인 방법 이 있어 야 합 니까?
자바 8 이전 인터페이스 와 실제 클래스 사이 의 결합 도 너무 높 습 니 다(tightly coupled).인터페이스 에 방법 을 추가 해 야 할 때 모든 실현 류 는 이에 따라 수정 해 야 합 니 다.기본 적 인 방법 은 이 문 제 를 해결 했다.기 존의 인터페이스의 실현 을 파괴 하지 않 고 인터페이스 에 새로운 방법 을 추가 할 수 있다.이것 은 lambda 표현 식 이 자바 8 언어의 중요 한 특성 으로 나타 날 때 낡은 인 터 페 이 스 를 업그레이드 하고 뒤로 호 환(backward compatibility)하 는 경 로 를 제공 합 니 다.foo이것/이것 
  1. String [] array = new String [] {
  2. "hello" ,
  3. ", " ,
  4. "world" ,
  5. };
  6. List < String > list = Arrays . asList ( array );
  7. list . forEach ( System . out :: println ); // jdk 1.8
 방법 은 jdk 1.8 에 추 가 된 인터페이스 기본 방법 입 니 다.기본 적 인 방법 이 도입 되 었 기 때문에 그렇지 않 습 니 다.  forEach  인터페이스 에 추가  Iterable  방법 은 모든 것 을 수정 해 야 한다.  forEach  인터페이스의 실현 류.
아래 코드 는 jdk 1.8 의  Iterable  인터페이스의  Iterable  기본 방법:forEach기본 방법의 계승
다른 방법 과 마찬가지 로 인터페이스 기본 방법 도 계승 할 수 있다.
  1. package java . lang ;
  2. import java.util.Objects ;
  3. import java.util.function.Consumer ;
  4. public interface Iterable < T > {
  5. default void forEach ( Consumer super T > action ) {
  6. Objects . requireNonNull ( action );
  7. for ( T t : this ) {
  8. action . accept ( t );
  9. }
  10. }
  11. }
인터페이스 기본 방법의 계승 은 세 가지 상황 으로 나 뉜 다. 
  1. interface InterfaceA {
  2. default void foo () {
  3. System . out . println ( "InterfaceA foo" );
  4. }
  5. }
  6. interface InterfaceB extends InterfaceA {
  7. }
  8. interface InterfaceC extends InterfaceA {
  9. @Override
  10. default void foo () {
  11. System . out . println ( "InterfaceC foo" );
  12. }
  13. }
  14. interface InterfaceD extends InterfaceA {
  15. @Override
  16. void foo ();
  17. }
  18. public class Test {
  19. public static void main ( String [] args ) {
  20. new InterfaceB () {}. foo (); // :“InterfaceA foo”
  21. new InterfaceC () {}. foo (); // :“InterfaceC foo”
  22. new InterfaceD () {
  23. @Override
  24. public void foo () {
  25. System . out . println ( "InterfaceD foo" );
  26. }
  27. }. foo (); // :“InterfaceD foo”
  28. // lambda
  29. (( InterfaceD ) () -> System . out . println ( "InterfaceD foo" )). foo ();
  30. }
  31. }
 인터페이스 인터페이스  InterfaceB  인터페이스):
  • 기본 방법 을 덮어 쓰 지 않 고 부모 인터페이스 에서 방법 을 가 져 오 는 기본 구현 입 니 다.
  • 복사 기본 방법 은 클래스 간 의 복사 규칙 과 유사 합 니 다.
  • 복사 기본 방법 을 다시 추상 적 인 방법 으로 설명 하면 새로운 인터페이스의 하위 클래스 는 반드시 다시 복사 하고 이 추상 적 인 방법 을 실현 해 야 한다.

  • 기본 방법의 다 중 계승
    자바 가 사용 하 는 것 은 단일 계승,다 중 실현 체 제 를 사용 하 는 것 으로 다 중 계승 이 가 져 온 호출 의 미 를 피 하 는 문제 이다.인터페이스의 하위 클래스 가 같은 서명 방법 을 동시에 가지 고 있 을 때 충돌 을 해결 하 는 방안 을 고려 해 야 한다.InterfaceC...에 있다  InterfaceD  클래스 
    1. interface InterfaceA {
    2. default void foo () {
    3. System . out . println ( "InterfaceA foo" );
    4. }
    5. }
    6. interface InterfaceB {
    7. default void bar () {
    8. System . out . println ( "InterfaceB bar" );
    9. }
    10. }
    11. interface InterfaceC {
    12. default void foo () {
    13. System . out . println ( "InterfaceC foo" );
    14. }
    15. default void bar () {
    16. System . out . println ( "InterfaceC bar" );
    17. }
    18. }
    19. class ClassA implements InterfaceA , InterfaceB {
    20. }
    21. //
    22. //class ClassB implements InterfaceB, InterfaceC {
    23. //}
    24. class ClassB implements InterfaceB , InterfaceC {
    25. @Override
    26. public void bar () {
    27. InterfaceB . super . bar (); // InterfaceB bar
    28. InterfaceC . super . bar (); // InterfaceC bar
    29. System . out . println ( "ClassB bar" ); //
    30. }
    31. }
     인터페이스  ClassA  인터페이스 에 있 는 방법 은 나 쁜 뜻 이 존재 하지 않 고 직접적 으로 많이 실현 할 수 있다.
    ...에 있다  InterfaceA  클래스  InterfaceB  인터페이스  ClassB  인터페이스 에 같은 서명 이 있 습 니 다.  InterfaceB  방법,충돌 을 수 동 으로 해결 해 야 합 니 다.나 쁜 뜻 이 존재 하 는 방법 을 덮어 쓰 고 사용 할 수 있다.  InterfaceC  필요 한 인터페이스 기본 방법 을 수 동 으로 호출 합 니 다.
    인터페이스 계승 행위 충돌 시 해결 규칙
    주의해 야 할 것 은 이런 상황 이다.foo...해 야 한다  InterfaceName.super.methodName();  클래스 다 실현 
    1. interface InterfaceA {
    2. default void foo () {
    3. System . out . println ( "InterfaceA foo" );
    4. }
    5. }
    6. interface InterfaceB extends InterfaceA {
    7. @Override
    8. default void foo () {
    9. System . out . println ( "InterfaceB foo" );
    10. }
    11. }
    12. //
    13. class ClassA implements InterfaceA , InterfaceB {
    14. }
    15. class ClassB implements InterfaceA , InterfaceB {
    16. @Override
    17. public void foo () {
    18. // InterfaceA.super.foo(); //
    19. InterfaceB . super . foo ();
    20. }
    21. }
     인터페이스  ClassA  인 터 페 이 스 를 연결 할 때 방법 이름 의 오류 가 발생 하지 않 습 니 다....해 야 한다  InterfaceA  복사  InterfaceB  방법 시 통과 불가  ClassB  호출  foo  인터페이스의  InterfaceA.super.foo(); 방법.
    ...때문에  InterfaceA  인터페이스 가 계승 되 었 다  foo  그러면  InterfaceB  인 터 페 이 스 는 모든 것 을 포함 하고 있 을 것 이다.  InterfaceA  인터페이스 의 필드 방법 때문에 동시에 실현 되 었 다.  InterfaceB  인터페이스  InterfaceA  인터페이스의 클래스 와 하 나 는 실현 되 었 다.  InterfaceA  인터페이스의 종 류 는 완전히 등가 이다.
    이것 은 이해 하기 쉽다.  InterfaceB  ...과  InterfaceB  등가.
    또는 다른 방식 으로 이해 하기:class SimpleDateFormat extends DateFormat여기  class SimpleDateFormat extends DateFormat, Object  같은 호출 은 
    1. class ClassC {
    2. public void foo () {
    3. System . out . println ( "ClassC foo" );
    4. }
    5. }
    6. class ClassD extends ClassC {
    7. @Override
    8. public void foo () {
    9. System . out . println ( "ClassD foo" );
    10. }
    11. }
    12. public class Test {
    13. public static void main ( String [] args ) {
    14. ClassC classC = new ClassD ();
    15. classC . foo (); // :“ClassD foo”
    16. }
    17. }
     클래스  classC.foo();  방법,인쇄 결 과 는"ClassD"입 니 다.왜냐하면  foo  클래스  ClassD foo  방법  ClassC  클래스 에 복사 되 었 습 니 다.
    위 에 있어 요.  foo  클래스 에서 방법 이름 의 다른 의미 가 나타 나 지 않 는 이 유 는 이른바'잘못된 의미 가 존재 한다'는 방법 이 모두  ClassD  인터페이스 인터페이스 의'동명 방법'은 계승 일 뿐이다.  ClassA  인터페이스 로 와 서 그것 을 복사 했다.InterfaceA  클래스 가 실 현 된 두 인 터 페 이 스 는 서로 무관 한 인터페이스 가 아니 기 때문에 동명 의 다른 의미 방법 은 존재 하지 않 는 다.
    덮어 쓰 는 것 은 부류 의 방법 에 대한 차단 을 의미 하 는데 이것 도 역시  InterfaceB  의 설계 의도 중 하나 다.그래서 이 루어 지고 있 습 니 다.  InterfaceA  인터페이스 클래스 에서 복 사 된 것 에 접근 할 수 없습니다.  ClassA  인터페이스의  Override  방법
    이것 은 인터페이스 계승 행위 가 충돌 할 때의 규칙 중 하나 이다.즉, 다른 형식 으로 덮어 쓰 는 방법 은 무 시 됩 니 다.
    하면,만약,만약...  InterfaceB  인터페이스의  InterfaceA  방법 은 사용자 정의 새로운 인터페이스 로 만 계승 할 수 있 습 니 다.  foo  인터페이스 및 디 스 플레이 복사  InterfaceA  방법  foo  호출  InterfaceA  인터페이스의  foo  방법,마지막 으로 실현 류 를 동시에 실현 하도록 한다.  InterfaceA.super.foo();  인터페이스 와 사용자 정의 새 인터페이스,코드 는 다음 과 같 습 니 다.InterfaceA주의! 비록...일지 라 도  foo  인터페이스의  InterfaceB  방법 은 부모 인터페이스의 기본 구현 방법 만 호출 했 을 뿐,이 복사 생략 할 수 없다.그렇지 않 으 면 
    1. interface InterfaceA {
    2. default void foo () {
    3. System . out . println ( "InterfaceA foo" );
    4. }
    5. }
    6. interface InterfaceB extends InterfaceA {
    7. @Override
    8. default void foo () {
    9. System . out . println ( "InterfaceB foo" );
    10. }
    11. }
    12. interface InterfaceC extends InterfaceA {
    13. @Override
    14. default void foo () {
    15. InterfaceA . super . foo ();
    16. }
    17. }
    18. class ClassA implements InterfaceB , InterfaceC {
    19. @Override
    20. public void foo () {
    21. InterfaceB . super . foo ();
    22. InterfaceC . super . foo ();
    23. }
    24. }
     인터페이스  InterfaceC  인터페이스의 암시 적  foo  방법 역시  InterfaceC  인터페이스 가 덮어 쓰 여 차단 되 어 호출 될 수 있 습 니 다.  InterfaceA  시간 착오.
    이 예 를 통 해 기본 적 인 방법 을 사용 하기 전에 그것 이 정말 필요 한 지 를 고려 해 야 한 다 는 것 을 알 아야 한다....때문에 기본 적 인 방법 은 프로그램 에 나 쁜 의 미 를 가 져 오고 복잡 한 계승 시스템 에서 컴 파일 오류 가 발생 하기 쉽다.기본 적 인 방법 을 남용 하면 코드 에 예상 치 못 하고 이상 한 오 류 를 가 져 올 수 있다.
    인터페이스 와 추상 류
    인터페이스 계승 행위 가 충돌 할 때 또 다른 규칙 은 이러한 방법 성명 이 인터페이스 기본 방법 보다 우선 하 다 는 것 이다.이 방법 이 구체 적 이 든 추상 적 이 든 간 에.foo InterfaceB  클래스 에 수 동 복사 가 필요 하지 않 습 니 다.  InterfaceC.super.foo()  방법 
    1. interface InterfaceA {
    2. default void foo () {
    3. System . out . println ( "InterfaceA foo" );
    4. }
    5. default void bar () {
    6. System . out . println ( "InterfaceA bar" );
    7. }
    8. }
    9. abstract class AbstractClassA {
    10. public abstract void foo ();
    11. public void bar () {
    12. System . out . println ( "AbstractClassA bar" );
    13. }
    14. }
    15. class ClassA extends AbstractClassA implements InterfaceA {
    16. @Override
    17. public void foo () {
    18. InterfaceA . super . foo ();
    19. }
    20. }
    21. public class Test {
    22. public static void main ( String [] args ) {
    23. ClassA classA = new ClassA ();
    24. classA . foo (); // :“InterfaceA foo”
    25. classA . bar (); // :“AbstractClassA bar”
    26. }
    27. }
     상속  ClassA 추상 류 에 존재 합 니 다.  bar  방법의 실현  ClassA  추상 적  AbstractClassA  방법 은 추상 적 이기 때문에  bar  클래스 에서 반드시 실현 해 야 합 니 다.  AbstractClassA  방법
    자바 8 의 인터페이스 기본 방법 은 추상 적 인 것 처럼 방법의 실현 을 제공 할 수 있 지만 그들 둘 은 여전히 서로 대체 할 수 없 는:
  • 인 터 페 이 스 는 여러 가지 유형 에 의 해 실 현 될 수 있 고 추상 류 는 한 가지 로 만 계승 할 수 있다.
  • 인터페이스 에 없습니다.  foo  포인터,구조 함수 가 없 으 면 인 스 턴 스 필드(인 스 턴 스 변수)나 인 스 턴 스 방법 이 있어 서 저장 할 수 없습니다. 상태(state),추상 적 인 방법 에서 가능 합 니 다.
  • 추상 류 는 자바 8 의 lambda 표현 식 에서 사용 할 수 없습니다.
  • 디자인 이념 에서 인 터 페 이 스 는 “like-a” 관계 “is-a” 관계

  • 인터페이스 정적 방법
    기본 방법 을 제외 하고 자바 8 은 인터페이스 에서 정적 방법 을 정의 할 수 있 습 니 다.ClassA기타 주의 점
  • foo  키 워드 는 인터페이스 에서 만 사용 할 수 있 습 니 다.  this  문장의 
    1. interface InterfaceA {
    2. default void foo () {
    3. printHelloWorld ();
    4. }
    5. static void printHelloWorld () {
    6. System . out . println ( "hello, world" );
    7. }
    8. }
    9. public class Test {
    10. public static void main ( String [] args ) {
    11. InterfaceA . printHelloWorld (); // :“hello, world”
    12. }
    13. }
     분기)추상 류 에 사용 할 수 없다.
  • 인터페이스 기본 방법 은 복사 할 수 없습니다.  default  클래스  switchdefault  화해시키다  Object  방법
  • 인터페이스 의 정적 방법 은 반드시  equals  의,hashCode 장식 부 호 는 생략 할 수 있 습 니 다.toString 수식 부 는 생략 할 수 없다.
  • 자바 8 환경 을 사용 하 더 라 도 일부 IDE 는 일부 코드 의 실시 간 컴 파일 알림 에 이상 한 알림 이 나타 날 수 있 으 므 로 IDE 에 지나치게 의존 하지 마 십시오.
  • 좋은 웹페이지 즐겨찾기