ประกาศ int ที่ไม่ได้ลงนามใน Java


316

มีวิธีการประกาศ int ไม่ได้ลงนามใน Java?

หรือคำถามอาจมีกรอบเช่นนี้เช่นกัน: อะไรคือ Java เทียบเท่าของไม่ได้ลงนาม?

เพียงแค่จะบอกคุณบริบทที่ผมกำลังมองไปที่การใช้ Java String.hashcode()ของ ฉันต้องการทดสอบความเป็นไปได้ของการชนถ้าจำนวนเต็มเป็น 32 ที่ไม่ได้ลงนาม int


7
ไม่มีประเภทที่ไม่ได้ลงนามใน Java
Andrew Logvinov

1
โพสต์นี้อาจช่วยคุณstackoverflow.com/a/4449161/778687
tusar

2
ดูเหมือนจะไม่เป็นวิธีที่ AFAICT ที่เกี่ยวข้อง: stackoverflow.com/questions/430346/…
James Manning

11
ขึ้นอยู่กับวัตถุประสงค์ที่คุณพยายามจะทำ เพื่อจุดประสงค์ส่วนใหญ่จำนวนเต็มทั้งหมดใน Java จะถูกลงชื่อ อย่างไรก็ตามคุณสามารถรักษาลงนามจำนวนเต็มไม่ได้ลงนามในกรณีหนึ่งโดยเฉพาะ: คุณสามารถเปลี่ยนทางขวาโดยไม่ต้องเข้าสู่ระบบโดยใช้การขยายการดำเนินการแทน>>> >>
dasblinkenlight

คำตอบ:


310

Java ไม่ได้มีประเภทข้อมูลสำหรับจำนวนเต็มไม่ได้ลงนาม

คุณสามารถกำหนด a longแทนintถ้าคุณต้องการเก็บค่าขนาดใหญ่

คุณยังสามารถใช้จำนวนเต็มที่ลงนามราวกับว่ามันไม่ได้ลงนาม ประโยชน์ของการแสดงส่วนประกอบสองอย่างคือการทำงานส่วนใหญ่ (เช่นการบวกการลบการคูณและการเลื่อนซ้าย) นั้นเหมือนกันในระดับไบนารีสำหรับจำนวนเต็มที่ลงชื่อและไม่ได้ลงนาม อย่างไรก็ตามการดำเนินการบางอย่าง (การแบ่งการเปลี่ยนแปลงที่ถูกต้องการเปรียบเทียบและการคัดเลือก) นั้นแตกต่างกัน ในฐานะของ Java SE 8 วิธีการใหม่ในIntegerชั้นเรียนช่วยให้คุณสามารถใช้intชนิดข้อมูลเพื่อดำเนินการทางคณิตศาสตร์ที่ไม่ได้ลงนาม :

ใน Java SE 8 และใหม่กว่าคุณสามารถใช้ชนิดข้อมูล int เพื่อแทนค่าจำนวนเต็ม 32 บิตที่ไม่ได้ลงนามซึ่งมีค่าต่ำสุด 0 และค่าสูงสุด 2 ^ 32-1 ใช้คลาส Integer เพื่อใช้ชนิดข้อมูล int เป็นจำนวนเต็มที่ไม่ได้ลงนาม วิธีการคงเหมือนcompareUnsigned, divideUnsignedฯลฯ ได้รับการเพิ่มชั้นจำนวนเต็มเพื่อสนับสนุนการดำเนินการทางคณิตศาสตร์สำหรับจำนวนเต็มไม่ได้ลงนาม

สังเกตได้ว่า intตัวแปรยังคงมีการลงชื่อเมื่อประกาศ แต่คณิตศาสตร์ที่ไม่ได้ลงนามตอนนี้สามารถทำได้โดยใช้วิธีการเหล่านั้นในIntegerชั้นเรียน


11
เพื่อความยุติธรรมสำหรับหลาย ๆ โครงการข้อกำหนดทางเทคนิคนั้นไม่เข้มงวดและคุณสามารถที่จะ "เสีย" ความทรงจำเช่นนั้นได้
Simeon Visser

