2017-01-17 75 views
2

我正在測試使用方法引用的規則,但是我寫的代碼不能編譯。編譯器不斷告訴我,我無法從靜態上下文中引用非靜態方法。但是,在Java文檔中明確寫道,可以使用「::」來「引用特定類型任意對象的實例方法」。任何人都可以指出我的代碼有什麼問題嗎?謝謝!在運行時用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)); 
    } 
} 

編輯:閱讀的答案後,我在想,如果它的情況是由類名引用的實例方法只適用於一些功能接口,而不是在其他的呢?例如,

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

不能編譯,而:

Predicate <String> predicate = String::isEmpty; 

編譯。 如果是這樣的話,有沒有一個頁面/教程/任何人都可以引用我的解釋哪些功能接口兼容,哪些不是?

+2

另請參見[這裏](http://stackoverflow.com/questions/25512532/lambda-parameters) – Holger

+1

'String :: startsWith'需要3個參數; 1.要調用的String實例,2. String參數前綴,以及int參數toffset。但是'Bipredicate '只能佔2個。 'String :: isEmpty',需要1個參數,要調用的實例,所以'謂詞'_will_工作。 –

+0

@JornVernee你是完全正確的。但是,爲什麼'Predicate 謂詞= String :: isEmpty; 「工作?喜歡爲什麼我不需要傳遞一個新的'String()實例(因爲你的答案在我原來的問題可能表明)? –

回答

2

如果你的方法是一個實例方法,那麼你必須調用它在某些情況下,例如:

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

既然你不使用任何實例變量或方法,你可以簡單地讓靜態和保持它的樣子。

+0

正在寫相同的答案;) – JFPicard

+0

由於方法不使用實例變量/方法,我會說你的答案是錯誤的,而OP應該簡單地使方法'靜態',而不是。另外,由於代碼是在一個非靜態的方法,爲什麼創建一個新的實例?使用'this :: evaluate'。 – Andreas

2

當靜態引用一個實例方法時,返回的函數會接受一個表示該實例的附加參數。

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方法不使用任何實例字段,你還不如讓它static,那麼你並不需要通過一個實例,可以使用只是一個BiPredicate<Integer, Integer>像你想。

+0

'Func biPredicate = Evaluation :: evaluate'語法錯誤:*無法對Evaluation類型的非靜態方法evaluate(int,int)進行靜態引用。*引入新的函數接口不會改變任何內容。 – Andreas

+1

@Andreas再試一次,我在那裏有一個錯字。它適用於我:) –

+0

只是寫'biPredicate = this :: evaluate'而不是創建一個新的功能接口會更容易嗎?或者'biPredicate = new Evaluation():: evaluate',如果你堅持使用新的實例對象*(儘管爲什麼?)*? – Andreas

0

我還在試圖找出適用的規則,但問題消失,如果你使用

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

我通過https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13令人費解,但儘可能接近我可以計算的,因爲Evaluation::evaluate力編譯器創建Evaluation類型的任意對象,並且您從該類型的對象內調用該對象,該規則不同。您需要從methodTest方法出現的特定對象中調用它。

雖然我沒有解釋,解決方法是使用this::evaluate。這明確地將方法引用與調用它的對象聯繫起來。

備註:您不需要評估boolean作爲條件以便從boolean派生boolean。你可以只是return a - b == 5;

相關問題