Bit Manipulation

Java provides excellent bit manipulation capabilities, which get down to the so-called "bits-and-bytes" level. Sometimes you need to communicate directly with the hardware which sometimes means using the bits-and-bytes.

Bit Manipulation and the Bitwise Operators

I have already touched on this subject in operator assignment but here is a recap on the bitwise operators

Operator
Name
Description
&
bitwise AND

The bits in the result are set to 1 if the corresponding bits in the two operands are both 1

1 1 = 1

|
bitwise inclusive OR

The bits in the result are set to 1 if one of the corresponding bits in the two operands are 1

1 0 = 1
0 1 = 1
1 1 = 1

^
biwise exclusive OR

The bits in the result are set to 1 if exactly one corresponding bit in either operand is both 1

1 0 = 1
0 1 = 1

<<
left shift
Shifts the bits of the first operand left by the number of bits specified by the second operand; fill from the right with 0 bits
>>
right shift with sign extension
Shifts the bits of the first operand right by the number of bits specified by the second operand. If the first operand is negative, 1's are shifted in from the left, otherwise 0's are shifted in from the left
>>>
right shift with zero extension
Shifts the bits of the first operand right by the number of bits specified by the second operand; 0's are shifted in from the left
~
one's complement
all 0 bits are set to 1 and all 1 bits are set to 0

Now for an example

Display bits
// PrintBits Class

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PrintBits extends JFrame {

   public PrintBits()
   {
      super( "Printing bit representations for numbers" );

      Container c = getContentPane();
      c.setLayout( new FlowLayout() );
      c.add( new JLabel( "Enter an integer " ) );
      final JTextField output = new JTextField( 33 );
      JTextField input = new JTextField( 10 );
      input.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               int val = Integer.parseInt( e.getActionCommand() );
               output.setText( getBits( val ) );
            }
         }
      );
      c.add( input );

      c.add( new JLabel( "The integer in bits is" ) );      
      output.setEditable( false );
      c.add( output );

      setSize( 720, 70 );
      show();
   }

   private String getBits( int value )
   {
      int displayMask = 1 << 31;
      StringBuffer buf = new StringBuffer( 35 );

      for ( int c = 1; c <= 32; c++ ) {
         buf.append(
            ( value & displayMask ) == 0 ? '0' : '1' );
         value <<= 1;

         if ( c % 8 == 0 )
            buf.append( ' ' );
      }

      return buf.toString();
   }

   public static void main( String args[] )
   {
      PrintBits app = new PrintBits();
      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );
   }
}

Now an example on how to manipulate the bits

Bit manipulation example
// MiscBitOps Class

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MiscBitOps extends JFrame {
   private JTextField input1, input2, bits1, bits2;
   private int val1, val2;

   public MiscBitOps()
   {
      super( "Bitwise operators" );

      JPanel inputPanel = new JPanel();
      inputPanel.setLayout( new GridLayout( 4, 2 ) );

      inputPanel.add( new JLabel( "Enter 2 ints" ) );
      inputPanel.add( new JLabel( "" ) );

      inputPanel.add( new JLabel( "Value 1" ) );
      input1 = new JTextField( 8 );
      inputPanel.add( input1 );

      inputPanel.add( new JLabel( "Value 2" ) );
      input2 = new JTextField( 8 );
      inputPanel.add( input2 );

      inputPanel.add( new JLabel( "Result" ) );
      final JTextField result = new JTextField( 8 );
      result.setEditable( false );
      inputPanel.add( result );

      JPanel bitsPanel = new JPanel();
      bitsPanel.setLayout( new GridLayout( 4, 1 ) );
      bitsPanel.add( new JLabel( "Bit representations" ) );

      bits1 = new JTextField( 33 );
      bits1.setEditable( false );
      bitsPanel.add( bits1 );

      bits2 = new JTextField( 33 );
      bits2.setEditable( false );
      bitsPanel.add( bits2 );

      final JTextField bits3 = new JTextField( 33 );
      bits3.setEditable( false );
      bitsPanel.add( bits3 );

      JPanel buttonPanel = new JPanel();
      JButton and = new JButton( "AND" );
      and.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               setFields();
               result.setText( Integer.toString( val1 & val2 ) );
               bits3.setText( getBits( val1 & val2 ) );
            }
         }
      );
      buttonPanel.add( and );

      JButton inclusiveOr = new JButton( "Inclusive OR" );
      inclusiveOr.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               setFields();
               result.setText( Integer.toString( val1 | val2 ) );
               bits3.setText( getBits( val1 | val2 ) );
            }
         }
      );
      buttonPanel.add( inclusiveOr );

      JButton exclusiveOr = new JButton( "Exclusive OR" );
      exclusiveOr.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               setFields();
               result.setText( Integer.toString( val1 ^ val2 ) );
               bits3.setText( getBits( val1 ^ val2 ) );
            }
         }
      );
      buttonPanel.add( exclusiveOr );
               
      JButton complement = new JButton( "Complement" );
      complement.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               input2.setText( "" );
               bits2.setText( "" );
               int val = Integer.parseInt( input1.getText() );
               result.setText( Integer.toString( ~val ) );
               bits1.setText( getBits( val ) );
               bits3.setText( getBits( ~val ) );
            }
         }
      );
      buttonPanel.add( complement );

      Container c = getContentPane();
      c.setLayout( new BorderLayout() );
      c.add( inputPanel, BorderLayout.WEST );
      c.add( bitsPanel, BorderLayout.EAST );
      c.add( buttonPanel, BorderLayout.SOUTH );

      setSize( 600, 150 );
      show();
   }

   private void setFields()
   {
      val1 = Integer.parseInt( input1.getText() );
      val2 = Integer.parseInt( input2.getText() );

      bits1.setText( getBits( val1 ) );
      bits2.setText( getBits( val2 ) );
   }

   private String getBits( int value )
   {
      int displayMask = 1 << 31;
      StringBuffer buf = new StringBuffer( 35 );

      for ( int c = 1; c <= 32; c++ ) {
         buf.append(
            ( value & displayMask ) == 0 ? '0' : '1' );
         value <<= 1;

         if ( c % 8 == 0 )
            buf.append( ' ' );
      }

      return buf.toString();
   }

   public static void main( String args[] )
   {
      MiscBitOps app = new MiscBitOps();
      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );
   }
}

Now an example on shifting bits

Shifting bit example
// BitShift Class

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class BitShift extends JFrame {

   public BitShift()
   {
      super( "Shifting bits" );

      Container c = getContentPane();
      c.setLayout( new FlowLayout() );
      final JTextField bits = new JTextField( 33 );
      c.add( new JLabel( "Integer to shift " ) );

      final JTextField value = new JTextField( 12 );
      value.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               int val = Integer.parseInt( value.getText() );
               bits.setText( getBits( val ) );
            }
         }
      );                   
      c.add( value );      
      
      bits.setEditable( false );
      c.add( bits );      

      JButton left = new JButton( "<<" );
      left.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               int val = Integer.parseInt( value.getText() );
               val <<= 1;
               value.setText( Integer.toString( val ) );
               bits.setText( getBits( val ) );
            }
         }
      );
      c.add( left );      

      JButton rightSign = new JButton( ">>" );
      rightSign.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               int val = Integer.parseInt( value.getText() );
               val >>= 1;
               value.setText( Integer.toString( val ) );
               bits.setText( getBits( val ) );
            }
         }
      );                    
      c.add( rightSign );      

      JButton rightZero = new JButton( ">>>" );
      rightZero.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               int val = Integer.parseInt( value.getText() );
               val >>>= 1;
               value.setText( Integer.toString( val ) );
               bits.setText( getBits( val ) );
            }
         }
      );
      c.add( rightZero );

      setSize( 400, 120 );
      show();
   }

   private String getBits( int value )
   {
      int displayMask = 1 << 31;
      StringBuffer buf = new StringBuffer( 35 );

      for ( int c = 1; c <= 32; c++ ) {
         buf.append(
            ( value & displayMask ) == 0 ? '0' : '1' );
         value <<= 1;

         if ( c % 8 == 0 )
            buf.append( ' ' );
      }

      return buf.toString();
   }

   public static void main( String args[] )
   {
      BitShift app = new BitShift();
      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );
   }
}

BitSet Class

The BitSet class makes life easier to create and manipulate bit sets. Bit sets are useful for representing a set of boolean flags, they are dynamically resizeable.

Create empty bit set BitSet b = new BitSet();
Create a bitset with size BitSet b = new BitSet( size );
set a bit to "on" b.set( bit Number );

There are a number of methods that can be used

clear sets a bit to "off"
get retrieve a bit's setting
and,or and xor performs logical operations on bit sets
size return the size of a bitset
equals compares two bitset for equality
clone clones a bitset and returns an Object reference to the new bitset
toString converts bitsets to a String
hashCode provides a hash code useful for storing and retrieving bitset objects in hash tables
Example
BitSet example
// BitSetTest Class

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;

public class BitSetTest extends JFrame {
 
   public BitSetTest()
   {
      super( "BitSets" );

      final BitSet sieve = new BitSet( 1024 );
      Container c = getContentPane();
      final JLabel status = new JLabel();
      c.add( status, BorderLayout.SOUTH );
      JPanel inputPanel = new JPanel();

      inputPanel.add( new JLabel( "Enter a value from " + "1 to 1023" ) );
      final JTextField input = new JTextField( 10 );
      input.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               int val = Integer.parseInt( input.getText() );

               if ( sieve.get( val ) )
                  status.setText( val + " is a prime number" );
               else
                  status.setText( val + " is not a prime number" );
            }
         }
      );
      inputPanel.add( input );
      c.add( inputPanel, BorderLayout.NORTH );

      JTextArea primes = new JTextArea();
      ScrollPane p = new ScrollPane();
      p.add( primes );

      c.add( p, BorderLayout.CENTER );

      // set all bits from 1 to 1023
      int size = sieve.size();

      for ( int i = 1; i < size; i++ )
         sieve.set( i );

      // perform Sieve of Eratosthenes
      int finalBit = ( int ) Math.sqrt( sieve.size() );

      for ( int i = 2; i < finalBit; i++ ) 
         if ( sieve.get( i ) ) 
            for ( int j = 2 * i; j < size; j += i ) 
               sieve.clear( j );

      int counter = 0;

      for ( int i = 1; i < size; i++ )
         if ( sieve.get( i ) ) {
            primes.append( String.valueOf( i ) );
            primes.append( ++counter % 7 == 0 ? "\n" : "\t" );
         }

      setSize( 300, 250 );
      show();
   }

   public static void main( String args[] )
   {
      BitSetTest app = new BitSetTest();
      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );
   }
}