그렇다면, 평균 람다 정말 독립형 방법이 아니라는 것을 수행하고 요소의 이러한 새로운 형태의 언어로 가져으로,
수정은 람다는 합성과 정상적인 방법으로 컴파일 이름
하지만 익명의 클래스를 표현하기위한 단순한 방법 일 뿐이므로 컴파일러 측에서 단순히 제네릭과 같은 기능이 추가됩니다.
아니요, 컴파일러 측에만 국한되지 않습니다. 컴파일러가 람다를위한 클래스 파일을 작성할 필요가 없도록 관련된 JVM에도 코드가있다.
또한 메소드 참조가 어떤 객체와 관련이없는 정적 메소드를 어떻게 준수합니까?
메소드 참조는 람다와 다르지 않습니다. 런타임시 함수 인터페이스를 구현하는 객체가 있어야합니다. 객체의 「SAM」를 호출하면 (자),이 메소드는 참조 된 메소드를 호출합니다.인스턴스 방법에있어서의 참조는 해당 메소드의 캡슐화 객체가 사용되는 기능 인터페이스에 할당되는 예를 들어
,
없음은이를 사용할 수 없다. 의는 System.out::println
방법 참조를 사용하여 다음 예를 보자 :
이
Arrays.asList("A", "B").forEach(System.out::println);
List<E>.forEach()
방법 void accept(E e)
을 정의하는 Consumer<? super E>
을 기대하고있다. 컴파일러는 런타임시 JVM이 void accept(E e)
메소드로 Consumer<E>
을 구현하는 클래스를 생성 할 수 있도록 클래스 파일에 바이트 코드 및 기타 정보를 생성해야합니다. 이 생성 된 메서드는 System.out.println(Object o)
을 호출합니다.
런타임 생성 된 클래스는 주석에서
class $$lambda$xy implements Consumer<Object> {
private PrintStream out;
$$lambda$xy(PrintStream out) {
this.out = out;
}
void accept(Object o) {
out.println(o);
}
}
귀하의 질문처럼 보일 것입니다 : "왜 직접 인스턴스와 그 방법을 지정하지?"
이의이 예를 약간 확장하자
static void helloWorld(Consumer<String> consumer) {
consumer.apply("Hello World!");
}
public static void main(String[] args) {
helloWorld(System.out::println);
}
이를 컴파일하려면 컴파일러가 Consumer<String>
를 구현하는 객체를 생성 바이트 코드를 생성 할 수있다 (그래서 helloWorld()
로 개체를 전달할 수 있습니다.) 그 객체는 어쨌든 accept(x)
메서드를 호출 할 때 PrintStream에서 println(x)
을 호출해야한다는 정보를 저장해야합니다.
다른 언어는 이러한 종류의 객체에 대해 다른 이름이나 개념을 가질 수 있습니다. Java에서 확립 된 개념은 "해당 익명 클래스의 인터페이스와 객체를 구현하는 익명 클래스"입니다.
개체가이 정보를 어떻게 저장합니까? 자,이 정보를 저장하는 새로운 멋진 방법을 발명 할 수 있습니다. Java 언어 설계자는 익명의 클래스가 당분간 충분할 것이라고 결정했습니다. 그러나 그들은 누군가가 새로운 아이디어를보다 효율적인 방식으로 구현한다면 자바 생태계 (Java 컴파일러와 JVM)에 쉽게 통합 될 수 있다는 예견을 받았습니다.
그래서 익명의 클래스를 컴파일 타임에 만들지 않고 컴파일러가 필요한 정보를 클래스 파일에 쓰도록하기로 결정했습니다. 이제 JVM은 런타임에 정보를 저장하는 최적의 방법 (정확한 객체를 올바른 메소드로 호출)을 결정할 수 있습니다.
람다 식의 JLS [섹션 15.27] (https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.27) 및 람다 식의 [섹션 15.13] (https : //docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.13)에 대한 답변이 있습니다. –