为什么JDK中存在Void包装类?

19
6个回答

17
如果你有一个类似于ExecutorService的对象,需要你提供一个Callable<T>对象,那么你可以传递一个Callable<Void>来表示你的Callable不返回任何值。 Callable<T>必须基于某种类型进行参数化,因此提供Void来表示缺少类型。

13

- 不同于其他的包装器类,Void并没有在自身中存储void类型的数据,因此本质上不是一个包装器

- 根据javadoc的解释,Void类的存在是因为我们有时候需要将void关键字表示为一个对象。

- 然而,我们无法使用new运算符创建Void类的实例。这是因为Void类中的构造函数被声明为私有。此外,Void类是一个final类,这意味着我们不能继承这个类。

- 因此,Void类存在的唯一目的是反射,通过它我们可以获取方法的返回类型为void。


List<Void> 没有实际用途。 - Amit Deshpande
但是如果你想要一个不切实际的用途,List<Void> 可以被用作非常低效的计数器 :-) - Stephen C
你说得对。在Java中,void(非)类型与C / C ++中的void不是同一概念。当你不关心列表元素类型时,应该使用List<?>而不是List<Void> - Stephen C
通过一些反射技巧,可以创建 Void 类的实例。 - Luke Woodward

7

3
Java反射API使用Void.TYPE来表示返回void的方法的返回类型,正如Luke Woodward所指出的那样。(我之前认为返回Void.class会导致与声明java.lang.Void返回类型的方法产生歧义。)
 void test(){...};

 Method handleForTest = ...;
 assert(handleForTest.getReturnType() == Void.TYPE);

在 Java 1.5 及之后的版本中,可以使用 Void 来表示泛型类不返回任何值 - 实现仍然需要返回 null,但是可以忽略,因为这是类型 Void 的唯一有效值。

interface<T> Example{
      //Implementations may do something and return a result
      T doSomeThing();
}

class ExampleVoid implements Example<Void>{
      //does something without returning a result
      Void doSomething(){return null;}
}

此外,Java允许在覆盖方法时给出更具体的返回类型。这基本上与上面的通用示例相同,只是为了展示如果原始返回类型为Object,则没有泛型也可以工作。(它仅限于Object,因为Void遵循与其他Java类型相同的规则,遗憾的是没有办法使用无名的null类型来实现这一点)
interface Example{
      //Implementations may do something and return a result
      Object doSomeThing();
}

class ExampleVoid implements Example{
      //does something without returning a result
      Void doSomething(){return null;}
}

Java反射API使用void.class作为void方法的返回类型,而不是Void.class。在您的第一个示例中,断言将失败。 - Luke Woodward

2

JLS#14.8. 表达式语句

与 C 和 C++ 不同,Java 编程语言只允许某些形式的表达式用作表达式语句。请注意,Java 编程语言不允许“转换为 void” - void 不是一种类型 - 因此,传统的 C 技巧写一个表达式语句,如:

(void)... ;  // incorrect!

不起作用。另一方面,Java编程语言允许在表达式语句中使用所有最有用的类型的表达式,并且不要求将用作表达式语句的方法调用用于调用void方法,因此几乎永远不需要这样的技巧。如果需要技巧,则可以使用赋值语句(§15.26)或局部变量声明语句(§14.4)来代替。 JLS#15.8.2. Class Literals void.class(§8.4.5)的类型是Class<Void>JLS#8.4.5. Method Return Type 方法声明的结果要么声明方法返回的值的类型(返回类型),要么使用关键字void表示该方法不返回值。

Java文档 Void

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

它用于反射目的,当您想要检查方法的返回类型时使用。

if (getClass().getMethod("someMethod").getReturnType() == Void.TYPE)

同样适用于通用方法。
 final Callable<Void> callable = new Callable<Void>() {
        public Void call() {
             return null;
        }
    };

2

原因

引入Void类型是为了允许回调和与外部系统(JNI、来自小程序的JavaScript调用等)进行接口交互,并且自Java 1.1以来一直存在于这种情况下,其中接口类型未知或不受其他接口强制执行(因此无法使用void关键字)。 Java被设计为“所有东西都是对象”的语言,除了基元和空引用之外,需要一个虚拟包装器/占位符来指示缺少预期类型。

定义

一种方法,如 JLS 中的 方法返回类型 部分(§8.4.5)所定义的,需要在返回类型中正式声明:

方法声明的结果要么声明方法返回的值的类型(返回类型),要么使用关键字 void 表示该方法不返回任何值。

正如 JLS 中的 类文字 部分(§15.8.2)所述:

“void.class”的类型(参见§8.4.5)是“Class<Void>”。它的使用在Java 5引入泛型后变得更加突出,因为它允许这些接口的定义使用泛型,并且可以对这些接口和回调的使用进行类型检查。在此之前,有时实现者需要知道没有传递对象或没有返回对象,例如在使用AccessController的特权执行块的情况下,通常用于定义安全代码路径的Applet中。”
  somemethod() {
     // ...normal code here...
     AccessController.doPrivileged(new PrivilegedAction<Void>() {
         public Void run() {
             // privileged code goes here, for example:
             System.loadLibrary("awt");
             return null; // nothing to return
         }
     });
     // ...normal code here...
 }

请注意,与Java 1.4版相比,这段代码的区别在于对调用者没有返回任何内容不太清晰(也不是类型安全):1.4 version of this same code
   somemethod() {
        // ...normal code here...
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                // privileged code goes here, for example:
                System.loadLibrary("awt");
                return null; // nothing to return
            }
        });
       // ...normal code here...
  }

更多阅读和类似问题:

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接