Java Bitwise operátorok

1. Áttekintés

Az operátorokat a Java nyelven használják adatok és változók működtetésére.

Ebben az oktatóanyagban feltárjuk a Bitwise operátorokat és azok működését a Java-ban.

2. Bitenkénti operátorok

A bitenkénti operátorok bináris számjegyeken vagy a bemeneti érték bitjein dolgoznak. Alkalmazhatjuk ezeket az egész típusú típusokra - hosszú, int, rövid, char, és byte.

A különféle bitenkénti operátorok feltárása előtt értsük meg először, hogyan működnek.

A bitenkénti operátorok bináris egyenértékű decimális számokkal dolgoznak, és műveleteket végeznek rajtuk apránként az adott operátor szerint:

  • Először az operandusokat alakítják át bináris reprezentációjukra
  • Ezután az operátort minden bináris számra alkalmazzuk, és kiszámoljuk az eredményt
  • Végül az eredményt visszaváltják tizedesre

Értsük meg egy példával; vegyünk kettőt egész számok:

int értéke 1 = 6; int értéke2 = 5;

Ezután alkalmazzunk bitenként VAGY operátort ezekre a számokra:

int eredmény = 6 | 5;

Ennek a műveletnek az elvégzéséhez először a számok bináris reprezentációját kell kiszámítani:

Bináris értéke1 = 0110 bináris értéke2 = 0101

Ezután a műveletet minden bitre alkalmazzuk. Az eredmény egy új bináris számot ad vissza:

0110 0101 ----- 0111

Végül az eredmény 0111 tizedesre konvertálódik, amely egyenlő 7:

eredmény: 7

A bitenkénti operátorokat tovább osztályozzák a bitenkénti logikai és a bitenkénti váltás operátorokként. Most nézzük át az egyes típusokat.

3. Bitenkénti logikai operátorok

A bitenkénti logikai operátorok az AND (&), OR (|), XOR (^) és a NOT (~).

3.1. Bitenként VAGY (|)

Az OR operátor összehasonlítja két egész szám bináris számjegyét, és 1-et ad vissza, ha bármelyikük 1.

Ez hasonló a || logikai operátor, amelyet logikai operátorokkal használunk. Két logikai érték összehasonlításakor az eredmény az igaz ha bármelyikük az igaz. Hasonlóképpen a kimenet 1, ha bármelyikük 1.

Az előző szakaszban láttunk egy példát erre az operátorra:

@Test public void givenTwoIntegers_whenOrOperator_thenNewDecimalNumber () value2; assertEquals (7, eredmény); 

Lássuk ennek a műveletnek a bináris ábrázolását:

0110 0101 ----- 0111

Itt láthatjuk, hogy az OR használata esetén a 0 és a 0 0-t eredményez, míg a legalább 1-gyel történő bármely kombináció 1-et eredményez.

3.2. Bitenként ÉS (&)

Az AND operátor összehasonlítja két egész szám bináris számjegyét, és 1-et ad vissza, ha mindkettő 1, különben 0-t ad vissza.

Ez hasonló a && operátorhoz logikai értékek. Amikor kettő értéke logikai vannak igaz egy && művelet eredménye igaz.

Használjuk ugyanazt a példát, mint a fentiekben, kivéve, hogy most a & operátort használjuk a | helyett operátor:

@Test public void givenTwoIntegers_whenAndOperator_thenNewDecimalNumber () {int érték1 = 6; int értéke2 = 5; int eredmény = érték1 & érték2; assertEquals (4, eredmény); }

Lássuk ennek a műveletnek a bináris ábrázolását is:

0110 0101 ----- 0100

0100 van 4 tizedesjegyekkel tehát az eredmény:

eredmény: 4

3.3. Bitenként XOR (^)

Az XOR operátor összehasonlítja két egész szám bináris számjegyét és 1-et ad vissza, ha mindkét összehasonlított bit különbözik. Ez azt jelenti, hogy ha mindkét egész szám bitje 1 vagy 0, az eredmény 0 lesz; különben az eredmény 1 lesz:

@Test public void givenTwoIntegers_whenXorOperator_thenNewDecimalNumber () {int érték1 = 6; int értéke2 = 5; int eredmény = érték1 ^ érték2; assertEquals (3, eredmény); }

És a bináris ábrázolás:

0110 0101 ----- 0011

0011 értéke 3 tizedesjegyig, ezért az eredmény:

eredmény: 3

3.4. Bitenkénti kiegészítés (~)

A Bitenkénti Not vagy a Complement operátor egyszerűen a bemeneti érték minden bitjének tagadását jelenti. Csak egy egész számot vesz fel, és ez egyenértékű a! operátor.

Ez az operátor megváltoztatja az egész szám bináris számjegyeit, ami azt jelenti, hogy mind a 0 1, mind az 1 0 lesz. A! operátor hasonlóan működik logikai értékek: megfordul logikai értékek tól igaz nak nek hamis és fordítva.

Most értsük meg egy példával, hogyan lehet megtalálni a tizedes szám kiegészítését.

Végezzük el az1 = 6 érték kiegészítését:

@Test public void givenOneInteger_whenNotOperator_thenNewDecimalNumber () {int érték1 = 6; int eredmény = ~ érték1; assertEquals (-7, eredmény); }

A bináris érték:

érték1 = 0000 0110

A komplementer operátor alkalmazásával az eredmény:

0000 0110 -> 1111 1001

Ez a kiegészítése a 6-os tizedes számnak. És mivel az első (bal szélső) bit bináris 1, ez azt jelenti, hogy a jel negatív a tárolt számhoz.

Mivel a számokat 2-es kiegészítőként tároljuk, először meg kell találnunk annak 2-es kiegészítését, majd az eredményül kapott bináris számot tizedessé kell alakítanunk:

1111 1001 -> 0000 0110 + 1 -> 0000 0111

Végül a 0000 0111 értéke 7 tizedesjegyig. Mivel az előjel bit 1 volt, amint azt fentebb említettük, az így kapott válasz:

eredmény: -7

3.5. Bitenkénti kezelőasztal

Összefoglaljuk az operátorok eddigi eredményét egy összehasonlító táblázatban:

A B A | B A&B A ^ B ~ A 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 1 1 1 1 1 1 1 0 0

4. Bitenkénti váltás kezelői

A bináris váltás operátorai a váltó operátor alapján a bemeneti érték összes bitjét balra vagy jobbra tolják.

Lássuk ezeknek az operátoroknak a szintaxisát:

érték 

A kifejezés bal oldala az eltolt egész szám, a kifejezés jobb oldala pedig azt jelzi, hogy hányszor kell eltolni.

A bitenkénti váltás operátorait tovább osztályozzák a balra és jobbra váltás operátorainak.

4.1. Aláírt bal váltás [<<]

A bal váltáskezelő a biteket balra tolja, annyiszor, amennyit az operandus jobb oldala határoz meg. A bal váltás után a jobb oldali üres helyet 0-val töltjük meg.

Egy másik fontos szempont, hogy megjegyezzük egy szám elmozdítása egyenértékű 2-gyel való szorzásával vagy általában egy szám balra tolásával n a pozíciók megegyeznek a 2 ^ szorzássaln.

Vegyük bemeneti értékként a 12 értéket.

Most 2 hellyel balra mozgatjuk (12 << 2), és meglátjuk, mi lesz a végeredmény.

A 12 bináris egyenértéke 00001100. Miután 2 hellyel balra tolódott, az eredmény 00110000, ami 48-nak felel meg tizedesjegyben:

@Test public void givenOnePositiveInteger_whenLeftShiftOperator_thenNewDecimalNumber () {int érték = 12; int leftShift = érték << 2; assertEquals (48, leftShift); } 

Ez hasonlóan működik negatív érték esetén:

@Test public void givenOneNegativeInteger_whenLeftShiftOperator_thenNewDecimalNumber () {int érték = -12; int leftShift = érték << 2; assertEquals (-48, leftShift); }

4.2. Aláírt jobb váltás [>>]

A jobb műszak kezelője az összes bitet jobbra tolja. A bal oldalon lévő üres hely a beviteli számtól függően kitöltődik:

  • Ha egy bemeneti szám negatív, ahol a bal szélső bit 1, akkor az üres helyek 1-gyel lesznek kitöltve
  • Ha egy bemeneti szám pozitív, ahol a bal szélső bit 0, akkor az üres helyek 0-val lesznek kitöltve

Folytassuk a példát a 12 bemenetként.

Most 2 hellyel jobbra mozgatjuk (12 >> 2), és meglátjuk, mi lesz a végeredmény.

A bemeneti szám pozitív, így 2 ponttal jobbra tolás után az eredmény 0011, ami 3 tizedesjegyű:

@Test public void givenOnePositiveInteger_whenSignedRightShiftOperator_thenNewDecimalNumber () {int érték = 12; int rightShift = érték >> 2; assertEquals (3, rightShift); }

Negatív érték esetén:

@Test public void givenOneNegativeInteger_whenSignedRightShiftOperator_thenNewDecimalNumber () {int érték = -12; int rightShift = érték >> 2; assertEquals (-3, rightShift); }

4.3. Aláíratlan jobb váltás [>>>]

Ez az operátor nagyon hasonlít az aláírt jobb műszak operátorhoz. Az egyetlen különbség az, hogy a bal oldali üres helyek 0-val vannak kitöltve, függetlenül attól, hogy a szám pozitív vagy negatív. Ezért az eredmény mindig pozitív egész szám lesz.

Változtassuk jobbra ugyanazt a 12 értéket:

@Test public void givenOnePositiveInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber () {int érték = 12; int unsignedRightShift = érték >>> 2; assertEquals (3, unsignedRightShift); }

És most a negatív érték:

@Test public void givenOneNegativeInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber () {int érték = -12; int unsignedRightShift = érték >>> 2; assertEquals (1073741821, unsignedRightShift); }

5. Különbség a bitenkénti és a logikai operátorok között

Néhány különbség van az itt tárgyalt bitenkénti operátorok és az általánosan ismert logikai operátorok között.

Első, logikai operátorok dolgoznak logikai kifejezések és visszatér logikai értékek (vagy igaz vagy hamis), mivel a bitenkénti operátorok bináris számjegyeken dolgoznak egész értékek (hosszú, int, rövid, char, és byte) és adjon vissza egész számot.

Emellett a logikai operátorok mindig az elsőt értékelik logikai kifejezés, és annak eredményétől és az alkalmazott operátortól függően értékelheti vagy nem értékelheti a másodikat. Másrészről, a bitenkénti operátorok mindig mindkét operandust értékelik.

Végül a logikai operátorokat több feltétel alapján döntések meghozatalára használják, míg a bitenkénti operátorok biteken dolgoznak, és bitről bitre műveleteket hajtanak végre.

6. Használjon tokokat

A bitenkénti operátorok néhány lehetséges felhasználási esete:

  • Kommunikációs kötegek, ahol az adatokhoz csatolt fejléc egyes bitjei fontos információkat jelentenek
  • Beágyazott rendszerekben csak egy adott regiszter egyetlen bitjének beállítása / törlése / váltása a fennmaradó bitek módosítása nélkül
  • Adatok titkosítása biztonsági kérdésekhez az XOR operátor használatával
  • Adattömörítés során az adatok egyik ábrázolásból a másikba történő átalakításával csökkenteni kell a felhasznált hely mennyiségét

7. Következtetés

Ebben az oktatóanyagban megismertük a bitenkénti operátorok típusait és azok különbségeit a logikai operátoroktól. Láttunk néhány lehetséges felhasználási esetet is.

A cikk összes kódpéldája elérhető a GitHub oldalon.