用于Java Void参考类型?


163

有一个Java Void(大写的V)引用类型。我见过的唯一情况是参数化Callables

final Callable<Void> callable = new Callable<Void>() {
            public Void call() {
                foobar();
                return null;
            }
        };

Java Void引用类型还有其他用途吗?除此以外,还能分配其他任何东西null吗?如果是,您有例子吗?



在Java8中,它具有新功能:使用功能接口替代消费者或供应商
puppylpg

Answers:


116

Void已成为您不感兴趣的泛型参数的约定。没有理由应使用任何其他非实例化类型,例如System

它也经常在示例中使用Map的值(虽然Collections.newSetFromMap使用Boolean的地图不具有接受null值)和java.security.PrivilegedAction

我写了一篇博客文章Void几年前。


谁制定了这个公约?docs状态docs.oracle.com/javase/tutorial/java/generics/types.html “类型参数命名约定按照约定,类型参数名称是单个大写字母。”
barlop 2015年

4
@barlop这是参数而不是参数名称。也就是说,它是type java.lang.Void。/约什·布洛赫(Josh Bloch)推广了该约定,尽管一旦您看到它,它就是显而易见的选择。
Tom Hawtin-大头钉

2
那博客条目已经死了
mFeinstein '18

51

您可以使用反射创建Void实例,但是它们对任何事情都没有用。无效是一种指示通用方法不返回任何内容的方法。

Constructor<Void> constructor = Void.class.getDeclaredConstructor();
constructor.setAccessible(true);
Void v = constructor.newInstance();
System.out.println("I have a " + v);

打印类似

I have a java.lang.Void@75636731

22
+1用于实例化文档所说的不可实例化的类。我也这样做了,我同意实例化的Voids是没有用的。
路加·伍德沃德

1
Constructor <Void> cv = Void.class.getDeclaredConstructor(); cv.setAccessible(true); 虚空v = cv.newInstance(); System.out.println(v); //;)
彼得·劳瑞

作为练习,尝试使用反射创建一个新的类,然后看看会发生什么。
彼得·劳瑞

我从sun.reflect.InstantiationExceptionConstructorAccessorImpl获得了java.lang.InstantiationException。:(
卢克·伍德沃德

7
这是特定于实现的,可以随时更改。无法保证该类具有no-arg构造函数,即使它确实具有可以执行任何操作的(也许System.exit(0))。我倾向于用构造函数编写实用程序类private Void() { throw new Error(); }。有些人可能更喜欢无值枚举。
汤姆·哈特芬


19

鉴于没有公共构造函数,我想说的是除了它之外别无其他东西null。如您的示例所示,我仅将其用作“我不需要使用此通用参数”的占位符。

从它的Javadoc说起,它也可以用于反思:

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


有趣的是,看到Oracle / Sun用这种方式描述它时,因为null是所有类型的实例。无论如何,正如您所说,它的纯粹含义是“我可以在这里写任何类型,因为我对此不感兴趣,所以我将
放空

17

所有的原始包装类(IntegerByteBooleanDouble,等等)包含在静态到对应的原语类的引用TYPE字段,例如:

Integer.TYPE == int.class
Byte.TYPE == byte.class
Boolean.TYPE == boolean.class
Double.TYPE == double.class

Void最初是在某个地方创建的,以引用该void类型:

Void.TYPE == void.class

但是,使用并不会带来任何好处Void.TYPE。使用时void.class,很明显您正在使用该void类型进行操作。

顺便说一句,我上一次尝试时,BeanShell无法识别void.class,因此您必须在那使用Void.TYPE它。


8
因此,既有Void.class也有void.class!
汤姆·安德森(

8

当您使用访客模式时,当您要确保返回值将为null时,可以更干净地使用Void而不是Object

public interface LeavesVisitor<OUT>
{
   OUT visit(Leaf1 leaf);

   OUT visit(Leaf2 leaf);
}

实现访问者时,可以将OUT显式设置为Void,以便您知道访问者将始终返回null,而不是使用Object

public class MyVoidVisitor implements LeavesVisitor<Void>
{
    Void visit(Leaf1 leaf){
        //...do what you want on your leaf
        return null;
    }

    Void visit(Leaf2 leaf){
        //...do what you want on your leaf
        return null;
    }
}

5

在泛型之前,它是为反射API创建的,用于保存由Method.getReturnType()返回的TYPE为void方法,该方法与其他原始类型类相对应。

编辑:从Void的JavaDoc:“ Void类是一个无法实例化的占位符类,用于保存对表示Java关键字void的Class对象的引用。在泛型之前,我知道除了反射之外没有其他用途。


我不相信这一点。我现在没有1.4或更早版本的JVM,但我相信Method.getReturnType()始终会为void方法返回void.class。
路加·伍德沃德

@Pour:我说的是泛型之前,我知道的唯一用途是保存TYPE(如Void.TYPE一样),该类型在反射的Method.getReturnType()中用于void方法。
劳伦斯·多尔

它以某种方式不会返回Void。请参阅stackoverflow.com/questions/34248693/...
阿里Fattahi

3

由于无法实例化Void,因此可以使用Apache commons Null对象,因此

Null aNullObject = ObjectUtils.Null;
Null noObjectHere = null;

在第一行中,你有一个对象,所以aNullObject != null保持,而在第二行中没有参考,因此noObjectHere == null保持

为了回答发布者的原始问题,其用法是区分“什么都没有”和“什么都没有”,这是完全不同的东西。

PS:对空对象模式说不


1

Void被创建为包装其原始void类型。每个基本类型都有对应的引用类型。Void用于实例化泛型类或泛型方法的使用,您不感兴趣的泛型参数。这里是一个示例...

public void onNewRegistration() {
    newRegistrationService.createNewUser(view.getUsername(), view.getPassword(),
            view.getInitialAmount(), view.getCurrency(), new AsyncCallback<Void>() {
      @Override
      public void onFailure(Throwable caught) {

      }

      @Override
      public void onSuccess(Void result) {
        eventBus.fireEvent(new NewRegistrationSuccessEvent());
      }
    });
  } 

如您所见,在这里,我不需要服务器要求创建新注册的任何内容,但是public interface AsyncCallback<T> { .... }它是通用接口,所以我提供了Void,因为通用对象不接受原始类型


0

当您不需要Attachment对象时,它也常用于Async-IO完成回调。在这种情况下指定null到IO操作和实施CompletionHandler<Integer,Void>


0

可能很少见,但是有一次,我Void在方面类中使用过。

这是一个在具有@Log注释的方法之后运行的一个方面,并且记录返回的方法和一些信息(如果方法的返回类型不为空)。

 @AfterReturning(value = "@annotation(log)", 
       returning = "returnValue", 
       argNames = "joinPoint, log, returnValue"
      )
    public void afterReturning(final JoinPoint joinPoint, final Log log,
            final Object returnValue) {

            Class<?> returnType = ((MethodSignature) joinPoint.getSignature())
            .getReturnType();
           if (Void.class.isAssignableFrom (returnType)) ) {
            //Do some log
         }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.