Используется для Java Void Reference Type?

163

Существует Java Void- прописной V-- ссылочный тип . Единственная ситуация , которую я когда - либо видел , как это используется параметризация Callableсек

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

Существуют ли другие способы использования Voidссылочного типа Java ? Можно ли когда-нибудь назначить что-то кроме null? Если да, у вас есть примеры?

Жюльен Частанг
источник

Ответы:

116

Voidстало соглашением для общего аргумента, который вас не интересует. Нет никаких причин, по которым вы должны использовать любой другой неинстанцируемый тип, такой как System.

Это также часто используется, например, в Mapзначениях (хотя Collections.newSetFromMapиспользование в Booleanкачестве карт не должно принимать nullзначения) и java.security.PrivilegedAction.

Я написал запись раздела на Voidнесколько лет назад.

Том Хотин - Tackline
источник
кто сделал это соглашение? состояние документов docs.oracle.com/javase/tutorial/java/generics/types.html «Соглашения об именах параметров типов По соглашению имена параметров типов состоят из одинарных прописных букв».
Бароп
4
@barlop Это аргумент, а не имя параметра. То есть это тип java.lang.Void. / Джош Блох популяризировал соглашение, хотя, как только вы его увидели, это очевидный выбор.
Том Хотин - tackline
2
Эта запись в блоге мертва
mFeinstein
51

Вы можете создать экземпляр 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
Питер Лори
источник
22
+1 за создание экземпляра класса, который, как говорится в документации, нереализуем. Я тоже это сделал и согласен с тем, что созданные пустоты бесполезны.
Люк Вудворд
1
Constructor <Void> cv = Void.class.getDeclaredConstructor (); cv.setAccessible (истина); Void v = cv.newInstance (); System.out.println (v); //;)
Питер Лори
В качестве упражнения попробуйте создать новый класс, используя отражения, и посмотрите, что произойдет.
Питер Лори
Я получил исключение java.lang.InstantiationException от sun.reflect.InstantiationExceptionConstructorAccessorImpl. :(
Люк Вудворд
7
Это зависит от реализации и может измениться в любое время. Нет гарантии, что у класса есть конструктор без аргументов, и даже если у него есть конструктор, который может делать что угодно (возможно System.exit(0)). Я склонен писать вспомогательные классы с конструктором как private Void() { throw new Error(); }. Некоторые могут предпочесть перечисление без значения.
Том Хотин - tackline
27

Future<Void>работает как шарм. :)

Александр Темерев
источник
6
Это более распространено (например, в Гуаве) для использования Future<?>, поскольку будущее часто будет иметь законное значение (не Voidтипового), но используется в контексте, который не заботится о значении.
Дэвид Филлипс
1
CompletableFuture<Void>работает как шарм.
Андрыбак
19

Учитывая, что нет открытых конструкторов , я бы сказал, что нельзя назначить ничего, кроме null. Я использовал его только как заполнитель для «мне не нужно использовать этот универсальный параметр», как показывает ваш пример.

Это может также использоваться в рефлексии, из того, что говорит его Javadoc :

Класс Void - это нереализуемый класс-заполнитель для хранения ссылки на объект Class, представляющий ключевое слово Java void.

Майкл Майерс
источник
Достаточно забавно видеть, что Oracle / Sun описывают это так, поскольку ноль - это экземпляр всех типов. В любом случае, как вы сказали, чистый смысл этого слова таков: «Я мог бы написать здесь любой тип, поскольку он мне не интересен, поэтому я поставлю Void, чтобы люди, читающие мой код, точно понимали это»
Snicolas
17

Все примитивные классы обертки ( Integer, Byte, Boolean, Doubleи т.д.) содержат ссылку на соответствующем примитивный класс в статическом 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

Когда вы используете шаблон посетителя, может быть лучше использовать Void вместо Object, если вы хотите быть уверены, что возвращаемое значение будет нулевым

пример

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

   OUT visit(Leaf2 leaf);
}

Когда вы реализуете своего посетителя, вы можете явно установить для OUT значение Void, чтобы вы знали, что ваш посетитель всегда будет возвращать ноль вместо использования 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 отражения, чтобы содержать TYPE, возвращаемый Method.getReturnType () для метода void, соответствующего другим классам примитивных типов.

РЕДАКТИРОВАТЬ: Из JavaDoc Void: «Класс Void является нереализуемым классом-заполнителем для хранения ссылки на объект Class, представляющий ключевое слово Java void». До Generics я не знаю ничего, кроме размышлений.

Лоуренс Дол
источник
Я не верю этому. У меня сейчас нет 1.4 или более ранней JVM, но я считаю, что Method.getReturnType () всегда возвращал void.class для метода void.
Люк Вудворд
@Pour: я говорю, что до обобщения, единственное известное мне использование - это удерживать TYPE (как в Void.TYPE), который использовался в методе отражения.getReturnType () для метода void.
Лоуренс Дол
Это как-то не возвращается Void. Пожалуйста, смотрите stackoverflow.com/questions/34248693/…
Алиреза Фаттахи
3

Поскольку вы не можете создать экземпляр Void, вы можете использовать Apache commons Null object , поэтому

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

в первой строке у вас есть объект, так что aNullObject != nullдержит, в то время как во второй строке нет ссылки, поэтому noObjectHere == nullдержит

Чтобы ответить на оригинальный вопрос автора, для этого нужно различать «ничто» и «ничто», которые являются совершенно разными вещами.

PS: Скажи нет объектному образцу Null

Мар Бар
источник
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

Он также обычно используется в обратных вызовах завершения Async-IO, когда у вас нет необходимости в Attachmentобъекте. В этом случае вы указываете null для операции ввода-вывода и реализуете CompletionHandler<Integer,Void>.

Экес
источник
0

Это может быть редким случаем, но однажды я использовал 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
         }
}
Алиреза Фаттахи
источник