Java의 기본 방법 확인

5008 단어 Java기본 방법
왜 기본 방법이 있습니까?
자바 8이 곧 다가온다. 비록 발표 기한이 연기되었지만, 우리는 그것이 최종적으로 발표될 때lambdas 표현식을 지원할 것이라고 확신한다.앞에서 언급한 바와 같이 우리는 이전에 이 주제에 대해 적지 않은 토론을 했지만 lambdas 표현식은 자바 8에서 유일하게 바뀐 게임 규칙이 아니다.
Java 8이 출시되고 lambda가 포함되어 있다고 가정합니다.지금 당신은 lambda를 사용할 계획입니다. 가장 뚜렷한 응용 장면은collection의 모든 요소에 lambda를 적용하는 것입니다.
 

List<?> list = …
list.forEach(…); //  lambda 
자바에 있어요.util.List 또는java.util.Collection 인터페이스에서 forEach의 정의를 찾을 수 없습니다.일반적으로 생각할 수 있는 해결 방법은 JDK에서 관련 인터페이스에 새로운 방법을 추가하고 실현하는 것이다.그러나 이미 발표된 버전에 대해서는 인터페이스에 새로운 방법을 추가하는 동시에 기존의 실현에 영향을 주지 않을 수 없다.
따라서 자바 8에서 lambda를 사용할 때 앞으로 호환되기 때문에collection 라이브러리에 사용할 수 없다면 얼마나 큰일인가.
상술한 원인으로 인해 새로운 개념을 도입하였다.가상 확장 방법, 즉 통상적으로 말하는defender 방법은 현재 인터페이스에 추가할 수 있으며, 이렇게 하면 성명된 행위의 기본적인 실현을 제공할 수 있다.
쉽게 말하면 자바의 인터페이스는 이제 방법을 실현할 수 있다.기본 방법이 가져오는 장점은 인터페이스에 새로운 기본 방법을 추가할 수 있고 인터페이스의 실현을 파괴하지 않는다는 것이다.
내가 보기에 이것은 매일 사용하는 Java 특성은 아니지만, Java의 Collections API로 하여금 lambda를 자연스럽게 사용할 수 있게 할 수 있다.
가장 간단한 예
가장 간단한 예를 살펴보자. 하나의 인터페이스 A, Clazz류가 인터페이스 A를 실현했다.
 

public interface A {
  default void foo(){
    System.out.println("Calling A.foo()");
  }
}
 
public class Clazz implements A {
}
코드는 Clazz 클래스가 foo () 방법을 실현하지 않았더라도 컴파일할 수 있습니다.인터페이스 A에서 foo() 방법의 기본 구현을 제공합니다.
이 예에서 클라이언트 코드를 사용합니다.
 

Clazz clazz = new Clazz();
clazz.foo(); //  A.foo()
다중 계승?
흔히 볼 수 있는 질문이 하나 있다. 사람들은 기본 방법에 대한 새로운 특성을 처음 들었을 때 "한 종류가 두 개의 인터페이스를 실현하고 두 개의 인터페이스가 모두 같은 서명으로 기본 방법을 정의한다면 어떻게 해야 합니까?"이전의 예에서 이 솔루션을 보여 드리겠습니다.
 

public interface A {
  default void foo(){
    System.out.println("Calling A.foo()");
  }
}
 
public interface B {
  default void foo(){
    System.out.println("Calling B.foo()");
  }
}
 
public class Clazz implements A, B {
}
이 코드를 컴파일할 수 없는 이유는 다음과 같습니다.
java:class Clazz는 types A에서 B까지foo()에 상관없는 기본값을 계승합니다
이것을 복구하기 위해서 Clazz에서 충돌을 다시 쓰는 방법을 수동으로 해결해야 합니다.
 

public class Clazz implements A, B {
  public void foo(){}
}
그러나 만약에 우리가 인터페이스 A에서 기본 실현 방법인 foo()를 호출하고 우리 자신의 방법을 실현하는 것이 아니라 호출하려면 어떻게 해야 합니까?다음과 같이 A의 foo()를 참조할 수 있습니다.
 

public class Clazz implements A, B {
  public void foo(){
    A.super.foo();
  }
}
지금 나는 내가 이 최종 방안을 좋아한다고 매우 확신할 수 없다.아마도 이것은 서명에서 기본 방법의 실현을 설명하는 것보다 더욱 간결할 것이다. 마치 기본 방법 규범의 첫 번째 원고에서 설명한 바와 같다.
 

public class Clazz implements A, B {
  public void foo() default A.foo;
}
그러나 이것은 확실히 문법을 바꾸었다. 그렇지 않니?그것은 실현이 아니라 인터페이스의 방법처럼 보인다.만약 인터페이스 A와 인터페이스 B가 서로 충돌하는 기본 방법을 많이 정의하고 모든 인터페이스 A의 기본 방법으로 충돌을 해결하고 싶다면 어떻습니까?현재 나는 계속해서 충돌을 해결하고 모든 충돌의 방법을 고쳐야만 한다.이것은 대량의 작업과 대량의 템플릿 코드를 써야 할 수도 있다.
나는 충돌을 해결하는 방법에 대해 대량의 토론이 필요할 것 같지만, 창립자들은 피할 수 없는 재난을 받아들이기로 결정한 것 같다.
실례
기본 방법으로 구현된 실제 예는 JDK8 초기의 가방에서 찾을 수 있습니다.집합된forEach 방법의 예로 돌아가면 우리는java에 있는 것을 발견할 수 있다.lang. Iterable 인터페이스의 기본값은 다음과 같습니다.
 

@FunctionalInterface
public interface Iterable<T> {
  Iterator<T> iterator();
 
  default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
      action.accept(t);
    }
  }
}
forEach는java를 사용했습니다.util.function.Consumer 기능 인터페이스 유형의 매개 변수는 lambda 표현식이나 다음과 같은 방법으로 참조할 수 있습니다.
 

List<?> list = …
list.forEach(System.out::println);
방법 호출
실제로 어떻게 기본적인 방법을 사용하는지 봅시다.만약 당신이 이 문제에 익숙하지 않다면, Rebel 실험실에서 자바 바이트에 관한 보고서를 읽는 것에 흥미가 있을 것이다.
클라이언트 코드의 시각에서 볼 때 기본적인 방법은 단지 흔히 볼 수 있는 가상 방법일 뿐이다.따라서 이름은 가상 확장 방법일 것이다.따라서 기본 방법을 인터페이스로 실현하는 간단한 예류에 있어 클라이언트 코드는 기본 방법을 호출하는 곳에서 자동으로 인터페이스를 호출합니다.
 

A clazz = new Clazz();
clazz.foo(); // invokeinterface foo()
 
Clazz clazz = new Clazz();
clazz.foo(); // invokevirtual foo()
기본 방법의 충돌이 해결되었다면, 기본 방법을 수정하고 그 중 하나의 인터페이스를 호출할 때, invokespecial은 구체적인 호출 인터페이스의 실현을 지정합니다.
 

public class Clazz implements A, B {
  public void foo(){
    A.super.foo(); // invokespecial foo()
  }
}
다음은 javap의 출력입니다.

public void foo();
Code:
0: aload_0
1: invokespecial #2 // InterfaceMethod A.foo:()V
4: return
보시다시피: invokespecial 명령은 인터페이스 방법 foo () 를 호출하는 데 사용됩니다.바이트 코드의 시각에서 볼 때, 이것은 여전히 신선한 일이다. 왜냐하면 이전에는 인터페이스를 가리키는 슈퍼가 아니라 한 종류(부류)를 가리키는 슈퍼를 통해서만 호출할 수 있었기 때문이다.
마지막으로...
기본 방법은 자바 언어에 대한 재미있는 보충 C입니다. 그들을 lambdas 표현식과 JDK 라이브러리 사이의 다리로 볼 수 있습니다.기본 표현식의 주요 목표는 표준 JDK 인터페이스를 진화시키고 우리가 최종적으로 Java8의 lambdas 표현식을 사용하기 시작할 때 우리에게 매끄러운 과도 체험을 제공하는 것이다.누가 알겠는가, 아마도 앞으로 우리는 API 디자인에서 더 많은 기본 방법의 응용을 보게 될 것이다.

좋은 웹페이지 즐겨찾기