Làm thế nào để sử dụng Số nguyên không dấu trong Java 8 và Java 9?


81

Trong Oracle "Primitive kiểu dữ liệu" trang , nó đề cập đến rằng Java 8 thêm hỗ trợ cho ints unsigned và chờ đợi:

int: Theo mặc định, intkiểu dữ liệu là một số nguyên bổ sung 32-bit có dấu của hai, có giá trị nhỏ nhất là −2 31 và giá trị lớn nhất là 2 31 −1. Trong Java SE 8 trở lên, bạn có thể sử dụng intkiểu dữ liệu để đại diện cho số nguyên 32 bit không dấu, có giá trị nhỏ nhất là 0 và giá trị lớn nhất là 2 32 −1. Sử dụng Integerlớp để sử dụng intkiểu dữ liệu là một số nguyên không dấu. Xem phần Các lớp số để biết thêm thông tin. Các phương thức tĩnh như compareUnsigned, divideUnsignedv.v. đã được thêm vào Integerlớp để hỗ trợ các phép toán số học cho các số nguyên không dấu.

long: Kiểu longdữ liệu là số nguyên bổ sung 64-bit hai của. Dấu longcó giá trị nhỏ nhất là −2 63 và giá trị lớn nhất là 2 63 −1. Trong Java SE 8 trở lên, bạn có thể sử dụng longkiểu dữ liệu để biểu thị 64-bit không dấu long, có giá trị nhỏ nhất là 0 và giá trị lớn nhất là 2 64 −1. Sử dụng kiểu dữ liệu này khi bạn cần phạm vi giá trị rộng hơn giá trị được cung cấp bởi int. Các Longlớp cũng chứa các phương pháp thích compareUnsigned, divideUnsignedvv để hỗ trợ hoạt động số học cho unsigned long.

Tuy nhiên, tôi không tìm thấy cách nào để khai báo một số nguyên hoặc dài không dấu. Ví dụ, đoạn mã sau đưa ra thông báo lỗi trình biên dịch "chữ nằm ngoài phạm vi" (tất nhiên là tôi đang sử dụng Java 8), khi nó phải nằm trong phạm vi (giá trị được gán chính xác là 2 64 −1) :

public class Foo {
    static long values = 18446744073709551615L;
    
    public static void main(String[] args){
        System.out.println(values);
    }  
}

Vậy có cách nào để khai báo int unsigned hay long không?


2
Điều gì được trả về trong hằng số Long.MAX_VALUE của bạn trong java 8?
Bruno Franco

21
Không có số nguyên không dấu hoặc kiểu dài không dấu. Nếu bạn sử dụng một trong các phương thức mới, phương thức đó sẽ xử lý một số nguyên 32 bit hoặc 64 bit như thể nó chưa được ký. Nhưng đó là tất cả. Loại của biến sẽ vẫn được ký và bạn phải nhớ rằng bạn đang sử dụng nó như một số chưa có dấu. Họ không thêm các ký tự không dấu, nhưng có thể họ sẽ thêm chúng vào Java 9 nếu có đủ người sửa lỗi chúng. :)
ajb

5
Họ không thực sự thay đổi bất cứ điều gì, ngoài việc thêm các phương pháp mới.
Hot Licks

4
Theo như tôi có thể nói, tất cả những gì họ đã làm là thêm các phương thức có thể trả về các giá trị không dấu, nhưng không cho phép bạn khai báo các giá trị không dấu. Thật là ngớ ngẩn nếu bạn hỏi tôi, và một nỗi đau thực sự. Tôi tự hỏi nếu một cách sẽ sử dụng Integer.divideUnsigned, với một tham số là 1, tham số còn lại là bất kỳ số nào bạn muốn được coi là không dấu. Sẽ làm việc theo những gì tôi có thể nói, nhưng có vẻ là cách làm thực sự ngớ ngẩn.
cluemein

@ajb làm cách nào để tôi có thể hỗ trợ bất kỳ sự trợ giúp nào trong quá trình "sửa lỗi" để cuối cùng thấy được dấu phù hợp trong Java? :)
Matthieu

Câu trả lời:


51

Theo tài liệu bạn đã đăng và bài đăng trên blog này - không có sự khác biệt nào khi khai báo nguyên thủy giữa int / long không dấu và một giá trị có dấu. "Hỗ trợ mới" là việc bổ sung các phương thức tĩnh trong các lớp Integer và Long, ví dụ: Integer.divideUnsigned . Nếu bạn không sử dụng các phương pháp đó, thì độ dài "không dấu" của bạn trên 2 ^ 63-1 chỉ là một độ dài đơn thuần cũ với giá trị âm.

Từ cách đọc lướt nhanh, có vẻ như không có cách nào để khai báo các hằng số nguyên trong phạm vi bên ngoài +/- 2 ^ 31-1 hoặc +/- 2 ^ 63-1 cho độ dài. Bạn sẽ phải tính toán thủ công giá trị âm tương ứng với giá trị dương nằm ngoài phạm vi của mình.


85

Chà, ngay cả trong Java 8, longintvẫn được ký, chỉ một số phương thức coi chúng như thể chúng chưa được ký . Nếu bạn muốn viết longchữ không dấu như vậy, bạn có thể làm

