繁体   English   中英

java.lang.Void 和 void 有什么区别?

[英]What is the difference between java.lang.Void and void?

在 API

“Void 类是一个不可实例化的占位符类,用于保存对表示 Java 关键字 void 的 Class 对象的引用。”

  1. 什么是“不可实例化”的占位符类? 什么时候使用java.lang.Void 如果类是“不可实例化的”,它有什么用?
  2. java.lang.Voidvoid有什么区别?

java.lang.Void类似于java.lang.Integer Integer是一种将原始类型int的值装箱的方式。 Void是一种对原始类型void的值进行装箱的方法。

“但是等等, void没有任何可能的值!”

正确的! 这就是使java.lang.Void “不可实例化”的原因。 :)

Java 类型系统的一个很好的特性是每个原始类型都有一个盒装的等价物。 intIntegerlongLongbyteByte ... 并且voidVoid 如果Void存在,那将是奇怪和不对称的。

“那么java.lang.Voidvoid有什么区别?”

简单的。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM