Java Bitwise-operators

1. Overzicht

Operatoren worden gebruikt in de Java-taal om met gegevens en variabelen te werken.

In deze tutorial verkennen we Bitwise Operators en hoe ze werken in Java.

2. Bitwise-operators

Bitwise-operators werken met binaire cijfers of bits van invoerwaarden. We kunnen deze toepassen op de integer-typen - lang, int, kort, char, en byte.

Voordat we de verschillende bitsgewijze operatoren gaan onderzoeken, moeten we eerst begrijpen hoe ze werken.

Bitwise-operators werken op een binair equivalent van decimale getallen en voeren bit voor bit bewerkingen uit volgens de gegeven operator:

  • Eerst worden de operanden geconverteerd naar hun binaire representatie
  • Vervolgens wordt de operator toegepast op elk binair getal en wordt het resultaat berekend
  • Ten slotte wordt het resultaat terug geconverteerd naar de decimale weergave

Laten we het begrijpen met een voorbeeld; laten we er twee nemen gehele getallen:

int waarde1 = 6; int waarde2 = 5;

Laten we vervolgens een bitsgewijze OR-operator toepassen op deze getallen:

int resultaat = 6 | 5;

Om deze bewerking uit te voeren, wordt eerst de binaire weergave van deze getallen berekend:

Binair getal van waarde1 = 0110 Binair getal van waarde2 = 0101

Vervolgens wordt de bewerking op elke bit toegepast. Het resultaat geeft een nieuw binair getal terug:

0110 0101 ----- 0111

Eindelijk het resultaat 0111 wordt terug geconverteerd naar een decimaal getal dat gelijk is aan 7:

resultaat: 7

Bitsgewijze operatoren worden verder geclassificeerd als bitsgewijze logische en bitsgewijze verschuivingsoperatoren. Laten we nu elk type doornemen.

3. Bitsgewijze logische operators

De bitsgewijze logische operatoren zijn AND (&), OR (|), XOR (^) en NOT (~).

3.1. Bitsgewijs OF (|)

De OR-operator vergelijkt elk binair cijfer van twee gehele getallen en geeft 1 terug als een van beide 1 is.

Dit is vergelijkbaar met de || logische operator die wordt gebruikt met booleans. Wanneer twee booleans worden vergeleken, is het resultaat waar als een van beide is waar. Evenzo is de uitvoer 1 als een van beide 1 is.

We zagen een voorbeeld van deze operator in de vorige sectie:

@Test openbare leegte gegevenTwoIntegers_whenOrOperator_thenNewDecimalNumber () waarde2; assertEquals (7, resultaat); 

Laten we eens kijken naar de binaire weergave van deze bewerking:

0110 0101 ----- 0111

Hier kunnen we zien dat het gebruik van OR, 0 en 0 zal resulteren in 0, terwijl elke combinatie met minstens een 1 zal resulteren in 1.

3.2. Bitsgewijs EN (&)

De AND-operator vergelijkt elk binair cijfer van twee gehele getallen en geeft 1 terug als beide 1 zijn, anders retourneert het 0.

Dit is vergelijkbaar met de operator && met boolean waarden. Wanneer de waarden van twee booleans zijn waar het resultaat van een && operatie is waar.

Laten we hetzelfde voorbeeld gebruiken als hierboven, maar nu met de operator & in plaats van de | operator:

@Test openbare leegte gegevenTwoIntegers_whenAndOperator_thenNewDecimalNumber () {int waarde1 = 6; int waarde2 = 5; int resultaat = waarde1 & waarde2; assertEquals (4, resultaat); }

Laten we ook de binaire weergave van deze bewerking bekijken:

0110 0101 ----- 0100

0100 is 4 in decimaal, daarom is het resultaat:

resultaat: 4

3.3. Bitsgewijze XOR (^)

De XOR-operator vergelijkt elk binair cijfer van twee gehele getallen en geeft 1 terug als beide vergeleken bits verschillend zijn. Dit betekent dat als bits van beide gehele getallen 1 of 0 zijn, het resultaat 0 zal zijn; anders is het resultaat 1:

@Test openbare ongeldig gegevenTwoIntegers_whenXorOperator_thenNewDecimalNumber () {int waarde1 = 6; int waarde2 = 5; int resultaat = waarde1 ^ waarde2; assertEquals (3, resultaat); }

En de binaire weergave:

0110 0101 ----- 0011

0011 is 3 in decimaal, daarom is het resultaat:

resultaat: 3

3.4. Bitwise AANVULLING (~)

Bitwise Not of Complement-operator betekent eenvoudigweg de negatie van elk bit van de invoerwaarde. Er is slechts één geheel getal nodig en het is gelijk aan de! operator.

Deze operator verandert elk binair cijfer van het gehele getal, wat betekent dat alle 0 1 worden en alle 1 0 worden. De! operator werkt op dezelfde manier voor boolean waarden: het keert om boolean waarden van waar naar false en vice versa.

Laten we nu met een voorbeeld kijken hoe we het complement van een decimaal getal kunnen vinden.

Laten we het complement van waarde1 = 6 doen:

@Test openbare leegte gegevenOneInteger_whenNotOperator_thenNewDecimalNumber () {int waarde1 = 6; int resultaat = ~ waarde1; assertEquals (-7, resultaat); }

De waarde in binair is:

waarde1 = 0000 0110

Door de complementoperator toe te passen, is het resultaat:

0000 0110 -> 1111 1001

Dit is het complement van het decimale getal 6. En aangezien het eerste (meest linkse) bit binair 1 is, betekent dit dat het teken negatief is voor het getal dat is opgeslagen.

Nu, aangezien de getallen worden opgeslagen als 2-complement, moeten we eerst het 2-complement vinden en vervolgens het resulterende binaire getal omzetten in een decimaal getal:

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

Ten slotte is 0000 0111 7 in decimaal. Omdat het tekenbit 1 was zoals hierboven vermeld, is het resulterende antwoord:

resultaat: -7

3.5. Bitwise Operator-tafel

Laten we het resultaat van de operators die we tot nu toe hebben gezien, samenvatten in een vergelijkingstabel:

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

4. Bitwise Shift-operators

Binaire shift-operators verschuiven alle bits van de invoerwaarde naar links of rechts op basis van de shift-operator.

Laten we eens kijken naar de syntaxis voor deze operators:

waarde 

De linkerkant van de uitdrukking is het gehele getal dat wordt verschoven, en de rechterkant van de uitdrukking geeft het aantal keren aan dat het moet worden verschoven.

Operators voor bitsgewijze verschuiving worden verder geclassificeerd als operatoren voor bitsgewijze verschuiving naar links en bitsgewijs verschuiven naar rechts.

4.1. Gesigneerd Left Shift [<<]

De linker shift-operator verschuift de bits naar links met het aantal keren dat is gespecificeerd door de rechterkant van de operand. Na de linker shift wordt de lege ruimte rechts gevuld met 0.

Een ander belangrijk punt om op te merken is dat het verschuiven van een getal met één is gelijk aan het vermenigvuldigen met 2, of, in het algemeen, het naar links verschuiven van een getal met n posities is gelijk aan vermenigvuldiging met 2 ^n.

Laten we de waarde 12 nemen als de invoerwaarde.

Nu gaan we het 2 plaatsen naar links schuiven (12 << 2) en kijken wat het uiteindelijke resultaat zal zijn.

Het binaire equivalent van 12 is 00001100. Na 2 plaatsen naar links te zijn verschoven, is het resultaat 00110000, wat gelijk is aan 48 in decimaal:

@Test openbare leegte gegevenOnePositiveInteger_whenLeftShiftOperator_thenNewDecimalNumber () {int waarde = 12; int leftShift = waarde << 2; assertEquals (48, leftShift); } 

Dit werkt op dezelfde manier voor een negatieve waarde:

@Test openbare leegte gegevenOneNegativeInteger_whenLeftShiftOperator_thenNewDecimalNumber () {int waarde = -12; int leftShift = waarde << 2; assertEquals (-48, leftShift); }

4.2. Gesigneerd Right Shift [>>]

De rechter shift-operator schuift alle bits naar rechts. De lege ruimte aan de linkerkant wordt gevuld afhankelijk van het ingevoerde nummer:

  • Als een ingangsnummer negatief is, waarbij het meest linkse bit 1 is, worden de lege ruimtes gevuld met 1
  • Als een ingangsgetal positief is, waarbij het meest linkse bit 0 is, dan worden de lege ruimtes gevuld met 0

Laten we doorgaan met het voorbeeld met 12 als invoer.

Nu gaan we het 2 plaatsen naar rechts schuiven (12 >> 2) en kijken wat het uiteindelijke resultaat zal zijn.

Het invoergetal is positief, dus na 2 plaatsen naar rechts te zijn verschoven, is het resultaat 0011, dat is 3 in decimaal:

@Test openbare leegte gegevenOnePositiveInteger_whenSignedRightShiftOperator_thenNewDecimalNumber () {int waarde = 12; int rightShift = waarde >> 2; assertEquals (3, rightShift); }

Ook voor een negatieve waarde:

@Test openbare leegte gegevenOneNegativeInteger_whenSignedRightShiftOperator_thenNewDecimalNumber () {int waarde = -12; int rightShift = waarde >> 2; assertEquals (-3, rightShift); }

4.3. Niet-ondertekende rechter verschuiving [>>>]

Deze operator lijkt erg op de operator met teken naar rechts. Het enige verschil is dat de lege ruimtes aan de linkerkant worden gevuld met 0, ongeacht of het getal positief of negatief is. Daarom is het resultaat altijd een positief geheel getal.

Laten we naar rechts dezelfde waarde van 12 verschuiven:

@Test openbare leegte gegevenOnePositiveInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber () {int waarde = 12; int unsignedRightShift = waarde >>> 2; assertEquals (3, unsignedRightShift); }

En nu de negatieve waarde:

@Test openbare ongeldige gegevenOneNegativeInteger_whenUnsignedRightShiftOperator_thenNewDecimalNumber () {int waarde = -12; int unsignedRightShift = waarde >>> 2; assertEquals (1073741821, unsignedRightShift); }

5. Verschil tussen bitsgewijze en logische operators

Er zijn een paar verschillen tussen de bitsgewijze operatoren die we hier hebben besproken en de meer algemeen bekende logische operatoren.

Eerste, logische operators werken aan boolean uitdrukkingen En terugkomen boolean waarden (ofwel waar of false), terwijl bitsgewijze operatoren werken met binaire cijfers van gehele waarden (lang, int, kort, char, en byte) en retourneer een geheel getal.

Logische operators evalueren ook altijd de eerste boolean expressie en, afhankelijk van het resultaat en de gebruikte operator, al dan niet de tweede evalueren. Aan de andere kant, bitsgewijze operatoren evalueren altijd beide operanden.

Ten slotte worden logische operatoren gebruikt bij het nemen van beslissingen op basis van meerdere voorwaarden, terwijl bitgewijze operatoren aan bits werken en bit voor bit bewerkingen uitvoeren.

6. Gebruiksscenario's

Enkele mogelijke gebruiksscenario's van bitsgewijze operatoren zijn:

  • Communicatiestapels waarbij de afzonderlijke bits in de koptekst die aan de gegevens zijn gekoppeld, belangrijke informatie betekenen
  • In embedded systemen om slechts één bit van een specifiek register in te stellen / wissen / omschakelen zonder de resterende bits te wijzigen
  • Om gegevens te versleutelen voor veiligheidsproblemen met behulp van de XOR-operator
  • Bij datacompressie door gegevens van de ene weergave naar de andere te converteren, om de hoeveelheid gebruikte ruimte te verminderen

7. Conclusie

In deze zelfstudie hebben we geleerd over de soorten bitsgewijze operatoren en hoe deze verschillen van logische operatoren. We zagen ook enkele potentiële use-cases voor hen.

Alle codevoorbeelden in dit artikel zijn beschikbaar op GitHub.