6
ฉันรู้ว่าฉันเข้าใจวัตถุประสงค์ดั้งเดิมของ Java ด้วย แต่ตัวอย่างเช่นสมาร์ทโฟนไม่ได้ทิ้งด้วยหน่วยความจำเสริม และพวกเขามักจะใช้ Java เท่าที่ฉันรู้ แต่ดีฉันไม่ต้องการเริ่มสงครามระหว่างโปรแกรมเมอร์ Java และอื่น ๆ
Tomáš Zato - Reinstate Monica

122
สำหรับฉันนี่ไม่ใช่แค่การเสียเงิน เมื่อคุณทำงานในระดับบิตงานที่ไม่ได้ลงนามนั้นง่ายต่อการทำงานด้วย
Cruncher

24
ในฐานะของ Java ที่ 8 นี้ไม่เป็นความจริง ใน Java SE 8 และหลังจากนั้นคุณสามารถใช้intชนิดข้อมูลที่จะเป็นตัวแทนของจำนวนเต็ม 32 บิตซึ่งมีค่าต่ำสุดของและค่าสูงสุด0 2^32-1- ดูdocs.oracle.com/javase/tutorial/java/nutsandbolts/...และdocs.oracle.com/javase/8/docs/api/java/lang/Integer.html
8bitjunkie

2
@ 7SpecialGems: ฉันได้อัปเดตคำตอบเพื่อรวมข้อมูลนั้นแล้ว ที่ถูกกล่าวว่ามันเป็นไปไม่ได้ที่จะประกาศจำนวนเต็มไม่ได้ลงนามหรือยกเว้นค่าลบมันเป็นไปได้เพียงเพื่อใช้intราวกับว่ามันไม่ได้ลงนามโดยใช้วิธีการต่างๆ
Simeon Visser

70

1
@stas ฉันมีปัญหาในการทำความเข้าใจการใช้งานและเรื่องใหญ่เกี่ยวกับความสามารถในการใช้ประเภทข้อมูลที่ไม่ได้ลงชื่อ จากแหล่งข้อมูลต่าง ๆ ที่ฉันอ่านออนไลน์ดูเหมือนว่ามันจะหมุนไปรอบ ๆ เพียงแค่เพิ่มค่าสูงสุดและการรับประกันโดยนัยโดยธรรมชาติว่ามันเป็นจำนวนบวก ความเข้าใจของฉันถูกต้องหรือมีเหตุผลสำคัญอื่น ๆ นอกจากนี้ตอนนี้Integerคลาสใน Java 8 อนุญาตให้หนึ่งใช้ int ที่ไม่ได้ลงนามคือความแตกต่างระหว่างแค่ในอวกาศและความเร็ว (ตั้งแต่ใน C / C ++ พวกเขากำลังดั้งเดิมในขณะที่ใน Java มันเป็นวัตถุห่อหุ้มทั้งหมด)
Abdul

2
@Abdul - เมื่อคุณทำงานที่ระดับบิต (โดยปกติจะเป็นเพราะคุณกำลังเชื่อมต่อกับฮาร์ดแวร์) คุณจำเป็นต้องมีค่าที่จะทำงานในลักษณะที่แน่นอน ie - เกลือกกลิ้งหลัง 11111111 ถึง 00000000 เป็นต้นการใช้การลงชื่อเข้าใช้แทนผู้ที่ไม่ได้ลงชื่อสามารถทำลายการคำนวณซีอาร์ซี ฯลฯ ซึ่งไม่ใช่การหยุดการแสดง แต่เสียเวลา
Lorne K

3
@Lorne K: ใน Java, intเกลือกกลิ้งแม้ว่าพวกเขาจะลงนาม มันคือ C / C ++ ที่มีการลงนามแบบไม่ได้ลงนาม แต่สาเหตุที่ทำให้ หาก“ เกลือกกลิ้ง” เป็นข้อกังวลเดียวของคุณคุณไม่จำเป็นต้องลงชื่อ ฉันเดาว่านั่นเป็นสาเหตุที่รูทีน CRC ฯลฯ ทำงานใน Java โดยไม่ต้องใช้ความพยายามเป็นพิเศษ และนั่นคือเหตุผลที่ API ใหม่เพิ่มการแยกวิเคราะห์การจัดรูปแบบการเปรียบเทียบการหารและส่วนที่เหลือ การดำเนินการอื่น ๆ ทั้งหมดคือการจัดการบิตทั้งหมด แต่ยังรวมถึงการลบการคูณและอื่น ๆ กำลังทำสิ่งที่ถูกต้องอยู่แล้ว
Holger

4
@Ciprian Tomoiaga: สำหรับการเพิ่มแบบโรลโอเวอร์รูปแบบบิตของอินพุตและผลลัพธ์ไม่ขึ้นอยู่กับว่าคุณตีความมันเป็นหมายเลขที่ลงนามหรือหมายเลขที่ไม่ได้ลงนาม หากคุณมีความอดทนคุณอาจลองด้วยชุดค่าผสม2⁶⁵ทั้งหมด ...
Holger

3
@ Holger ขอบคุณสำหรับคำอธิบาย! ที่จริงแล้วมันกลับกลายเป็นว่าทำไมเราถึงใช้ส่วนประกอบ 2 อย่าง ผมไม่ลองกับบาง 2 ^ 8 รวมกัน ^^
ปริTomoiagă

66

ไม่ว่าค่าใน int จะถูกเซ็นชื่อหรือไม่ได้ขึ้นอยู่กับว่าบิตถูกตีความ - Java ตีความบิตเป็นค่าที่ลงนาม (มันไม่มีพื้นฐานดั้งเดิมที่ไม่ได้ลงนาม)

หากคุณมี int ที่คุณต้องการตีความว่าเป็นค่าที่ไม่ได้ลงชื่อ (เช่นคุณอ่าน int จาก DataInputStream ที่คุณรู้ว่ามีค่าที่ไม่ได้ลงนาม) จากนั้นคุณสามารถทำเคล็ดลับต่อไปนี้

int fourBytesIJustRead = someObject.getInt();
long unsignedValue = fourBytesIJustRead & 0xffffffffl;

โปรดทราบว่ามันเป็นสิ่งสำคัญที่ตัวอักษรฐานสิบหกเป็นตัวอักษรยาวไม่ใช่ตัวอักษร int - ดังนั้น 'l' ในตอนท้าย


3
สำหรับฉันนี่คือคำตอบที่ดีที่สุด ... ข้อมูลของฉันมาจาก NFC การ์ด UID ซึ่งสามารถมี 4 หรือ 8 ไบต์ ... ในกรณีของ 4 ไบต์ฉันจำเป็นต้องส่งไปยัง int ที่ไม่ได้ลงชื่อและฉันไม่สามารถ ใช้ ByteBuffer.getLong เพราะไม่ใช่ข้อมูล 64 บิต ขอบคุณ
Loudenvier

ทำไมถึงต้องใช้เวลานาน คุณไม่สามารถทำ0xFFFFFFและรักษา int หรือไม่?
พอใจ

19

เราจำเป็นต้องได้รับการรับรองตัวเลขการจำลองของ MySQL ไม่ได้ลงนามTINYINT, SMALLINT, INT, BIGINTในjOOQซึ่งเป็นเหตุผลที่เราได้สร้างjOOU , การเสนอขายห้องสมุด minimalistic เสื้อคลุมประเภทสำหรับตัวเลขจำนวนเต็มไม่ได้ลงนามในชวา ตัวอย่าง:

import static org.joou.Unsigned.*;

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

ประเภททั้งหมดเหล่านี้ขยายjava.lang.Numberและสามารถแปลงเป็นประเภทดั้งเดิมและลำดับสูงกว่าBigIntegerและสามารถแปลงเป็นลำดับที่สูงกว่าชนิดดั้งเดิมและหวังว่านี่จะช่วยได้

(ข้อจำกัดความรับผิดชอบ: ฉันทำงานให้ บริษัท หลังห้องสมุดเหล่านี้)


ฟังดูสะดวกมาก! ขอบคุณที่พูดถึง :)
Lucas Sousa

7

สำหรับหมายเลขที่ไม่ได้ลงนามคุณสามารถใช้คลาสเหล่านี้จากไลบรารี Guava :

พวกเขาสนับสนุนการดำเนินการต่าง ๆ :

  • บวก
  • ลบ
  • ครั้ง
  • พอควร
  • dividedBy

สิ่งที่ดูเหมือนว่าขาดหายไปในขณะนี้คือตัวดำเนินการเปลี่ยนไบต์ หากคุณต้องการสิ่งเหล่านี้คุณสามารถใช้ BigInteger จาก Java


4

ใช้charสำหรับจำนวนเต็ม 16 บิตที่ไม่ได้ลงชื่อ


Char ไม่ใช่ int ที่ไม่ได้ลงนาม 32 บิต แต่ char เป็นคำตอบที่ดีสำหรับการเพิ่มหน่วยความจำ ลิงค์นี้: stackoverflow.com/questions/1841461/unsigned-short-in-java (จาก jqr ด้านบน)
blobmaster

2

บางทีนี่คือสิ่งที่คุณหมายถึงอะไร

long getUnsigned(int signed) {
    return signed >= 0 ? signed : 2 * (long) Integer.MAX_VALUE + 2 + signed;
}
  • getUnsigned(0) → 0
  • getUnsigned(1) → 1
  • getUnsigned(Integer.MAX_VALUE) → 2147483647
  • getUnsigned(Integer.MIN_VALUE) → 2147483648
  • getUnsigned(Integer.MIN_VALUE + 1) → 2147483649

คุณกำลังเสียสละหนึ่งในพันล้านของวินาทีของการแสดงสำหรับการพิมพ์ที่ขี้เกียจกับผู้ประกอบการที่สามแทนที่จะเป็นประโยค ไม่ดี. (ล้อเล่น)
ytpillai

5
คุณคิดว่าจริงๆ2 * (long) Integer.MAX_VALUE + 2เข้าใจง่ายกว่า0x1_0000_0000Lไหม ในเรื่องนั้นทำไมไม่ง่าย ๆreturn signed & 0xFFFF_FFFFL;?
Holger

2

ดูเหมือนว่าคุณสามารถจัดการปัญหาการเซ็นชื่อด้วยการทำ "ตรรกะ AND" กับค่าก่อนที่จะใช้:

ตัวอย่าง (ค่าของbyte[] header[0]คือ0x86):

System.out.println("Integer "+(int)header[0]+" = "+((int)header[0]&0xff));

ผลลัพธ์:

Integer -122 = 134

2

มีคำตอบที่ดีอยู่ที่นี่ แต่ฉันไม่เห็นการสาธิตการใช้งานระดับบิต เช่นเดียวกับ Visser (คำตอบที่ยอมรับในปัจจุบัน) พูดว่า Java ลงนามจำนวนเต็มตามค่าเริ่มต้น (Java 8 มีจำนวนเต็มไม่ได้ลงนาม แต่ฉันไม่เคยใช้เลย) โดยไม่ต้องกังวลใจต่อไปทำมัน ...

ตัวอย่าง RFC 868

จะเกิดอะไรขึ้นถ้าคุณต้องการเขียนจำนวนเต็มที่ไม่ได้ลงชื่อไปยัง IO ตัวอย่างการปฏิบัติคือเมื่อคุณต้องการส่งออกเวลาตามRFC 868868 สิ่งนี้ต้องการจำนวนเต็ม 32 บิต, big-endian และ unsigned ที่เข้ารหัสจำนวนวินาทีตั้งแต่ 12:00 AM 1 มกราคม 1900 คุณจะเข้ารหัสได้อย่างไร

สร้างจำนวนเต็ม 32- บิตที่ไม่ได้ลงชื่อของคุณเองดังนี้:

ประกาศอาร์เรย์ไบต์ 4 ไบต์ (32 บิต)

Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)

สิ่งนี้จะเริ่มต้นอาร์เรย์ให้ดูที่อาร์เรย์อาร์เรย์ถูกกำหนดค่าเริ่มต้นเป็นศูนย์ใน Java หรือไม่ . ตอนนี้คุณต้องกรอกข้อมูลในแต่ละไบต์ด้วยอาเรย์ตามลำดับใหญ่ (หรือเล็ก ๆ น้อย ๆ ถ้าคุณต้องการทำลายล้าง) สมมติว่าคุณมีเวลานาน (จำนวนเต็มยาวคือ 64 บิตใน Java) ที่เรียกว่าsecondsSince1900(ซึ่งใช้ประโยชน์เพียง 32 บิตแรกเท่านั้นและคุณได้จัดการกับความจริงที่ว่าวันที่อ้างอิงเวลา 12.00 น. วันที่ 1 มกราคม 1970) คุณสามารถใช้ตรรกะ AND เพื่อแยกบิตออกจากนั้นและเปลี่ยนบิตเหล่านั้นไปยังตำแหน่ง (หลัก) ที่จะไม่ถูกละเว้นเมื่อรวมเข้ากับไบต์และในลำดับใหญ่

my32BitUnsignedInteger[0] = (byte) ((secondsSince1900 & 0x00000000FF000000L) >> 24); // first byte of array contains highest significant bits, then shift these extracted FF bits to first two positions in preparation for coersion to Byte (which only adopts the first 8 bits)
my32BitUnsignedInteger[1] = (byte) ((secondsSince1900 & 0x0000000000FF0000L) >> 16);
my32BitUnsignedInteger[2] = (byte) ((secondsSince1900 & 0x000000000000FF00L) >> 8);
my32BitUnsignedInteger[3] = (byte) ((secondsSince1900 & 0x00000000000000FFL); // no shift needed

ของเรา my32BitUnsignedIntegerตอนนี้เทียบเท่ากับจำนวนเต็ม 32 บิตที่ไม่ได้ลงนามซึ่งเป็นไปตามมาตรฐาน RCF 868 ใช่ประเภทข้อมูลแบบยาวมีการเซ็นชื่อ แต่เราไม่สนใจความจริงนั้นเพราะเราสันนิษฐานว่าวินาทีวินาทีตั้งแต่ 1900 ใช้เพียง 32 บิตที่ต่ำกว่าเท่านั้น เนื่องจาก coersing ยาวเป็นไบต์บิตทั้งหมดที่สูงกว่า 2 ^ 7 (สองหลักแรกในฐานสิบหก) จะถูกละเว้น

แหล่งอ้างอิง: Java Network Programming, 4th Edition


1

เพิ่งสร้างโค้ดชิ้นนี้ซึ่งจะแปลง "this.altura" จากลบเป็นจำนวนบวก หวังว่าสิ่งนี้จะช่วยให้คนที่ต้องการความช่วยเหลือ

       if(this.altura < 0){    

                        String aux = Integer.toString(this.altura);
                        char aux2[] = aux.toCharArray();
                        aux = "";
                        for(int con = 1; con < aux2.length; con++){
                            aux += aux2[con];
                        }
                        this.altura = Integer.parseInt(aux);
                        System.out.println("New Value: " + this.altura);
                    }

-19

คุณสามารถใช้ฟังก์ชัน Math.abs (ตัวเลข) มันจะส่งกลับจำนวนบวก


12
nitpick: ไม่ใช่ถ้าคุณผ่านMIN_VALUE
Dennis Meng

2
@ kyo722 ฉันไม่สามารถจินตนาการได้ว่าสิ่งนี้จะส่งกลับค่าบวกในช่วงของดั้งเดิมที่ไม่ได้ลงนาม
Florian R. Klein

1
nitpick # 2: ไม่ใช่ถ้าคุณผ่าน0
genisage
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.