Void和无参数之间有什么区别?

67

我有一个类,定义了两个重载方法。

public void handle(Void e) 

protected void handle() 

显然它们是不同的,尤其是handle(Void e)public


那两者之间有什么区别?

如何调用第一个方法?我正在使用handle(null) - 这样做正确吗?


1
根据参数和访问权限,您可以调用handle(),这将调用第二个方法,而handle(null)或handle(null)将调用第一个。 - Vinit Prajapati
4
@VinitPrajapati.. 你无法实例化 Void - Rohit Jain
@RohitJain 已更正注释 - Vinit Prajapati
foo和foo(void)之间的区别是什么? - RAS
9
我认为这是不同的。 - Adam Lee
是的,这是正确的。你只能使用 handle(null) 调用 public void handle(Void e) - M. Atif Riaz
4个回答

69

Void 是一个特殊的类,通常只用于反射——它的主要用途是表示 void 方法的返回类型。来自Void 的 javadoc

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

因为 Void 类不能被实例化,所以您只能向带有 Void 类型参数的方法(例如 handle(Void e))传递 null 值。


这是官方的说法,但对于那些感兴趣的人来说,尽管在 Void 的 javadoc 中声称不可能,您实际上可以实例化一个 Void 实例:

Constructor<Void> c = Void.class.getDeclaredConstructor();
c.setAccessible(true);
Void v = c.newInstance(); // Hello sailor!


话虽如此,我曾经看到Void被用作泛型参数类型时,表示该类型被“忽略”,例如:

Callable<Void> ignoreResult = new Callable<Void> () {
    public Void call() throws Exception {
        // do something
        return null; // only possible value for a Void type
    }
}

Callable 的泛型参数是返回类型,因此当像这样使用 Void 时,它清楚地向代码的读者发出信号,表明返回值并不重要,即使需要使用 Callable 接口,例如在使用 Executor 框架时。


8
这句话的意思是:“这并不意味着‘不关心类型’,而是意味着‘我想返回除了通用类型以外的任何东西,但是通用类型不支持 void,因为它不是一个类,所以我使用 Void 代替它。” - josefx
1
+1 我相信你可以通过反射实例化一个 Void 的实例。 - Eng.Fouad
2
@Adam 这可能听起来像一个奇怪的请求,但你是否愿意接受另一个答案?原因是如果我的一个答案超过了被接受的答案,我会得到一个特别的“帽子”。这将是一个不错的圣诞礼物 :) - 谢谢 - Bohemian
@Adam,应该是“心智”,而不是“明” :) 这就是iPhone的自动更正技术... :/ - Bohemian
我曾经使用过Void,或许是不寻常的,来解决在扩展带有更多参数的方法时出现的冲突(不要问为什么)。如果需要将methodA(String)扩展为methodA(String, String),但是methodA(String, String)已经存在并且具有不同的含义,我会将第一个方法扩展为methodA(String, Void, String)(并将其称为methodA(strA, (Void)null, strB))。当然,我可以将其命名为methodB(String, String),但有时候不行。(再次强调,不要问为什么!) - ADTC
显示剩余3条评论

47

第一个函数是一个单参数函数,必须提供并且只能接受值为null的有效值。除了null之外的任何值都不会编译通过。第二个函数不接受任何参数,并且将null传递给它也无法编译通过。


9
在函数参数中使用Void有什么意义? - Adam Lee
4
不,正如Bohemian所说,它的存在是为了能够代表一个空方法的返回值以便于反射。 - Confusion
1
那么,使用函数的Void参数的特定用例是什么? - Emre Tapcı

15
考虑来自Android系统AsyncTask<T1,T2,T3> API,它提供了三个钩子函数:
class AsyncTask<S, T, V> {
  void doInBackground(S...);
  void onProgressUpdate(T...);
  void onPostExecute(V);
}

当您扩展泛型类型AsyncTask<T1,T2,T3>时,可能不想使用进度结果钩子的参数,因此您的实现将如下所示:

class HTTPDownloader extends AsyncTask<URL, Void, Void> {
  void doInBackground(URL... urls) {}
  void onProgressUpdate(Void... unused) {}
  void onPostExecute(Void unused) {}
}

你可以使用null参数调用这些方法,因为Void无法被实例化。


Void ... 是必需的,以保留参数计数,使 onProgressUpdate 正确地覆盖父类中的同名方法(因为在 Java 中,如果不传递参数,则会导致它成为一个新函数而不是覆盖)。 - Zags

6
如果 `Void` 其实不是类型参数的一个实例(在这种情况下,它显然是有意义的),那么声明一个 `handle(Void)` 也是有意义的,如果你的 `handle` 方法受到超语言契约的约束,该契约规定想要参与某种协议的对象必须实现一个具有一个参数的 `handle` 方法,无论实际参数类型如何。现在,可能会有一种特殊情况的实现无法处理任何东西,除了 `null`,因此对于这样的实现,声明 `handle(Void)` 是有意义的。

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