static long values = Long.parseUnsignedLong("18446744073709551615");

public static void main(String[] args) {
    System.out.println(values); // -1
    System.out.println(Long.toUnsignedString(values)); // 18446744073709551615
}

5
Một quan sát mà tôi thấy với điều này là thứ tự bị hỏng. Nếu tôi nhận được một long không dấu từ một hệ thống nào đó (nhân tiện, Twitter cung cấp các ID như vậy) và muốn sắp xếp chúng, có lẽ vì tôi biết chúng theo thứ tự thời gian, thì mọi thứ ngoài Long.MAX_VALUE sẽ thực sự hiển thị trước 0 dưới dạng âm . với thực hiện của Java :-( Thay vào đó, dường như người ta cũng phải chuyển nó xuống mà unsigned 0 bản đồ để ký Long.MIN_VALUE.
David Smiley

10
@DavidSmiley Điểm tốt. Để sắp xếp chờ đợi unsigned, sử dụng Long.compareUnsigned , hoặc vượt qua phương pháp đó như là một so sánh chức năng sắp xếp,
kajacx

26
    // Java 8
    int vInt = Integer.parseUnsignedInt("4294967295");
    System.out.println(vInt); // -1
    String sInt = Integer.toUnsignedString(vInt);
    System.out.println(sInt); // 4294967295

    long vLong = Long.parseUnsignedLong("18446744073709551615");
    System.out.println(vLong); // -1
    String sLong = Long.toUnsignedString(vLong);
    System.out.println(sLong); // 18446744073709551615

    // Guava 18.0
    int vIntGu = UnsignedInts.parseUnsignedInt(UnsignedInteger.MAX_VALUE.toString());
    System.out.println(vIntGu); // -1
    String sIntGu = UnsignedInts.toString(vIntGu);
    System.out.println(sIntGu); // 4294967295

    long vLongGu = UnsignedLongs.parseUnsignedLong("18446744073709551615");
    System.out.println(vLongGu); // -1
    String sLongGu = UnsignedLongs.toString(vLongGu);
    System.out.println(sLongGu); // 18446744073709551615

    /**
     Integer - Max range
     Signed: From −2,147,483,648 to 2,147,483,647, from −(2^31) to 2^31 – 1
     Unsigned: From 0 to 4,294,967,295 which equals 2^32 − 1

     Long - Max range
     Signed: From −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807, from −(2^63) to 2^63 − 1
     Unsigned: From 0 to 18,446,744,073,709,551,615 which equals 2^64 – 1
     */

9
Nên thêm một số giải thích, không chỉ là ném mã ra khỏi đó.
cluemein

20

Không có cách nào để khai báo một long hoặc int không dấu trong Java 8 hoặc Java 9. Nhưng một số phương thức xử lý chúng như thể chúng chưa có dấu, ví dụ:

static long values = Long.parseUnsignedLong("123456789012345678");

nhưng đây không phải là khai báo của biến.


3
tôi thương tại sao không. họ có thể dễ dàng thêm các loại uint và ulong
EKanadily

@docesam trong nàynày docu là giải thích chi tiết. trong ngắn hạn, chỉ một phương thức cho thao tác không dấu đối với lớp Integer đã được thêm vào. và nếu họ có thể dễ dàng thêm vào, tôi không biết tại sao họ không làm điều đó ;-)
1ac0

@ Ladislav DANKO có những người thận trọng, và có những người khác. tôi không chắc liệu - trong trường hợp này - nó có thận trọng hay không, nhưng tôi ấn tượng rằng oracle không quá thận trọng.
EKanadily

1
@docesam Không, họ không thể có "các loại uint và ulong dễ dàng thêm vào". Điều đó sẽ yêu cầu đại tu JLS, JVM spec, JNI, rất nhiều thư viện (như java.util.Arrays), phản chiếu, và nhiều hơn nữa.
Nayuki

1
@ Michaelangel007 Này, tôi nghĩ chúng ta đang tiếp cận chủ đề này với các giả định nền tảng khác nhau. Bạn muốn gửi cho tôi một email và chúng ta sẽ nói về chi tiết?
Nayuki

4

Nếu sử dụng thư viện của bên thứ ba là một tùy chọn, thì có jOOU (một thư viện phụ từ jOOQ ), cung cấp các loại trình bao bọc cho các số nguyên không dấu trong Java. Điều đó không hoàn toàn giống với việc hỗ trợ kiểu nguyên thủy (và do đó là mã byte) cho các kiểu không dấu, nhưng có lẽ nó vẫn đủ tốt cho trường hợp sử dụng của bạn.

import static org.joou.Unsigned.*;

// and then...
UByte    b = ubyte(1);
UShort   s = ushort(1);
UInteger i = uint(1);
ULong    l = ulong(1);

Tất cả các kiểu này đều mở rộng java.lang.Numbervà có thể được chuyển đổi thành các kiểu nguyên thủy bậc cao hơn và BigInteger.

(Tuyên bố từ chối trách nhiệm: Tôi làm việc cho công ty đứng sau những thư viện này)

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.