JavaRush /Java Blog /Random-KO /Java 8의 기본 메소드: 할 수 있는 것과 할 수 없는 것
Spitfire
레벨 33

Java 8의 기본 메소드: 할 수 있는 것과 할 수 없는 것

Random-KO 그룹에 게시되었습니다
Peter Verhas 가 2014년 4월에 쓴 기사 의 번역입니다 . Java 8의 기본 메소드: 할 수 있는 것과 할 수 없는 것  - 1번역자로부터: " 기본 메소드 "라는 용어가 방금 Java에 등장했는데 이에 대한 러시아어 번역이 확립되어 있는지 확실하지 않습니다. 이상적이지는 않지만 "기본 방법"이라는 용어를 사용하겠습니다. 보다 성공적인 번역에 대해 논의해 보시기 바랍니다.

기본 방법은 무엇입니까

이제 Java 8 릴리스에서는 인터페이스를 구현하는 클래스와 인터페이스가 계속 호환되도록 인터페이스에 새 메소드를 추가할 수 있습니다. 키예프에서 뉴욕까지 많은 프로그래머가 사용하는 라이브러리를 개발하는 경우 이는 매우 중요합니다. Java 8 이전에는 라이브러리에 인터페이스를 정의한 경우 업데이트 시 인터페이스를 실행하는 일부 애플리케이션이 중단될 위험 없이 인터페이스에 메서드를 추가할 수 없었습니다. 그렇다면 Java 8에서는 더 이상 이것을 두려워할 수 없습니까? 아니 당신은 할 수 없습니다. 인터페이스에 기본 메서드를 추가하면 일부 클래스를 사용할 수 없게 될 수 있습니다. 먼저 기본 메서드의 좋은 점을 살펴보겠습니다. Java 8에서는 메소드를 인터페이스에서 직접 구현할 수 있습니다. (이제 인터페이스의 정적 메소드도 구현할 수 있지만 이는 또 다른 이야기입니다.) 인터페이스에 구현된 메소드를 기본 메소드라고 하며 default 키워드로 표시 됩니다 . 클래스가 인터페이스를 구현하는 경우 인터페이스에 구현된 메서드를 구현할 수 있지만 반드시 구현해야 하는 것은 아닙니다. 클래스는 기본 구현을 상속합니다. 이것이 클래스가 구현하는 인터페이스를 변경할 때 클래스를 수정할 필요가 없는 이유입니다.

다중 상속?

클래스가 둘 이상의 인터페이스(예: 두 개)를 구현하고 동일한 기본 메서드를 구현하는 경우 상황이 더 복잡해집니다. 클래스는 어떤 메소드를 상속받나요? 대답은 없습니다. 이 경우 클래스는 메서드 자체를 구현해야 합니다(직접 또는 다른 클래스에서 상속받아). 하나의 인터페이스에만 기본 메서드가 있고 다른 인터페이스에는 동일한 메서드가 추상인 경우 상황은 비슷합니다. Java 8은 규율을 적용하고 모호한 상황을 피하려고 노력합니다. 둘 이상의 인터페이스에서 메소드가 선언된 경우 클래스는 기본 구현을 상속하지 않으므로 컴파일 오류가 발생합니다. 그러나 클래스가 이미 컴파일된 경우에는 컴파일 오류가 발생하지 않을 수 있습니다. 이 점에 있어서 Java 8은 충분히 강력하지 않습니다. 이에 대해서는 논의하고 싶지 않은 이유가 있습니다(예: Java 릴리스가 이미 출시되었고 토론 시간이 오래 지났으며 일반적으로 이곳은 논의할 장소가 아닙니다).
  • 두 개의 인터페이스가 있고 클래스가 두 인터페이스를 모두 구현한다고 가정해 보겠습니다.
  • 인터페이스 중 하나가 기본 메서드 m()을 구현합니다.
  • 모든 인터페이스와 클래스를 컴파일합니다.
  • m() 메서드가 없는 인터페이스를 추상 메서드로 선언하여 변경합니다.
  • 수정된 인터페이스만 컴파일합니다.
  • 수업을 시작하세요.
Java 8의 기본 메소드: 할 수 있는 것과 할 수 없는 것  - 2이 경우 수업이 작동합니다. 업데이트된 인터페이스로 컴파일할 수는 없지만 이전 버전으로 컴파일되었으므로 작동합니다. 지금
  • 추상 m() 메서드로 인터페이스를 변경하고 기본 구현을 추가합니다.
  • 수정된 인터페이스를 컴파일합니다.
  • 실행 클래스: 오류.
메서드의 기본 구현을 제공하는 두 개의 인터페이스가 있는 경우 해당 메서드는 클래스 자체에서 구현되지 않는 한(역시 자체적으로 또는 다른 클래스에서 상속됨) 클래스에서 호출될 수 없습니다. Java 8의 기본 메소드: 할 수 있는 것과 할 수 없는 것  - 삼클래스 호환 가능. 수정된 인터페이스로 로드할 수 있습니다. 두 인터페이스 모두에 기본 구현이 있는 메서드가 호출될 때까지 실행될 수도 있습니다.

예제 코드

Java 8의 기본 메소드: 할 수 있는 것과 할 수 없는 것  - 4위 내용을 설명하기 위해 C.java 클래스에 대한 테스트 디렉터리와 I1.java 및 I2.java 파일의 인터페이스에 대한 하위 디렉터리 3개를 만들었습니다. 테스트의 루트 디렉토리에는 C.java 클래스의 소스 코드가 포함되어 있습니다. 기본 디렉터리에는 실행 및 컴파일에 적합한 인터페이스 버전이 포함되어 있습니다. 인터페이스 I1에는 기본 메서드 m()이 있습니다. I2 인터페이스에는 아직 메서드가 없습니다. 클래스에는 메서드가 있으므로 main이를 실행하여 테스트할 수 있습니다. 명령줄 인수가 있는지 확인하므로 m().
~/github/test$ cat C.java
public class C implements I1, I2 {
  public static void main(String[] args) {
    C c = new C();
    if( args.length == 0 ){
      c.m();
    }
  }
}
~/github/test$ cat base/I1.java
public interface I1 {
  default void m(){
    System.out.println("hello interface 1");
  }
}
~/github/test$ cat base/I2.java
public interface I2 {
}
명령줄에서 클래스를 컴파일하고 실행할 수 있습니다.
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
Compatible 디렉토리에는 m() 메소드를 추상 메소드로 선언하는 I2 인터페이스 버전과 기술적인 이유로 수정되지 않은 I1.java 사본이 포함되어 있습니다.
~/github/test$ cat compatible/I2.java

public interface I2 {
  void m();
}
이러한 세트는 C 클래스를 컴파일하는 데 사용할 수 없습니다.
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
       ^
1 error
오류 메시지는 매우 정확합니다. 그러나 이전 컴파일의 C.class가 있고 인터페이스를 호환 가능한 디렉터리로 컴파일하면 클래스를 실행하는 데 계속 사용할 수 있는 두 개의 인터페이스가 있습니다.
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
세 번째 디렉터리에는 wrong다음 메서드도 선언하는 버전 I2가 포함되어 있습니다 m().
~/github/test$ cat wrong/I2.java
public interface I2 {
  default void m(){
    System.out.println("hello interface 2");
  }
}
컴파일에 대해 걱정할 필요조차 없습니다. 메서드가 두 번 선언되더라도 m() 메서드가 호출될 때까지 클래스를 계속 사용하고 실행할 수 있습니다. 이것이 바로 다음을 위한 명령줄 인수가 필요한 것입니다.
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
    at C.m(C.java)
    at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$

결론

라이브러리를 Java 8로 이식하고 기본 메소드를 포함하도록 인터페이스를 변경하면 아마도 아무런 문제가 없을 것입니다. 적어도 그것은 Java 8 라이브러리 개발자가 기능을 추가하면서 기대하는 것입니다. 라이브러리를 사용하는 애플리케이션은 기본 메서드가 없는 Java 7용으로 여전히 라이브러리를 사용하고 있습니다. 여러 개의 라이브러리를 함께 사용하면 충돌이 발생할 가능성이 있습니다. 그것을 피하는 방법? 이전과 동일한 방식으로 라이브러리의 API를 디자인합니다. 기본 메소드의 기능에 의존하여 안주하지 마십시오. 그들은 최후의 수단입니다. 다른 인터페이스와의 충돌을 피하기 위해 이름을 신중하게 선택하십시오. 이 기능을 활용한 Java 개발이 어떻게 발전할지 살펴보겠습니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION