2017-11-25 7 views
0

람다식이 기능적 인터페이스에 할당되면 람다에 대한 "대상 유형"과 그 유형의 인스턴스 (즉, 기능 인터페이스의 유형)은 기능 인터페이스에서 추상 메소드의 구현으로 사용 된 람다 표현식으로 작성됩니다.Java의 람다 식 메커니즘

내 질문 : 그렇다면, 평균 람다 정말 독립형 방법이 아니며, 요소 등 새로운 유형으로 언어 반입, 단순히 익명의 클래스를 표현하기위한 컴팩트 방법임을 않는 경우 그리고 단지 컴파일러 측에 generics와 같은 기능이 추가되었습니다.

또한 메서드 참조가 그 무엇, 특히 개체와 관련이없는 정적 메서드를 어떻게 준수합니까? 예를 들어 인스턴스 메소드에 대한 메소드 참조가 기능적 인터페이스에 지정되면 해당 메소드에 대한 캡슐화 오브젝트가 사용되지만 정적 메소드의 경우에는 어떤 일이 발생합니까?

+0

람다 식의 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)에 대한 답변이 있습니다. –

답변

1

그렇다면, 평균 람다 정말 독립형 방법이 아니라는 것을 수행하고 요소의 이러한 새로운 형태의 언어로 가져으로,

수정은 람다는 합성과 정상적인 방법으로 컴파일 이름

하지만 익명의 클래스를 표현하기위한 단순한 방법 일 뿐이므로 컴파일러 측에서 단순히 제네릭과 같은 기능이 추가됩니다.

아니요, 컴파일러 측에만 국한되지 않습니다. 컴파일러가 람다를위한 클래스 파일을 작성할 필요가 없도록 관련된 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은 런타임에 정보를 저장하는 최적의 방법 (정확한 객체를 올바른 메소드로 호출)을 결정할 수 있습니다.

+0

자세한 답장을 보내 주셔서 감사합니다. 그러나 나는 아직도 그것을 이해하는데 어려움을 겪고있다 : "그 JVM은 메소드 구현을 가진 클래스가 인스턴스를 호출 할 때 (void를 통해 accept (E e) 메소드를 사용하여 소비자 을 구현하는 클래스를 생성 할 것이다. 그것의 실제 객체)는 기능 인터페이스의 계약을 수행 할 것인가? 인스턴스와 메소드에 직접 할당하지 않는 이유는 무엇입니까? 인스턴스가 데코레이션으로 인터페이스를 구현하지 않았기 때문이라고 생각하십니까? – Learnerer

+0

@Learnerer 내 대답을 업데이트했습니다. 잘하면이 도움이 –

+0

어쩌면 혼란은 프로그래밍 모델과 구현 메커니즘 사이의 간섭으로 인한 것입니다. 당신의 대답에 감사드립니다. – Learnerer

0
인스턴스 방법에있어서의 참조는 그 방법 봉지 객체가 사용되는 다음의 기능 인터페이스 할당 예컨대

,하지만 정적 방법의 경우에서 발생 - 들은 아니다 어떤 개체와도 연관되어 있습니다.

상황에 따라 다릅니다. 주어진 문자열을 분명히 다듬을 정적 인 Utils#trim(String) 메서드가 있다고 가정 해 보겠습니다.

이제는 List<String> list이 없으므로 일부 문자열이 포함될 수 있습니다. 우리는 다음과 같이 할 수 있습니다 :

list.stream().map(Utils::trim).collect(Collectors.toList());

주어진 컨텍스트에서 우리는 Utils::trim 메서드의 입력 인수로 목록의 모든 문자열을 사용하기 위해 람다 정적 메서드 참조를 사용하고 있습니다.

+0

감사합니다. 하지만 실제로 람다 또는 메소드 참조를 사용하는 방법을 묻지는 않습니다. 실제로 장면 뒤에있는 작업을 파악하려고합니다. 실제로 구현 된 방법입니다. – Learnerer