2017-01-17 2 views
2

메서드 참조를 사용하는 규칙을 테스트했지만 필자가 작성한 코드는 컴파일되지 않습니다. 컴파일러는 정적 컨텍스트에서 비 정적 메서드를 참조 할 수 없다는 것을 계속해서 알려줍니다. 그러나 Java Documents에서는 명시 적으로 "::"을 사용하여 "특정 유형의 임의 객체의 인스턴스 메소드에 대한 참조"를 사용할 수 있다고 썼습니다. 아무도 내 코드에 문제가 있음을 지적 할 수 있습니까? 고맙습니다!Java에서 런타임에 인스턴스에서 메서드 참조를 사용할 때

package Test; 
import java.util.function.BiPredicate; 

class Evaluation { 
    public boolean evaluate(int a, int b) { 
     if (a-b ==5){ 
      return true ; 
     } 
     return false; 
    } 

    public void methodTest() { 
     BiPredicate<Integer, Integer> biPredicate = Evaluation::evaluate; 
     System.out.println(biPredicate.test(6,1)); 
    } 
} 

편집 :이 경우는 클래스 이름으로 인스턴스 메서드를 참조하는 것은 단지 다른 사람의 일부 기능 인터페이스에서 작동하지만하지 않는 것이 경우 답변을 읽고 나면, 궁금 해서요?

Predicate <String> predicate = String::isEmpty; 

컴파일 : 동안 예를 들어,

BiPredicate <String, Integer> biPredicate = String::startsWith; 

는 컴파일되지 않습니다. 이 경우 누군가가 나를 참조 할 수있는 페이지/튜토리얼/어떤 것이있어 어떤 기능 인터페이스가 호환 가능하고 어떤 기능 인터페이스가 아닌지를 설명 할 수 있습니까?

public void methodTest(){ 
    BiPredicate<Integer, Integer> biPredicate = this::evaluate; 
    System.out.println(biPredicate.test(6,1)); 
} 

어떤 인스턴스 변수 또는 메소드를 사용하지 않기 때문에, 당신은 단순히 정적 만들 수 : 당신의 방법은 인스턴스 메서드 인 경우

+2

참고 사항 [here] (http://stackoverflow.com/questions/25512532/lambda-parameters) – Holger

+1

'String :: startsWith'는 3 개의 인수를 취합니다. 1. 호출 할 String 인스턴스, 2. String 매개 변수 접두사 및 3. int 매개 변수 toffset.그러나 Bipredicate 는 그것들 중 2 개만을 설명 할 수 있습니다. 'String :: isEmpty'는 1 매개 변수, 즉 호출 할 인스턴스를 취합니다. 따라서'술어 '_will_이 작동합니다. –

+0

@ JornVernee 당신은 완전히 옳습니다. 그러나, 왜 '술어 술어 = 문자열 :: isEmpty; '일해? 왜 내가'String()'의 새로운 인스턴스를 전달할 필요가 없는지 (내 원래의 질문에 대한 당신의 대답이 나타낼 수 있듯이)? –

답변

2

, 당신은 예를 들어, 일부 인스턴스를 호출해야 그것을 그대로 유지하십시오.

+0

같은 대답을 쓰고 있었다;) – JFPicard

+0

메소드가 인스턴스 변수/메소드를 사용하지 않기 때문에, 당신의 대답이 틀렸다는 것과 그 OP가 대신 단순히 정적 인 메소드를 만들어야한다고 말하고 싶다. 또는 코드가 정적이 아닌 메소드에 있기 때문에 새 인스턴스를 만드는 이유는 무엇입니까? 'this :: evaluate'을 사용하십시오. – Andreas

2

정적으로 인스턴스 메서드를 참조 할 때 반환 된 Functor는 인스턴스를 나타내는 추가 인수를 사용합니다.

interface Func { 
    boolean evaluate(Evaluation instance, int a, int b); 
} 
... 
Func biPredicate = Evaluation::evaluate; 
System.out.println(biPredicate.evaluate(new Evaluation(), 6, 1)); 

그러나 전화 할 때는 Evaluation의 인스턴스를 전달해야합니다. 당신의 evaluate 방법은 인스턴스 필드를 사용하지 않기 때문에

, 당신은뿐만 아니라 당신이 시도 단지 BiPredicate<Integer, Integer> 것처럼 static, 다음 인스턴스를 통과 할 필요가 없습니다 만들고, 사용할 수 있습니다.

+0

'Func biPredicate = Evaluation :: evaluate' 구문 오류 : * 평가 유형에서 비 정적 메서드 evaluate (int, int)에 대한 정적 참조를 만들 수 없습니다. * 새로운 기능 인터페이스 소개는 아무 것도 변경하지 않습니다. – Andreas

+1

@Andreas 다시 시도해보십시오, 거기에 오타가있었습니다. 그것은 나를 위해 잘 작동합니다. –

+0

새로운 기능 인터페이스를 만드는 대신'biPredicate = this :: evaluate'을 쓰는 것이 더 쉬울까요? 또는 새로운 인스턴스 객체를 사용하기를 원한다면'biPredicate = new Evaluation() :: evaluate'을 사용합니다 * (왜?) *? – Andreas

0

나는 아직도 적용되는 규칙을 알아 내려고 노력하고있어,하지만 문제는, 내가하지만 가깝게 내가 이해할 수 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13을 통해 기괴하고있어

BiPredicate<Integer, Integer> biPredicate = this::evaluate; 

를 사용하는 경우 멀리가는 Evaluation::evaluate 힘 때문에 컴파일러가 유형 Evaluation의 임의의 객체를 만들고, 그 유형의 객체 내에서 규칙을 호출한다는 것입니다. methodTest 메서드가 나타나는 내부의 특정 객체에서 호출해야합니다.

설명이 없지만 해결 방법은 this::evaluate입니다. 이는 메소드 참조를 호출하는 객체와 명확하게 연결합니다.

사이드 노트 : boolean에서 boolean을 유도하기 위해 조건으로 boolean을 평가할 필요가 없습니다. 너는 단지 return a - b == 5; 일 수있다.