Sử dụng cho loại tham chiếu Void Java?


163

Có một kiểu tham chiếu Java Void- chữ hoa V-- . Tình huống duy nhất tôi từng thấy nó được sử dụng là tham số hóa s Callable

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

Có cách sử dụng nào khác cho Voidkiểu tham chiếu Java không? Nó có thể được chỉ định bất cứ điều gì khác hơn null? Nếu có, bạn có ví dụ không?



Câu trả lời:


116

Voidđã trở thành quy ước cho một đối số chung mà bạn không quan tâm. Không có lý do tại sao bạn nên sử dụng bất kỳ loại không khả thi nào khác, chẳng hạn như System.

Nó cũng thường được sử dụng trong các Mapgiá trị ví dụ (mặc dù Collections.newSetFromMapsử dụng Booleanlàm bản đồ không phải chấp nhận nullgiá trị) và java.security.PrivilegedAction.

Tôi đã viết một mục weblog vào Voidmột vài năm trước.


ai thực hiện quy ước đó? trạng thái docs docs.oracle.com/javase/tutorial/java/generics/types.html "Loại tham số đặt tên tham số theo quy ước, tên tham số loại là chữ cái in hoa đơn."
barlop 12/2/2015

4
@barlop Đó là đối số không phải là tên tham số. Đó là, nó là loại java.lang.Void. / Josh Bloch đã phổ biến quy ước, mặc dù một khi bạn đã thấy nó, đó là sự lựa chọn rõ ràng.
Tom Hawtin - tackline

2
Mục blog đó đã chết
mFeinstein

51

Bạn có thể tạo cá thể của Void bằng phản xạ, nhưng chúng không hữu ích cho bất cứ điều gì. Vô hiệu là một cách để chỉ ra một phương thức chung không trả về gì cả.

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

in một cái gì đó như

I have a java.lang.Void@75636731

22
+1 để khởi tạo một lớp mà tài liệu nói là không thể chứng minh được. Tôi cũng đã làm điều này và tôi đồng ý rằng Voids tức thời là vô dụng.
Luke Woodward

1
Trình xây dựng <Void> cv = Void. Class.getDeclaredConstructor (); cv.setAccessible (đúng); Vô hiệu v = cv.newInstance (); System.out.println (v); //;)
Peter Lawrey

Như một bài tập, hãy thử tạo một Class mới bằng cách sử dụng các phản xạ và xem điều gì sẽ xảy ra.
Peter Lawrey

Tôi đã nhận được java.lang.InstantiationException từ sun.reflect.InstantiationExceptionConstructorAccessorImpl. :(
Luke Woodward

7
Đây là thực hiện cụ thể và có thể thay đổi bất cứ lúc nào. Không có gì đảm bảo rằng lớp có một hàm tạo không có đối số và ngay cả khi nó có một hàm có thể làm bất cứ điều gì (có lẽ System.exit(0)). Tôi có xu hướng viết các lớp tiện ích với một hàm tạo như private Void() { throw new Error(); }. Một số có thể thích một enum không có giá trị.
Tom Hawtin - tackline

27

Future<Void>hoạt động như quyến rũ. :)


6
Nó phổ biến hơn (ví dụ, trong ổi) để sử dụng Future<?>, vì tương lai thường sẽ có một giá trị hợp pháp (không thuộc Voidloại) nhưng được sử dụng trong bối cảnh không quan tâm đến giá trị.
David Phillips

1
CompletableFuture<Void>làm việc như một sự quyến rũ là tốt.
andrybak

19

Cho rằng không có nhà xây dựng công cộng , tôi sẽ nói rằng nó không thể được chỉ định bất cứ điều gì khác hơn null. Tôi chỉ sử dụng nó như một trình giữ chỗ cho "Tôi không cần sử dụng tham số chung này", như ví dụ của bạn cho thấy.

Nó cũng có thể được sử dụng để phản chiếu, từ những gì Javadoc nói:

Lớp Void là một lớp giữ chỗ không đáng tin cậy để giữ một tham chiếu đến đối tượng Class đại diện cho khoảng trống từ khóa Java.


Đủ hài hước để thấy Oracle / Sun mô tả nó theo cách như null là một ví dụ của tất cả các loại. Nhưng dù sao, như bạn nói, ý nghĩa tinh khiết của nó là: "Tôi có thể viết bất kỳ loại ở đây là tôi không quan tâm đến nó, vì vậy tôi sẽ đưa Void để đảm bảo người đọc mã của tôi hiểu chính xác điều đó"
Snicolas

