2017-06-14 163 views
2

短缺問題

是否有可能無論如何做這樣的事情在Java中:訪問參數化類型參數化類型的

public interface Processor<T extends Producer> { 
    <T2> T2 process(T<T2> producer); 
} 

其中生產者被聲明爲Producer<T>

長的問題

如果Java類型A是參數與B型,這也是通用的,是有可能在一個以某種方式使用參數化類型B的?我知道,這是神祕的。

比方說,我們有一個通用的接口監製:

此接口的
public interface Producer<T> { 
    T produce(); 
} 

實現意味着是通用的爲好。它們在產生物體的類型上沒有區別,而是在於它們如何生成它們,因此可能存在:DatabaseProducer,RandomProducer等。

我們還有一個Processor接口。處理器的特定實現能夠與生產者的特定實現協同工作,但處理器也不關心處理對象的類型。我們可以很輕鬆地實現這樣的情況:MyProcessor的

public class MyProducer<T> implements Producer<T> { 
    @Override 
    public T produce() { 
     (...) 
    } 
} 

public class MyProcessor implements Processor<MyProducer> { 
    <T> T process(MyProducer<T> producer) { 
     return producer.produce(); 
    } 
} 

過程()方法獲取通用MyProducer,只是返回它所產生的。只要生產者爲MyProducer類型,此實現將與String,Integer或其他對象的生產者一起工作。

現在的問題是如何編寫一個通用的處理器接口。該接口使用Producer類型進行參數化,並且該方法應返回相關Producer的參數化類型。

我們不能做這樣的事情:

public interface Processor<T extends Producer> { 
    <T2> T2 process(T<T2> producer); 
} 

或類似的東西:

public interface Processor<T extends Producer> { 
    T.T process(T producer); 
} 

它甚至有可能在Java中呢?有什麼理由不能或不應該支持它,或者這只是一個缺失的功能?我認爲編譯器可以完全理解這種情況,並檢查類型是否正常。


更新

解決方案有兩個參數化類型,例如:

public interface Processor<T extends Producer<T2>, T2> { 
    T2 process(T producer); 
} 

是不是我要找的。請注意,MyProcessor未綁定到任何特定類型的生成對象。從process()方法返回的類型是在調用站點推斷的。

此外我理解類型擦除的工作原理和相關的問題。問題是:由於類型擦除,這種情況是有問題的還是不可能的?我不相信。

如果我們有一個普通的通用方法,例如:

<T> T process(MyProducer<T> producer) { 
    return producer.produce(); 
} 

我們稱之爲:

MyProducer<String> prod = (...); 
String result = processor.process(prod); 

然後一切都會好起來。當然,在這種情況下,字符串被擦除,process()和produce()方法都返回結果字節碼中的Object,但編譯器明白MyProducer.produce()實際上會返回String,所以process()也會返回String。我不明白爲什麼它不能在我的情況相同的方式工作:

public interface Processor<T extends Producer> { 
    <T2> T2 process(T<T2> producer); 
} 

編譯器從生產者傳遞對象調用現場推斷返回類型,它可以證明,實現在上述同樣的方式是正確的。我認爲Java中唯一缺少的東西是編譯器應該注意到T擴展了泛型,所以T<T2>可以被視爲類似於Producer<T2>。也許我在這裏沒有看到重要的東西。

+2

您應該做的第一件事是在您的Java編譯器中啓用所有警告並解決這些警告。特別要注意關於原始類型的警告。 – VGR

回答

1

您可以在類級別或方法級別上使用泛型。如果你需要有處理器使用特定類型的生產者,那麼你可以有處理器被這樣定義:

public interface Producer<T> { 
    T produce(); 
} 

public interface Processor< T, P extends Producer<T> > { 
    public T process(P producer); 
} 

public class MyProducer<T> implements Producer<T> { 
    @Override 
    public T produce() { 
     return null; 
    } 
} 

public class MyProcessor<T> implements Processor<T, MyProducer<T> > { 

    public T process(MyProducer<T> producer) { 
     return producer.produce(); 
    } 
} 

更新1:

我看不出做Processor接口通用的點然後在那裏使用Producer與原始類型。如果你不想參數化Processor任何類型的Producer那麼你在方法級別聲明參數化類型:

public static interface Processor { 
     public <T> T process(Producer<T> producer); 
    } 

    public static class MyProcessor implements Processor{ 

     public <T> T process(Producer<T> producer) { 
      return producer.produce(); 
     } 
    } 

    //in here we wont have any compilation errors 
    String result = new MyProcessor().process(new MyProducer<String>()); 

BTW,我不喜歡你如何申報MyProducer是通用的,顯示你是如何要知道在produce()方法中返回什麼類型的對象。

更新2:

在這種情況下,我不認爲我們沒有鑄造可以做。這裏是沒有界限Producer另一個版本,這將需要鑄造:

public static interface Processor< P extends Producer<?> > { 
    public <T> T process(P producer); 
} 

public static class MyProcessor implements Processor< MyProducer<?> > { 

    @SuppressWarnings("unchecked") 
    public <T> T process(MyProducer<?> producer) { 
     return (T)producer.produce(); 
    } 
} 

//again this will work without any compilation errors 
String result = new MyProcessor().process(new MyProducer<String>() 
+0

請參閱我的問題更新。 – broot

+0

我其實確實想把Processor的實現綁定到Producer的具體實現上。但我不想將它綁定到任何特定類型的製作對象上。我刪除了農產品(),因爲它是無關緊要的。 MyProducer可以有例如一個列表,它在一個構造函數中接收,並且它一次產生一個項目 - 無論如何,真的。 – broot

0

這是不可能的,因爲你的泛型類型是Non-Reifiable

非Reifiable類型

一個reifiable型是類型信息在運行時完全可用的類型 。這包括基元,非泛型類型,原始類型, 和未綁定通配符的調用。

不可否定類型是類型,其中通過類型擦除在 編譯時已刪除信息 - 通用類型的調用 未定義爲無界通配符。一個不可確定的類型在運行時沒有可用的所有信息。不可確定的 類型的示例是List和List; JVM不能在運行時告訴這些類型之間的差異。如泛型的限制條件所示,在某些情況下,無法使用不可確定類型 :例如,在表達式的一個實例中,或者在數組中的某個元素爲 。

public interface Processor<T extends Producer, T2> { 
    T2 process(T producer); 
} 

回答了提問更新:

一個非常簡單的解決辦法可以通過在你的界面使用附加的類型來完成

我要說的是,它在這是不可能的因爲ProducerT沒有實際關係。什麼是可能的是創建Producer界面中的內部類,並把它作爲一個類型:

public interface Producer<T>{ 
    T produce(); 

    class NotGenericType <T>{ 
     // inner T != outter T 
     // do something with T ? 
    } 
} 

public interface Processor<P extends Producer>{ 
    // NotGenericType belongs to the type P 
    P.NotGenericType process(P producer); 

    // Won't work because there is no relation between T and Producer 
    // P.T process(P producer); 
} 

我也沒多想什麼用這個可以有,但。

+1

請參閱我的問題的更新。 – broot

+0

@broot,請看看 –