Verwendung für den Java Void-Referenztyp?


163

Es gibt einen Java Void- V - Referenztyp in Großbuchstaben . Die einzige Situation, die ich jemals gesehen habe, ist die Parametrisierung von Callables

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

Gibt es andere Verwendungszwecke für den Java- VoidReferenztyp? Kann es jemals etwas anderes zugewiesen werden als null? Wenn ja, haben Sie Beispiele?



Antworten:


116

Voidist zur Konvention für ein generisches Argument geworden, an dem Sie nicht interessiert sind. Es gibt keinen Grund, warum Sie einen anderen nicht instanziierbaren Typ verwenden sollten, wie z System.

Es wird auch häufig in beispielsweise MapWerten verwendet (obwohl Collections.newSetFromMapVerwendungen Booleanals Karten keine nullWerte akzeptieren müssen ) und java.security.PrivilegedAction.

Ich habe vor ein paar Jahren einen Weblog-Eintrag geschriebenVoid .


Wer hat diese Konvention gemacht? Der Dokumentstatus docs.oracle.com/javase/tutorial/java/generics/types.html "Konventionen zur Benennung von Typparametern Standardmäßig sind Typparameternamen einzelne Großbuchstaben."
Barlop

4
@barlop Es ist das Argument, nicht der Parametername. Das heißt, es ist der Typ java.lang.Void. / Josh Bloch hat die Konvention populär gemacht, obwohl es die offensichtliche Wahl ist, wenn Sie sie einmal gesehen haben.
Tom Hawtin - Tackline

2
Dieser Blogeintrag ist tot
mFeinstein

51

Sie können eine Instanz von Void mithilfe von Reflexionen erstellen, diese sind jedoch für nichts nützlich. Void ist eine Möglichkeit, anzugeben, dass eine generische Methode nichts zurückgibt.

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

druckt so etwas wie

I have a java.lang.Void@75636731

22
+1 zum Instanziieren einer Klasse, die laut Dokumentation nicht instabil ist. Ich habe dies auch getan und bin damit einverstanden, dass instanziierte Voids nutzlos sind.
Luke Woodward

1
Konstruktor <Void> cv = Void.class.getDeclaredConstructor (); cv.setAccessible (true); Void v = cv.newInstance (); System.out.println (v); //;)
Peter Lawrey

Versuchen Sie als Übung, mithilfe von Reflexionen eine neue Klasse zu erstellen, und sehen Sie, was passiert.
Peter Lawrey

Ich habe eine java.lang.InstantiationException von sun.reflect.InstantiationExceptionConstructorAccessorImpl erhalten. :(
Luke Woodward

7
Dies ist implementierungsspezifisch und kann sich jederzeit ändern. Es gibt keine Garantie dafür, dass die Klasse einen Konstruktor ohne Argumente hat, und selbst wenn sie einen hat, der (vielleicht System.exit(0)) alles kann . Ich neige dazu, Utility-Klassen mit einem Konstruktor als zu schreiben private Void() { throw new Error(); }. Einige bevorzugen möglicherweise eine Aufzählung ohne Wert.
Tom Hawtin - Tackline


19

Da es keine öffentlichen Konstruktoren gibt , würde ich sagen, dass nichts anderes zugewiesen werden kann als null. Ich habe es nur als Platzhalter für "Ich muss diesen generischen Parameter nicht verwenden" verwendet, wie Ihr Beispiel zeigt.

Es könnte auch in der Reflexion verwendet werden, wie sein Javadoc sagt:

Die Void-Klasse ist eine nicht instabilisierbare Platzhalterklasse, die einen Verweis auf das Class-Objekt enthält, das das Java-Schlüsselwort void darstellt.


Es ist lustig genug zu sehen, wie Oracle / Sun es so beschreibt, dass null eine Instanz aller Art ist. Wie Sie sagten, ist die reine Bedeutung davon "Ich könnte hier jeden Typ schreiben, da ich nicht daran interessiert bin, also werde ich Void setzen, um sicherzustellen, dass Leute, die meinen Code lesen, genau das verstehen"
Snicolas

17

Alle die primitiven Wrapper - Klassen ( Integer, Byte, Boolean, Doubleusw.) enthalten einen Verweis auf die entsprechenden primitive Klasse in einem statischen TYPEFeld, zum Beispiel:

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

Voidwurde ursprünglich als irgendwo erstellt, um einen Verweis auf den voidTyp zu setzen:

Void.TYPE == void.class

Sie gewinnen jedoch nicht wirklich etwas mit Void.TYPE. Wenn Sie verwenden, ist void.classes viel klarer, dass Sie etwas mit dem voidTyp tun .

Abgesehen davon hat BeanShell das letzte Mal, als ich es ausprobiert habe, nicht erkannt void.class, sodass Sie es Void.TYPEdort verwenden müssen.


8
Es gibt also sowohl eine Void.class als auch eine void.class!
Tom Anderson

8

Wenn Sie das Besuchermuster verwenden, kann es sauberer sein, Void anstelle von Object zu verwenden, wenn Sie sicherstellen möchten, dass der Rückgabewert null ist

Beispiel

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

   OUT visit(Leaf2 leaf);
}

Wenn Sie Ihren Besucher implementieren, können Sie OUT explizit als ungültig festlegen, damit Sie wissen, dass Ihr Besucher immer null zurückgibt, anstatt Object zu verwenden

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

Vor Generics wurde es für die Reflection-API erstellt, um den von Method.getReturnType () zurückgegebenen TYPE für eine void-Methode zu speichern, die den anderen primitiven Typklassen entspricht.

BEARBEITEN: Aus dem JavaDoc von Void: "Die Void-Klasse ist eine nicht instabilisierbare Platzhalterklasse, die einen Verweis auf das Class-Objekt enthält, das das Java-Schlüsselwort void darstellt." Vor Generics ist mir keine andere Verwendung als Reflexion bekannt.


Ich glaube das nicht. Ich habe jetzt keine 1.4 oder frühere JVM vor mir, aber ich glaube, dass Method.getReturnType () für eine void-Methode immer void.class zurückgegeben hat.
Luke Woodward

@Pour: Ich sage, dass vor Generika die einzige mir bekannte Verwendung darin besteht, TYPE (wie in Void.TYPE) zu halten, das in Reflection's Method.getReturnType () für eine void-Methode verwendet wurde.
Lawrence Dol

Es kehrt irgendwie nicht zurück Void. Bitte sehen Sie stackoverflow.com/questions/34248693/…
Alireza Fattahi

3

Wie Sie nicht instantiate Void können, können Sie Apache commons Null - Objekt , so

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

in der ersten Zeile, Sie ein Objekt haben, so aNullObject != nullhält, während in der zweiten Zeile kein Hinweis gibt, so noObjectHere == nullhalten

Um die ursprüngliche Frage des Posters zu beantworten, besteht die Verwendung darin, zwischen "dem Nichts" und "nichts" zu unterscheiden, die völlig verschiedene Dinge sind.

PS: Sag Nein zum Null-Objektmuster


1

Void wird erstellt, um seinen primitiven Void-Typ zu umschließen. Jeder primitive Typ hat seinen entsprechenden Referenztyp. Void wird verwendet, um eine generische Klasse oder die Verwendung einer generischen Methode zu instanziieren. Ein generisches Argument, an dem Sie nicht interessiert sind. Und hier ist ein Beispiel ...

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());
      }
    });
  } 

Wie Sie sehen können, möchte ich hier nichts von dem Server, den ich zum Erstellen neuer Registrierungen auffordere, sondern public interface AsyncCallback<T> { .... }eine generische Schnittstelle, sodass ich Void bereitstelle, da Generika keine primitiven Typen akzeptieren


0

Es wird auch häufig bei Async-IO-Abschlussrückrufen verwendet, wenn Sie kein AttachmentObjekt benötigen . In diesem Fall geben Sie für die E / A-Operation und die Implementierung null an CompletionHandler<Integer,Void>.


0

Es mag selten vorkommen, aber einmal habe ich Voidin Aspektklassen verwendet.

Dies war ein Aspekt, der nach Methoden mit @LogAnmerkungen ausgeführt wird und die zurückgegebene Methode und einige Informationen protokolliert, wenn der Rückgabetyp der Methode nicht ungültig ist.

 @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
         }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.