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 |
^ |
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 |
<< |
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 ); } } ); } } |
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 ); } } ); } } |