2016-03-08 59 views
3

Java8允許我使用方法聲明作爲任何接口的實現,只要它只包含一個方法即可。如何更改函數引用的類型?

但是一旦被定義,類型不能被改變。

我的代碼:

import java.util.function.IntConsumer; 

public class A { 

    interface MyConsumer { 
     void doSomething(int i); 
    } 

    public static void main(String[] args) { 
     IntConsumer i = A::consume; 
     MyConsumer i2 = A::consume; 

     IntConsumer i3 = (IntConsumer) i2; // ClassCastException 
     MyConsumer i4 = (MyConsumer) i; // ClassCastException 

     IntConsumer i5 = i2; // does not compile 
     MyConsumer i6 = i; // does not compile 

     IntConsumer i7 = i2::doSomething; // workaround, as suggested by @Eran http://stackoverflow.com/a/35846001/476791 
     MyConsumer i8 = i::accept; 

     Object i9 = A::consume; // does not compile 
     Object i10 = (IntConsumer) A::consume; // works 
     Object i11 = (MyConsumer) A::consume; // works 
     Object i12 = (MyConsumer) (IntConsumer) A::consume; // does not work 
    } 

    static void consume(int i) { 
     System.out.println(i); 
    } 
} 

注意:如果你直列一些變量,那麼一些非工作的例子突然開始工作。

我詳細的想法:

  1. 如果IntConsumer i = A::consume是有效的,那麼A::consumeimplement IntConsumer
  2. 如果MyConsumer i2 = A::consume是有效的,那麼A::consumeimplement MyConsumer
  3. 如果A::consume實現IntConsumerMyConsumer,那麼應該可以鑄造

是否有另一種方法可以在之後「投射」或「改變」消費者類型?

+0

我建議你閱讀'Functional Interface'和'方法參考'。你所看到的不是簡單的繼承。這些實現邏輯不適用於此。 – Codebender

回答

1

A::consume沒有固有的類型。當它出現在使用或分配給函數接口類型的上下文中時,編譯器將創建一個對象,其類型使用A::consume實現。

一旦你有了,你有一個特定的功能接口類型的對象。這不是一種方法;這是一個非常正常的對象。 Java對象不能假裝爲其實際類型不實現或擴展的其他類型。

所以一旦你有一個IntConsumer,你不能將它投到MyConsumer。你可以用它來獲得一個方法參考,然後可以成爲一個新的MyConsumer,但那個對象將永遠只是一個IntConsumer,沒有別的了。

3

是否有另一種方法可以在之後「投射」或「改變」消費者類型?

您無法更改對象的實際類型(1)。您可以投射一個基元,並且可以將引用轉換爲適用於所引用對象的另一種類型。

你可以做的是用你想要的類型包裝實例。 (1)你可以破解對象頭中的類指針,但這不太可能是一個好主意。

+0

@slartidan這不是一個動態轉換,它被編譯器用於類型推斷。 'A :: consume'具有固有的無類型。 Object o = A :: consume'不會被編譯。 –

相關問題