ในบทเรียนวันนี้ เราจะทำความคุ้นเคยกับ Java Bitwise Operators และพิจารณาตัวอย่างวิธีการทำงานกับพวกเขา คุณคงคุ้นเคยกับคำว่า "บิต" ถ้าไม่จำความหมายของมัน :) บิตเป็นหน่วยข้อมูลที่เล็กที่สุดในคอมพิวเตอร์ ชื่อของมันมาจากเลข
ฐานสอง บิตสามารถแสดงด้วยหนึ่งในสองจำนวน: 1 หรือ 0 มีระบบเลขฐานสองแบบพิเศษที่ใช้เลขฐานสองและเลขศูนย์ เราจะไม่เจาะลึกปริศนาทางคณิตศาสตร์ที่นี่ เราจะทราบเพียงว่าตัวเลขใดๆ ใน Java สามารถแปลงเป็นรูปแบบไบนารีได้ ในการทำเช่นนี้ คุณต้องใช้คลาสตัวตัดคำ
ตัวอย่างเช่น นี่คือวิธีที่คุณสามารถทำได้สำหรับ
int :
public class Main {
public static void main(String[] args) {
int x = 342;
System.out.println(Integer.toBinaryString(x));
}
}
เอาต์พุตคอนโซล:
101010110 1010 10110 (ฉันเว้นวรรคเพื่อให้อ่านง่ายขึ้น) คือเลข 342 ในระบบเลขฐานสิบ เราได้แบ่งจำนวนนี้ออกเป็นบิตต่างๆ แล้ว: เลขศูนย์และเลขหนึ่ง การดำเนินการกับบิตเรียกว่า
บิต
โอเปอเรเตอร์นี้ง่ายมาก: มันผ่านแต่ละบิตของตัวเลขของเรา และพลิกบิต: ศูนย์กลายเป็นหนึ่ง และหนึ่งกลายเป็นศูนย์ ถ้าเราใช้กับเลข 342 สิ่งที่เกิดขึ้นคือ:
101010110 คือ 342 แสดงเป็นเลขฐานสอง 010101001 เป็นค่าของนิพจน์ ~342 ลองนำไปใช้จริง:
public class Main {
public static void main(String[] args) {
int x = 342;
System.out.println(~x);
}
}
เอาต์พุตคอนโซล:
169 169 คือผลลัพธ์ของเรา (
010101001 ) ในระบบทศนิยมที่คุ้นเคย :)
อย่างที่คุณเห็น มันค่อนข้างคล้ายกับตรรกะ AND (
&& ) คุณจะจำได้ว่า ตัว ดำเนินการ
&&จะคืนค่าจริงก็ต่อเมื่อตัวถูกดำเนินการทั้งสองเป็นจริงเท่านั้น Bitwise
&ทำงานในลักษณะเดียวกัน: เปรียบเทียบตัวเลขสองตัวทีละบิต การเปรียบเทียบทำให้เกิดตัวเลขที่สาม ตัวอย่างเช่น สมมติตัวเลข 277 และ 432:
110110000 คือ 277 แทนด้วยเลขฐานสอง 1000101011 คือ 432 แทนด้วยเลขฐานสอง ถัดไป ตัวดำเนินการ
&เปรียบเทียบบิตแรกของตัวเลขบนกับบิตแรกของตัวเลขล่าง เนื่องจากนี่คือตัวดำเนินการ AND ผลลัพธ์จะเป็น 1 ก็ต่อเมื่อทั้งสองบิตเป็น 1 ในกรณีอื่นๆ ผลลัพธ์จะเป็น 0 100010101
&&โอเปอเรเตอร์ ขั้นแรก เราจะเปรียบเทียบบิตแรกของตัวเลขสองตัว จากนั้นบิตที่สอง บิตที่สาม และอื่นๆ อย่างที่คุณเห็น มีเพียงสองกรณีเท่านั้นที่ทั้งสองบิตสอดคล้องกันในจำนวนเท่ากับ 1 (บิตแรกและบิตที่ห้า) การเปรียบเทียบอื่น ๆ ทั้งหมดสร้าง 0 วินาที ในที่สุดเราก็ได้หมายเลข 1,0001000 ในระบบทศนิยมจะตรงกับหมายเลข 272 ตรวจสอบกัน:
public class Main {
public static void main(String[] args) {
System.out.println(277&432);
}
}
เอาต์พุตคอนโซล:
272
ตัวดำเนินการนี้ทำงานในลักษณะเดียวกัน: เปรียบเทียบตัวเลขสองตัวทีละบิต เฉพาะตอนนี้หากอย่างน้อยหนึ่งบิตเป็น 1 ผลลัพธ์คือ 1 ลองดูตัวเลขเดียวกัน (277 และ 432): 100010101
| 110110000 _______________ 110110101 - ผลลัพธ์ของ
| ตัวดำเนินการ เราได้รับผลลัพธ์ที่แตกต่างกัน: บิตเดียวที่ยังคงเป็นศูนย์คือบิตที่เป็นศูนย์ในตัวเลขทั้งสอง ผลลัพธ์คือหมายเลข 110110101 ในระบบทศนิยมจะตรงกับหมายเลข 437 ตรวจสอบกัน:
public class Main {
public static void main(String[] args) {
System.out.println(277|432);
}
}
เอาต์พุตคอนโซล:
437 เราคำนวณทุกอย่างถูกต้อง! :)
- ^ - XOR ระดับบิต (พิเศษ OR)
เรายังไม่พบตัวดำเนินการนี้ แต่ไม่มีอะไรซับซ้อนเกี่ยวกับเรื่องนี้ มันคล้ายกับตัวดำเนินการ OR ทั่วไป มีข้อแตกต่างอย่างหนึ่งคือ OR ธรรมดาจะส่งกลับค่าจริงหากตัวถูกดำเนินการอย่างน้อยหนึ่งตัวเป็นจริง แต่ไม่จำเป็นต้องเป็นอย่างใดอย่างหนึ่ง: ถ้าตัวถูกดำเนินการทั้งคู่เป็นจริง ผลลัพธ์ก็จะเป็นจริง แต่เอกสิทธิ์เฉพาะ OR จะคืนค่าจริงก็ต่อเมื่อตัวถูกดำเนินการตัวใดตัวหนึ่งเป็นจริงเท่านั้น ถ้าตัวถูกดำเนินการทั้งคู่เป็นจริง OR ธรรมดาจะส่งกลับค่าจริง ("อย่างน้อยหนึ่งค่าจริง") แต่ XOR ส่งคืนค่าเท็จ นั่นเป็นเหตุผลว่าทำไมจึงเรียกว่า OR แต่เพียงผู้เดียว เมื่อรู้ว่าตัวดำเนินการบิตก่อนหน้าทำงานอย่างไร คุณอาจคำนวณ 277
^ 432 ได้อย่างง่ายดาย แต่ลองมาเจาะลึกกันอีกครั้ง :) 100010101
^ 110110000 _______________ 010100101 - ผลลัพธ์ของ
^โอเปอเรเตอร์ นั่นคือผลลัพธ์ของเรา บิตเหล่านั้นที่เหมือนกันในตัวเลขทั้งสองจะสร้าง 0 (หมายถึงการทดสอบ "เพียงตัวเดียว" ล้มเหลว) แต่บิตที่สร้างคู่ 0-1 หรือ 1-0 กลายเป็นคู่ ผลลัพธ์ของเราคือหมายเลข 010100101 ในระบบทศนิยมจะตรงกับหมายเลข 165 มาดูกันว่าการคำนวณของเราถูกต้องหรือไม่:
public class Main {
public static void main(String[] args) {
System.out.println(277^432);
}
}
เอาต์พุตคอนโซล:
165 สุดยอด! ทุกอย่างเป็นไปตามที่เราคิด :) ตอนนี้ได้เวลาทำความคุ้นเคยกับตัวดำเนินการกะบิตแล้ว ชื่อพูดสำหรับตัวเอง เรารับตัวเลขแล้วเลื่อนบิตไปทางซ้ายหรือขวา :) มาดูกันว่าเป็นอย่างไร:
เลื่อนไปทางซ้าย
การเลื่อนบิตไปทางซ้ายแสดงโดย
<< นี่คือตัวอย่าง:
public class Main {
public static void main(String[] args) {
int x = 64;//value
int y = 3;// Shift distance
int z = (x << y);
System.out.println(Integer.toBinaryString(x));
System.out.println(Integer.toBinaryString(z));
}
}
ในตัวอย่างนี้ ตัวเลข x = 64 เรียกว่าค่า เป็นบิตของค่าที่เราจะเปลี่ยน เราจะเลื่อนบิตไปทางซ้าย (คุณอาจเดาได้จากทิศทางของ ตัวดำเนินการ
<< ) ในระบบเลขฐานสอง เลข 64 = 1000000 เลข
y = 3เรียกว่า ระยะกะ ระยะการเลื่อนระบุจำนวนบิตไปทางขวา/ซ้ายที่คุณต้องการเลื่อนบิตของจำนวน
x ในตัวอย่างของเรา เราจะเลื่อนพวกมันไปทางซ้าย 3 บิต หากต้องการดูกระบวนการกะให้ชัดเจนยิ่งขึ้น ให้ดูที่รูปภาพ ในตัวอย่างนี้ เราใช้
int s Ints ใช้ 32 บิตในหน่วยความจำของคอมพิวเตอร์ นี่คือลักษณะของหมายเลข 64 ดั้งเดิมของเรา:
และตอนนี้เรานำแต่ละบิตของเราแล้วเลื่อนไปทางซ้าย 3 แห่ง:
ลองดูสิ่งที่เราได้รับ อย่างที่คุณเห็น บิตทั้งหมดของเราเปลี่ยนไป และเพิ่มศูนย์อีก 3 ตัวจากขอบของช่วง สาม เพราะเราเลื่อนไป 3 ถ้าเราเลื่อนไป 10 ก็จะเพิ่มศูนย์ 10 ตัว ดังนั้น นิพจน์
x << yจึงหมายถึง "เลื่อนบิตของจำนวน
xไปทางซ้ายทีละ y" ผลลัพธ์ของนิพจน์ของเราคือจำนวน 1000000000 ซึ่งเป็น 512 ในระบบทศนิยม ตรวจสอบ:
public class Main {
public static void main(String[] args) {
int x = 64;//value
int y = 3;// Shift distance
int z = (x << y);
System.out.println(z);
}
}
เอาต์พุตคอนโซล:
512 ทันที! ในทางทฤษฎี บิตสามารถเลื่อนได้อย่างไม่มีที่สิ้นสุด แต่เนื่องจากจำนวนของเราเป็น int
เราจึงมีเลขฐานสองเพียง 32 หลักเท่านั้น ในจำนวนนี้ 7 คันถูกครอบครองไปแล้ว 64 คัน (1000000) ดังนั้น หากเราเลื่อนตำแหน่งไปทางซ้าย 27 ตำแหน่ง ตำแหน่งเดียวของเราจะเคลื่อนเลยช่วงประเภทข้อมูลและสูญหายไป เหลือเพียงศูนย์เท่านั้น!
public class Main {
public static void main(String[] args) {
int x = 64;//value
int y = 26;// Shift distance
int z = (x << y);
System.out.println(z);
}
}
เอาต์พุตของคอนโซล:
0 ตามที่คาดไว้ บิตเคลื่อนเกิน 32 บิตที่มีอยู่และหายไป เราจบลงด้วยตัวเลข 32 บิตที่ประกอบด้วยศูนย์เท่านั้น
โดยปกติสิ่งนี้สอดคล้องกับ 0 ในระบบทศนิยม กฎง่ายๆ สำหรับการจำการเลื่อนไปทางซ้าย: สำหรับการเลื่อนไปทางซ้ายแต่ละครั้ง จำนวนจะคูณด้วย 2 ลองคำนวณนิพจน์ต่อไปนี้โดยไม่มีรูปภาพของบิต 111111111 << 3 เราต้องคูณจำนวน 111111111
ด้วย 2 เป็นผลให้เราได้รับ 888888888 มาเขียนโค้ดและตรวจสอบ:
public class Main {
public static void main(String[] args) {
System.out.println(111111111 << 3);
}
}
เอาต์พุตคอนโซล:
888888888
เลื่อนไปทางขวา
การดำเนินการ นี้แสดงโดย
>> มันทำสิ่งเดียวกัน แต่ในทิศทางอื่น! :) เราจะไม่คิดค้นวงล้อขึ้นมาใหม่ ลองด้วย
int 64 เดียวกัน
public class Main {
public static void main(String[] args) {
int x = 64;//value
int y = 2;// Shift distance
int z = (x >> y);
System.out.println(z);
}
}
อันเป็นผลมาจากการเลื่อนไปทางขวาทีละ 2 เลขศูนย์สุดโต่งสองตัวในจำนวนของเราจะเคลื่อนออกจากช่วงและหายไป เราได้ 10,000 ซึ่งตรงกับเลข 16 ในเอาต์พุตคอนโซลระบบทศนิยม:
16 นี่คือกฎง่ายๆ สำหรับการจำการเลื่อนไปทางขวา: การเลื่อนไปทางขวาแต่ละครั้งหารด้วยสอง ทิ้งเศษที่เหลือ ตัวอย่างเช่น 35
>> 2 หมายความว่าเราต้องหาร 35 ด้วย 2 สองครั้ง ทิ้งเศษที่เหลือ
35/2 = 17 (ทิ้งเศษที่เหลือ 1) 17/2 = 8 (ทิ้งเศษ 1) สุดท้าย 35
>> 2 ควร เท่ากับ 8 ตรวจสอบกัน:
public class Main {
public static void main(String[] args) {
System.out.println(35 >> 2);
}
}
เอาต์พุตคอนโซล:
8
ลำดับความสำคัญของตัวดำเนินการใน Java
ขณะเขียนและอ่านโค้ด คุณมักจะพบนิพจน์ที่รวมการทำงานหลายอย่างเข้าด้วยกัน สิ่งสำคัญคือต้องเข้าใจลำดับที่จะดำเนินการ (ไม่เช่นนั้น คุณอาจประหลาดใจกับผลลัพธ์ที่ได้) เนื่องจาก Java มีการดำเนินการจำนวนมาก แต่ละการดำเนินการจึงได้รับการกำหนดตำแหน่งในตารางพิเศษ:
ลำดับความสำคัญของตัวดำเนินการ
ผู้ประกอบการ |
ลำดับความสำคัญ |
โพสต์ฟิกซ์ |
expr++ expr-- |
คนเดียว |
++expr --expr +expr ~ ! |
ทวีคูณ |
* / % |
สารเติมแต่ง |
+ - |
กะ |
<< >>>>> _ |
เชิงสัมพันธ์ |
< > <= >=อินสแตนซ์ของ |
ความเท่าเทียมกัน |
== != |
ระดับบิตและ |
& |
พิเศษระดับบิตหรือ |
^ |
รวมบิตหรือ |
| |
ตรรกะและ |
&& |
ตรรกะ OR |
|| |
ไตรภาค |
? : |
งานที่มอบหมาย |
= += -= *= /= %= &= ^= |= <<= >>= >>>= |
การดำเนินการทั้งหมดจะดำเนินการจากซ้ายไปขวาโดยคำนึงถึงลำดับความสำคัญ เช่น ถ้าเราเขียน
int x = 6 - 4/2;
จากนั้นการดำเนินการหาร (
4/2 ) จะดำเนินการก่อน แม้ว่าจะเป็นที่สอง แต่ก็มีลำดับความสำคัญสูงกว่า วงเล็บและวงเล็บระบุลำดับความสำคัญสูงสุด คุณคงจำได้จากโรงเรียน ตัวอย่างเช่น หากคุณเพิ่มลงในนิพจน์
int x = (6 - 4)/2;
จากนั้นทำการลบก่อนเนื่องจากอยู่ในวงเล็บ ลำดับความสำคัญของ ตัวดำเนินการ
&& ทางตรรกะ ค่อนข้างต่ำ (ดูตาราง) ดังนั้นโดยปกติจะเป็นตัวสุดท้าย ตัวอย่างเช่น:
boolean x = 6 - 4/2 > 3 && 12*12 <= 119;
นิพจน์นี้จะถูกดำเนินการดังนี้:
boolean x = 6 - 2 > 3 && 12*12 <= 119;
boolean x = 6 - 2 > 3 && 144 <= 119;
boolean x = 4 > 3 && 144 <= 119;
ถัดไป ตัวดำเนินการเปรียบเทียบจะถูกดำเนินการ:
boolean x = true && 144 <= 119;
boolean x = true && false;
และสุดท้าย ตัวดำเนินการ AND (
&& ) จะถูกดำเนินการเป็นคนสุดท้าย
boolean x = true && false;
boolean x = false;
ตัวอย่างเช่น ตัวดำเนินการการบวก (
+ ) มีความสำคัญสูงกว่า ตัวดำเนินการเปรียบเทียบ
!= (ไม่เท่ากัน) ดังนั้นในการแสดงออก
boolean x = 7 != 6+1;
การดำเนินการ 6+1 จะดำเนินการก่อน จากนั้นตรวจสอบ 7 != 7 (ซึ่งประเมินเป็นเท็จ) และสุดท้าย การกำหนดผลลัพธ์ (เท็จ) ให้กับตัวแปร
x (การกำหนดโดยทั่วไปมีความสำคัญต่ำสุดในบรรดาตัวดำเนินการทั้งหมด ดูที่ โต๊ะ). วุ้ย มันเป็นบทเรียนครั้งใหญ่ แต่คุณก็ทำได้! หากคุณไม่เข้าใจบทเรียนบางส่วนหรือบทก่อนหน้าอย่างถ่องแท้ ไม่ต้องกังวล เราจะพูดถึงหัวข้อเหล่านี้มากกว่าหนึ่งครั้งในอนาคต บทเรียน CodeGym สองสามบทเกี่ยวกับการดำเนินการเชิงตรรกะและตัวเลข เราจะไม่พูดถึงสิ่งเหล่านี้ในเร็วๆ นี้ แต่คุณอ่านตอนนี้ก็ไม่เสียหายอะไร
GO TO FULL VERSION