17

Tất cả các lớp wrapper nguyên thủy ( Integer, Byte, Boolean, Double, vv) chứa một tham chiếu đến lớp nguyên thủy tương ứng trong một tĩnh TYPElĩnh vực, ví dụ:

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

Voidban đầu được tạo như một nơi nào đó để đặt một tham chiếu đến voidloại:

Void.TYPE == void.class

Tuy nhiên, bạn không thực sự đạt được bất cứ điều gì bằng cách sử dụng Void.TYPE. Khi bạn sử dụng void.class, rõ ràng hơn là bạn đang làm gì đó với voidloại.

Ở một khía cạnh khác, lần cuối cùng tôi dùng thử, BeanShell đã không nhận ra void.class, vì vậy bạn phải sử dụng Void.TYPEnó.


8
Vì vậy, có cả Void. Class và void. Class!
Tom Anderson

8

Khi bạn sử dụng mẫu khách truy cập , có thể sạch hơn khi sử dụng Void thay vì Object khi bạn muốn chắc chắn rằng giá trị trả về sẽ là null

Thí dụ

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

   OUT visit(Leaf2 leaf);
}

Khi bạn sẽ triển khai khách truy cập của mình, bạn có thể đặt OUT thành Void một cách rõ ràng để bạn biết khách truy cập của mình sẽ luôn trả về null, thay vì sử dụng 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

Trước generic, nó đã được tạo cho API phản chiếu, để giữ TYPE được trả về bởi Method.getReturnType () cho một phương thức void, tương ứng với các lớp kiểu nguyên thủy khác.

EDIT: Từ JavaDoc of Void: "Lớp Void là một lớp giữ chỗ không đáng tin cậy để giữ một tham chiếu đến đối tượng Class đại diện cho khoảng trống từ khóa Java". Trước Generics, tôi biết không sử dụng gì ngoài phản xạ.


Tôi không tin điều này. Bây giờ tôi không có JVM 1.4 hoặc sớm hơn trước mặt tôi, nhưng tôi tin rằng Method.getReturnType () luôn trả về void. Class cho phương thức void.
Luke Woodward

@Pour: Tôi đang nói rằng trước khi dùng thuốc generic, cách sử dụng duy nhất tôi biết là giữ TYPE (như trong Void.TYPE), được sử dụng trong Phương thức phản chiếu.getReturnType () cho phương thức void.
Lawrence Dol

Nó bằng cách nào đó không trở lại Void. Vui lòng xem stackoverflow.com/questions/34248693/ Lời
Alireza Fattahi

3

Khi bạn không thể khởi tạo Void, bạn có thể sử dụng đối tượng Null Apache commons , vì vậy

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

trong dòng đầu tiên, bạn có một đối tượng, vì vậy aNullObject != nullgiữ, trong khi ở dòng thứ hai không có tham chiếu, vì vậy noObjectHere == nullgiữ

Để trả lời câu hỏi ban đầu của người đăng, cách sử dụng này là để phân biệt giữa "không có gì" và "không có gì", đó là những điều hoàn toàn khác nhau.

PS: Nói không với mẫu đối tượng Null


1

Void được tạo ra để bọc loại khoảng trống nguyên thủy của nó. Mỗi loại nguyên thủy đều có loại Tham chiếu tương ứng. Void được sử dụng để khởi tạo một lớp chung hoặc sử dụng một phương thức chung, Một phù thủy đối số chung mà bạn không quan tâm. Và đây là một ví dụ ...

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

Ở đây, như bạn có thể thấy, tôi không muốn bất cứ thứ gì từ máy chủ mà tôi yêu cầu tạo đăng ký mới, nhưng public interface AsyncCallback<T> { .... }là một giao diện chung vì vậy tôi cung cấp Void vì các tướng không chấp nhận các kiểu nguyên thủy


0

Nó cũng thường được sử dụng trong các cuộc gọi lại hoàn thành Async-IO khi bạn không có nhu cầu về một Attachmentđối tượng. Trong trường hợp đó, bạn chỉ định null cho hoạt động IO và thực hiện CompletionHandler<Integer,Void>.


0

Nó có thể là trường hợp hiếm gặp nhưng một lần, tôi đã sử dụng Voidtrong các lớp khía cạnh.

Đây là một khía cạnh chạy sau các phương thức có @Logchú thích và ghi lại phương thức được trả về và một số thông tin nếu kiểu trả về của phương thức không có giá trị.

 @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
         }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.