[英]What is the difference between java.lang.Void and void?
在 API
“Void 類是一個不可實例化的占位符類,用於保存對表示 Java 關鍵字 void 的 Class 對象的引用。”
java.lang.Void
? 如果類是“不可實例化的”,它有什么用?java.lang.Void
和void
有什么區別? java.lang.Void
類似於java.lang.Integer
。 Integer
是一種將原始類型int
的值裝箱的方式。 Void
是一種對原始類型void
的值進行裝箱的方法。
“但是等等, void
沒有任何可能的值!”
正確的! 這就是使java.lang.Void
“不可實例化”的原因。 :)
Java 類型系統的一個很好的特性是每個原始類型都有一個盒裝的等價物。 int
有Integer
, long
有Long
, byte
有Byte
... 並且void
有Void
。 如果Void
不存在,那將是奇怪和不對稱的。
“那么java.lang.Void
和void
有什么區別?”
簡單的。 void
是原始類型。 Void
是繼承自Object
的引用類型。 它們的相似之處在於它們都沒有任何可能的值。 但是,從類型系統的角度來看,它們是兩種截然不同的類型。
“但我的程序中對Void
沒有任何用處。”
而且我對GarbageCollectorMXBean
沒有任何用處。 有些功能沒有非晦澀的用途。 沒關系。
Void
最常見的用途是反射,但這並不是唯一可以使用它的地方。
void
是一個關鍵字,表示函數不會產生值。
java.lang.Void
是一個引用類型,那么以下是有效的:
Void nil = null;
(到目前為止,它並不有趣......)
作為結果類型(返回值類型為Void
的函數),它意味着函數 *always * 返回null
(它不能返回null
以外的任何內容,因為Void
沒有實例)。
Void function(int a, int b) {
//do something
return null;
}
為什么我想要一個總是返回 null 的函數?
在泛型發明之前,我沒有Void
的用例。
對於泛型,有一些有趣的案例。 例如, Future<T>
是另一個線程執行的異步操作結果的持有者。 Future.get
將返回操作值(類型為T
),並將阻塞直到執行計算。
但是......如果沒有什么可以返回怎么辦? 很簡單:使用Future<Void>
。 例如,在 Google App Engine 中,異步數據存儲服務delete
操作返回一個 future . When
. When
is invoked on that future,
get() 時,刪除完成后返回 null`。 可以用Callable寫一個類似的例子。
另一個用例是沒有值的Map
,即Map<T,Void>
。 這樣的映射的行為類似於Set<T>
,那么當沒有Set
的等效實現時它可能很有用(例如,沒有WeakHashSet
,那么可以使用WeakHashMap<T,Void>
)。
Void
唯一的一點是持有Void.TYPE
,它有點像void.class
。 如果您對返回void
的方法有反射引用,並且您獲得了它的返回類型,那么它將返回Void.TYPE
。
您不能也不應該將其用於其他任何事情。
Void 是 void 的一個自動裝箱功能(從 JDK 1.5 開始)。
好吧,它的自我解釋是 Void 是引用,而 void 是原始類型。
那么,哪里有要求必須使用 Void ???
泛型類型的一種常見用法,我們不能使用原始類型。
比如說,在 Android
AsyncTaks<Params, Progress, Result>
的情況下,如果我不想獲得 Progress 更新怎么辦。 我不能在這里使用 void (原始類型) 我們需要 java.lang.Void
另一個使用Void
的例子是SwingWorker
new SwingWorker<Void, Integer> () {
@Override
protected Void doInBackground(){
...
}
@Override
protected void process(List<Integer> chunk){
...
}
@Override
public void done(){
...
}
}.execute();
Void 很有用,因為有時您需要在方法本身之外指定方法的返回類型。
例如這個java 8 lambda 表達式,它使用一個名為checkBenefitConcertInCentralPark
的方法檢查 EventResource 對象是否具有某些屬性,並傳遞給方法checkCreatedEvent
:
eventChecker.checkCreatedEvent(TestEvents::checkBenefitConcertInCentralPark);
checkBenefitConcertInCentralPark
方法是這樣定義的(注意 Void 的使用):
public static Void checkBenefitConcertInCentralPark(EventResource eventResource) {
// JUnit code here...
// assertThat(blablabla :) )
return null; // we can only return null at the end of a method when returning Void
}
然后將checkBenefitConcertInCentralPark
方法傳遞到方法checkCreatedEvent
中。
// Function<EventResource, Void> describes the checkBenefitConcertInCentralPark method
public void checkCreatedEvent(Function<EventResource, Void> function) {
function.apply(this.eventResource);
}
我個人是這樣使用它的:
@FunctionalInterface
interface MyPackagePrivateInterface<T, Next> {
//Returns next
Next compareAndSwap(T prev);
}
@FunctionalInterface
public interface ClientPublicInterface<T> extends MyPackagePrivateInterface<T, Void> {
}
我的理由是這樣的:
基於用戶輸入的計算可能會創建您的系統可能需要的新類型分配。
該動作可能會保持其同名,因為在客戶端的眼中它正在執行它所說的內容,但是在系統內的子層中正在發生等效的動作,但具有完全不同的類型,只有您的系統應該知道的類型。
這可能與“自相似”原則有關,其中系統由與其自身相似的較小組件組成,因此重用具有不同類型和相似名稱的接口可能是合乎邏輯的,該系統還意味着具體化(將抽象的東西轉換為real) 是系統狀態固有的,因此用戶對立即讀取返回值不感興趣,但目標依賴於對象的狀態變化。
現在這個特定示例是針對原子操作的,TBH 我想不出可能需要這樣做的不同情況,原因是本機原子操作依賴於時空(空間 = 內存范圍)快照才能准確執行.
這種新的分配對客戶來說並不重要,而只對系統的功能很重要。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.