2016-09-29 94 views
3

是什麼以下兩種方法聲明之間的區別區別:Java泛型 - 在方法聲明

1. <R> Stream<R> myFunc(Function<? super T, ? extends R> mapper);  
2. Stream<R> myFunc(Function<? super T, ? extends R> mapper); 

對於第2個聲明進行編譯,我需要類型參數添加到類像這樣。

public class MyGenericsTest<T, R> 

在這種情況下,編譯器確保在編譯時確定myFunc的返回類型。編譯器也可以從方法簽名中知道。我對編譯器對這兩個聲明的處理方式感到困惑。

+0

在其中一種情況下,'R'是_class_的泛型類型參數,而不僅僅是一種方法。 –

回答

5

通過寫<R> Stream<R> myFunc(Function<? super T, ? extends R> mapper)你告訴編譯器:

  • R是任何類,並且是本地的方法(通過在年初<R>開始)
  • 返回類型是RStream
  • T是在類型參數MyGenericsTest<T>中指定的類(如果您不指定它,它將不會工作,因爲編譯器不會知道T

如果更改爲Stream<R> myFunc(Function<? super T, ? extends R> mapper)RT不是本地(無<R, T>在方法的開始),而編譯器期望他們在類級別定義爲MyGenericsTest<T, R>

+0

:編譯器通過查看類和方法簽名來推斷R是本地方法。爲什麼必須在方法聲明的開始處明確提供。 –

+0

如果你的項目中有一個'R.java'文件,會發生什麼情況?編譯器如何知道你的方法中的「R」是否意味着是泛型類或具體類?通過明確地聲明'',您告訴編譯器,標記爲'R'的方法或類文件中的所有內容都是通用的。 – ortis

+0

「編譯器期望它們在類級別上定義」......嚴格來說,這不是事實。它必須在封閉範圍內的某個地方定義,但通過使用內部類可以使其成爲'R'在泛型_method_而不是泛型類上定義的。這是合法的,但不常用。 – ajb

1

第二種形式:

Stream<R> myFunc(Function<? super T, ? extends R> mapper); 

真的是沒有任何與此不同:

Stream<String> myFunc(Function<? super T, ? extends String> mapper); 

給編譯器,只是它使用了不同的類型。第二個返回String流。第一個返回R的流,不管R是什麼。編譯器已經知道String是什麼。對於第一個,編譯器必須知道什麼是R,這意味着它必須在某個地方定義。它可以是外部類的通用參數,但它也可以是從其他地方導入的非泛型類(由非常糟糕的人編寫,以提供有意義的名稱)。

請記住,雖然我們經常使用單個大寫字母作爲通用參數,但這只是人類的慣例。編譯器只是將它視爲任何其他標識符。

但這就是爲什麼你的兩個例子如此不同。第一個是將該方法定義爲的語法,該方法是一個帶有您稱爲R的類型參數的泛型方法。第二個是與返回Stream<String>List<Integer>或其他的方法完全相同的語法。