Java Void 引用类型的用途?

Posted

技术标签:

【中文标题】Java Void 引用类型的用途?【英文标题】:Uses for the Java Void Reference Type? 【发布时间】:2010-10-13 05:38:48 【问题描述】:

有一个 Java Void -- 大写 V-- reference type。我见过它使用的唯一情况是参数化Callables

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

Java Void 引用类型还有其他用途吗?除了null,它还能被分配任何东西吗?如果有,你有例子吗?

【问题讨论】:

dzone.com/articles/why-does-void-class-exist-jdk 在Java8中,新增功能:use Function interface to replace Consumer or Supplier 【参考方案1】:

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

它也经常用于例如Map 值(尽管Collections.newSetFromMap 使用Boolean,因为地图不必接受null 值)和java.security.PrivilegedAction

【讨论】:

谁制定了这个约定?文档状态docs.oracle.com/javase/tutorial/java/generics/types.html“类型参数命名约定按照约定,类型参数名称是单个大写字母。” @barlop 这是参数而不是参数名称。也就是说,它是java.lang.Void 类型。 / 乔什·布洛赫 (Josh Bloch) 推广了该约定,尽管一旦您看到它,它就是显而易见的选择。 该博客条目已失效【参考方案2】:

您可以使用反射创建 Void 实例,但它们对任何事情都没有用。 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

【讨论】:

+1 用于实例化文档中说不可实例化的类。我也这样做了,我同意实例化的 Void 是没用的。 构造函数 cv = Void.class.getDeclaredConstructor(); cv.setAccessible(true);无效 v = cv.newInstance(); System.out.println(v); // ;) 作为练习,尝试使用反射创建一个新类,看看会发生什么。 我从 sun.reflect.InstantiationExceptionConstructorAccessorImpl 得到一个 java.lang.InstantiationException 。 :( 这是特定于实现的,可能随时更改。不能保证该类有一个无参数的构造函数,即使它确实有一个可以做任何事情的构造函数(可能是System.exit(0))。我倾向于使用private Void() throw new Error(); 的构造函数编写实用程序类。有些人可能更喜欢无值枚举。【参考方案3】:

Future&lt;Void&gt; 就像魅力一样。 :)

【讨论】:

使用Future&lt;?&gt; 更为常见(例如,在 Guava 中),因为未来通常会有一个合法值(非Void 类型),但在不使用的上下文中使用'不在乎价值。 CompletableFuture&lt;Void&gt; 的作用也是一种魅力。【参考方案4】:

鉴于有no public constructors,我会说它不能被分配除null以外的任何东西。如您的示例所示,我仅将其用作“我不需要使用此通用参数”的占位符。

它也可以用于反射,从它的Javadoc 所说:

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

【讨论】:

有趣的是,Oracle/Sun 如此描述它,因为 null 是所有类型的实例。无论如何,正如你所说,它的纯粹含义是“我可以在这里写任何类型,因为我对它不感兴趣,所以我会放 Void 以确保阅读我的代码的人完全理解这一点”【参考方案5】:

所有原始包装类(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

【讨论】:

所以既有 Void.class 又有 void.class!【参考方案6】:

当您使用visitor pattern 时,如果您想确保返回值为空,则使用 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;
    

【讨论】:

【参考方案7】:

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

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

【讨论】:

我不相信这个。现在我面前没有 1.4 或更早的 JVM,但我相信 Method.getReturnType() 总是为 void 方法返回 void.class。 @Pour:我是说 before 泛型,我知道的唯一用途是保存 TYPE(如在 Void.TYPE 中),它在反射的方法中使用.getReturnType() 用于 void 方法。 它不知何故不返回Void。请看***.com/questions/34248693/…【参考方案8】:

由于不能实例化Void,所以可以使用Apache commons Null object,所以

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

在第一行,你有一个对象,所以aNullObject != null 成立,而在第二行没有引用,所以noObjectHere == null 成立

为了回答发帖者的原始问题,这个的用法是区分“无”和“无”,它们是完全不同的东西。

PS:对 Null 对象模式说不

【讨论】:

【参考方案9】:

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&lt;T&gt; .... 是一个通用接口,所以我提供Void 因为泛型不接受原始类型

【讨论】:

【参考方案10】:

当您不需要 Attachment 对象时,它也常用于 Async-IO 完成回调。在这种情况下,您将 IO 操作指定为 null 并实现 CompletionHandler&lt;Integer,Void&gt;

【讨论】:

【参考方案11】:

这可能很少见,但有一次,我在方面类中使用了Void

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

 @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
         

【讨论】:

以上是关于Java Void 引用类型的用途?的主要内容,如果未能解决你的问题,请参考以下文章

java中方法的返回类型都有哪些?可以引用数据类型吗?举例说明

为啥要使用 void 指针来取消引用数据类型的变量?

引用类型擦除的 void*

java中的引用类型的对象存放在哪里

C++引用的进一步深入学习

成员引用基类型“void”不是结构或联合 (OBJ-C)