[英]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.