CodeGym /จาวาบล็อก /สุ่ม /ตัวดำเนินการ Java Bitwise
John Squirrels
ระดับ
San Francisco

ตัวดำเนินการ Java Bitwise

เผยแพร่ในกลุ่ม
ในบทเรียนวันนี้ เราจะทำความคุ้นเคยกับ Java Bitwise Operators และพิจารณาตัวอย่างวิธีการทำงานกับพวกเขา คุณคงคุ้นเคยกับคำว่า "บิต" ถ้าไม่จำความหมายของมัน :) บิตเป็นหน่วยข้อมูลที่เล็กที่สุดในคอมพิวเตอร์ ชื่อของมันมาจากเลขฐานสอง บิตสามารถแสดงด้วยหนึ่งในสองจำนวน: 1 หรือ 0 มีระบบเลขฐานสองแบบพิเศษที่ใช้เลขฐานสองและเลขศูนย์ เราจะไม่เจาะลึกปริศนาทางคณิตศาสตร์ที่นี่ เราจะทราบเพียงว่าตัวเลขใดๆ ใน Java สามารถแปลงเป็นรูปแบบไบนารีได้ ในการทำเช่นนี้ คุณต้องใช้คลาสตัวตัดคำ
ตัวดำเนินการระดับบิต - 1
ตัวอย่างเช่น นี่คือวิธีที่คุณสามารถทำได้สำหรับ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 ดั้งเดิมของเรา:
ตัวดำเนินการระดับบิต - 2
และตอนนี้เรานำแต่ละบิตของเราแล้วเลื่อนไปทางซ้าย 3 แห่ง:
ตัวดำเนินการระดับบิต - 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 บิตที่ประกอบด้วยศูนย์เท่านั้น
ตัวดำเนินการระดับบิต - 4
โดยปกติสิ่งนี้สอดคล้องกับ 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);
   }
}
ตัวดำเนินการระดับบิต - 5
ตัวดำเนินการระดับบิต - 6
อันเป็นผลมาจากการเลื่อนไปทางขวาทีละ 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;
นิพจน์นี้จะถูกดำเนินการดังนี้:
  • 4/2 = 2

boolean x = 6 - 2 > 3 && 12*12 <= 119;
  • 12*12 = 144

boolean x = 6 - 2 > 3 && 144 <= 119;
  • 6-2 = 4

boolean x = 4 > 3 && 144 <= 119;
ถัดไป ตัวดำเนินการเปรียบเทียบจะถูกดำเนินการ:
  • 4 > 3 = จริง

boolean x = true && 144 <= 119;
  • 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 สองสามบทเกี่ยวกับการดำเนินการเชิงตรรกะและตัวเลข เราจะไม่พูดถึงสิ่งเหล่านี้ในเร็วๆ นี้ แต่คุณอ่านตอนนี้ก็ไม่เสียหายอะไร
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION