Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java How to Program, Fourth Edition - Deitel H., Deitel P.pdf
Скачиваний:
58
Добавлен:
24.05.2014
Размер:
14.17 Mб
Скачать

Chapter 20

Java Utilities Package and Bit Manipulation

1175

0 through 5. Then simply shift this value by adding 1 to produce a number in the range from 1 through 6. The expression is as follows:

Math.abs( r.nextInt() ) % 6 + 1

The calls

r.nextFloat()

r.nextDouble()

generate uniformly distributed values in the range 0.0 <= x < 1.0. The call

r.nextGaussian()

generates a double value with a probability density of a Gaussian (i.e., “normal”) distribution (mean of 0.0 and standard deviation of 1.0).

20.8 Bit Manipulation and the Bitwise Operators

Java provides extensive bit-manipulation capabilities for programmers who need to get down to the so-called “bits-and-bytes” level. Operating systems, test equipment software, networking software and many other kinds of software require that the programmer communicate “directly with the hardware.” In this section and the next, we discuss Java’s bitmanipulation capabilities. We introduce Java’s bitwise operators, and we demonstrate their use in live-code examples.

Computers represent all data internally as sequences of bits. Each bit can assume the value 0 or the value 1. On most systems, a sequence of 8 bits forms a byte—the standard storage unit for a variable of type byte. Other data types are stored in larger numbers of bytes. The bitwise operators can manipulate the bits of integral operands (i.e., those having type byte, char, short, int and long).

Note that the bitwise operator discussions in this section show the binary representations of the integer operands. For a detailed explanation of the binary (also called base 2) number system, see Appendix E, Number Systems.

The bitwise operators are bitwise AND (&), bitwise inclusive OR (|), bitwise exclusive OR (^), left shift (<<), right shift with sign extension (>>), right shift with zero extension

(>>>) and complement (~). The bitwise AND, bitwise inclusive OR and bitwise exclusive OR operators compare their two operands bit by bit. The bitwise AND operator sets each bit in the result to 1 if the corresponding bit in both operands is 1. The bitwise inclusive OR operator sets each bit in the result to 1 if the corresponding bit in either (or both) operand(s) is 1. The bitwise exclusive OR operator sets each bit in the result to 1 if the corresponding bit in exactly one operand is 1. The left shift operator shifts the bits of its left operand to the left by the number of bits specified in its right operand. The right shift operator with sign extension shifts the bits in its left operand to the right by the number of bits specified in its right operand—if the left operand is negative, 1s are shifted in from the left; otherwise, 0s are shifted in from the left. The right shift operator with zero extension shifts the bits in its left operand to the right by the number of bits specified in its right operand—0s are shifted in from the left. The bitwise complement operator sets all 0 bits in its operand to 1 in the result and sets all 1 bits to 0 in the result. Detailed discussions of each bitwise operator appear in the following examples. The bitwise operators are summarized in Fig. 20.5.

1176

Java Utilities Package and Bit Manipulation

Chapter 20

 

 

 

 

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.

 

|

 

bitwise inclusive OR

The bits in the result are set to 1 if at least one of the cor-

 

 

 

responding bits in the two operands is 1.

 

^

 

bitwise exclusive OR

The bits in the result are set to 1 if exactly one of the corre-

 

 

 

sponding bits in the two operands is 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

Shifts the bits of the first operand right by the number of bits

 

 

extension

specified by the second operand. If the first operand is nega-

 

 

 

tive, 1s are shifted in from the left; otherwise, 0s 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; 0s are shifted in from the left.

~

one’s complement

All 0 bits are set to 1 and all 1 bits are set to 0.

Fig. 20.5 The bitwise operators .

When using the bitwise operators, it is useful to display values in their binary representation to illustrate the effects of these operators. The application of Fig. 20.6 allows the user to enter an integer into a JTextField and press Enter. Method actionPerformed (lines 32–36) reads the String from the JTextField, converts it to an integer and invokes method getBits (lines 55–80) to obtain a String representation of the integer in bits. The result is displayed in the output JTextField. The integer is displayed in its binary representation in groups of eight bits each. Method getBits uses the bitwise AND operator to combine variable value with variable displayMask. Often, the bitwise AND operator is used with an operand called a mask—an integer value with specific bits set to 1. Masks are used to hide some bits in a value while selecting other bits. In getBits, mask variable displayMask is assigned the value 1 << 31 or

10000000 00000000 00000000 00000000

The left shift operator shifts the value 1 from the low-order (rightmost) bit to the high-order (leftmost) bit in displayMask and fills in 0 bits from the right.

1// Fig. 20.6: PrintBits.java

2 // Printing an unsigned integer in bits

3

4 // Java core packages

5import java.awt.*;

6import java.awt.event.*;

Fig. 20.6 Printing the bits in an integer (part 1 of 3).

Chapter 20

Java Utilities Package and Bit Manipulation

1177

7

8 // Java extension packages

9 import javax.swing.*;

10

11public class PrintBits extends JFrame {

12private JTextField outputField;

13

14// set up GUI

15public PrintBits()

16{

17super( "Printing bit representations for numbers" );

19Container container = getContentPane();

20container.setLayout( new FlowLayout() );

22 container.add( new JLabel( "Enter an integer " ) );

23

24// textfield to read value from user

25JTextField inputField = new JTextField( 10 );

27

inputField.addActionListener(

28

 

29

new ActionListener() {

30

 

31

// read integer and get bitwise representation

32

public void actionPerformed( ActionEvent event )

33

{

34

int value = Integer.parseInt(

35

event.getActionCommand() );

36

outputField.setText( getBits( value ) );

37

}

38}

39);

41 container.add( inputField );

42

43 container.add( new JLabel( "The integer in bits is" ) );

44

45// textfield to display integer in bitwise form

46outputField = new JTextField( 33 );

47outputField.setEditable( false );

48container.add( outputField );

49

50setSize( 720, 70 );

51setVisible( true );

52}

53

54// display bit representation of specified int value

55private String getBits( int value )

56{

57// create int value with 1 in leftmost bit and 0s elsewhere

58int displayMask = 1 << 31;

59

Fig. 20.6 Printing the bits in an integer (part 2 of 3).

1178

Java Utilities Package and Bit Manipulation

Chapter 20

60// buffer to build output

61StringBuffer buffer = new StringBuffer( 35 );

63// for each bit append 0 or 1 to buffer

64for ( int bit = 1; bit <= 32; bit++ ) {

66

// use displayMask to isolate bit and determine whether

67

// bit has value of 0 or 1

68

buffer.append(

69

( value & displayMask ) == 0 ? '0' : '1' );

70

 

71

// shift value one position to left

72

value <<= 1;

73

 

74

// append space to buffer every 8 bits

75

if ( bit % 8 == 0 )

76

buffer.append( ' ' );

77

}

78

 

79return buffer.toString();

80}

81

82// execute application

83public static void main( String args[] )

84{

85PrintBits application = new PrintBits();

87 application.setDefaultCloseOperation(

88JFrame.EXIT_ON_CLOSE );

89}

90

91 } // end class PrintBits

Fig. 20.6 Printing the bits in an integer (part 3 of 3).

Lines 68–69 append a 1 or a 0 to a StringBuffer for the current leftmost bit of variable value. Assume that value contains 4000000000 (11101110 01101011 00101000 00000000). When value and displayMask are combined using &, all the bits except the high-order (leftmost) bit in variable value are “masked off” (hidden), because any bit “ANDed” with 0 yields 0. If the leftmost bit is 1, value & displayMask evaluates to a nonzero value and 1 is appended; otherwise, 0 is appended. Then vari-

Chapter 20 Java Utilities Package and Bit Manipulation 1179

able value is left shifted one bit by the expression value <<= 1 (this is equivalent to value = value << 1). These steps are repeated for each bit in variable value. At the end of method getBits, the StringBuffer is converted to a String in line 79 and returned from the method. Figure 20.7 summarizes the results of combining two bits with the bitwise AND (&) operator.

Common Programming Error 20.1

Using the logical AND operator (&&) for the bitwise AND operator (&) is a common pro- gramming error.

Figure 20.8 demonstrates the bitwise AND operator, the bitwise inclusive OR operator, the bitwise exclusive OR operator and the bitwise complement operator. The program uses method getBits (lines 163–188) to get a String representation of the integer values. The program allows the user to enter values into JTextFields (for the binary operators, two values must be entered), and then to press the button representing the operation they would like to test. The program displays the result of each operation in both integer and bitwise representations.

The first output window for Fig. 20.8 shows the results of combining the value 65535 and the value 1 with the bitwise AND operator (&). All the bits except the low-order bit in the value 65535 are “masked off” (hidden) by “ANDing” with the value 1.

Bit 1

Bit 2

Bit 1 & Bit 2

 

 

 

0

0

0

1

0

0

0

1

0

1

1

1

Fig. 20.7 Results of combining two bits with the bitwise AND operator (&).

1// Fig. 20.8: MiscBitOps.java

2 // Using the bitwise AND, bitwise inclusive OR, bitwise 3 // exclusive OR, and bitwise complement operators.

4

5 // Java core packages

6import java.awt.*;

7 import java.awt.event.*;

8

9 // Java extension packages

10 import javax.swing.*;

11

12public class MiscBitOps extends JFrame {

13private JTextField input1Field, input2Field,

14bits1Field, bits2Field, bits3Field, resultField;

Fig. 20.8 Demonstrating the bitwise AND, bitwise inclusive OR, bitwise exclusive OR and bitwise complement operators (part 1 of 6).

1180

Java Utilities Package and Bit Manipulation

Chapter 20

15 private int value1, value2;

16

17// set up GUI

18public MiscBitOps()

19{

20super( "Bitwise operators" );

22JPanel inputPanel = new JPanel();

23inputPanel.setLayout( new GridLayout( 4, 2 ) );

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

26inputPanel.add( new JLabel( "" ) );

27

28inputPanel.add( new JLabel( "Value 1" ) );

29input1Field = new JTextField( 8 );

30inputPanel.add( input1Field );

31

32inputPanel.add( new JLabel( "Value 2" ) );

33input2Field = new JTextField( 8 );

34inputPanel.add( input2Field );

35

36inputPanel.add( new JLabel( "Result" ) );

37resultField = new JTextField( 8 );

38resultField.setEditable( false );

39inputPanel.add( resultField );

40

41JPanel bitsPanel = new JPanel();

42bitsPanel.setLayout( new GridLayout( 4, 1 ) );

43bitsPanel.add( new JLabel( "Bit representations" ) );

45bits1Field = new JTextField( 33 );

46bits1Field.setEditable( false );

47bitsPanel.add( bits1Field );

48

49bits2Field = new JTextField( 33 );

50bits2Field.setEditable( false );

51bitsPanel.add( bits2Field );

52

53bits3Field = new JTextField( 33 );

54bits3Field.setEditable( false );

55bitsPanel.add( bits3Field );

56

57 JPanel buttonPanel = new JPanel();

58

59// button to perform bitwise AND

60JButton andButton = new JButton( "AND" );

62

andButton.addActionListener(

63

 

64

new ActionListener() {

65

 

Fig. 20.8 Demonstrating the bitwise AND, bitwise inclusive OR, bitwise exclusive OR and bitwise complement operators (part 2 of 6).

Chapter 20

Java Utilities Package and Bit Manipulation

1181

 

 

 

66

// perform bitwise AND and display results

 

67

public void actionPerformed( ActionEvent event )

 

68

{

 

69

setFields();

 

70

resultField.setText(

 

71

Integer.toString( value1 & value2 ) );

 

72

bits3Field.setText( getBits( value1 & value2 ) );

73

}

 

74}

75);

77 buttonPanel.add( andButton );

78

79// button to perform bitwise inclusive OR

80JButton inclusiveOrButton = new JButton( "Inclusive OR" );

82

inclusiveOrButton.addActionListener(

83

 

84

new ActionListener() {

85

 

86

// perform bitwise inclusive OR and display results

87

public void actionPerformed( ActionEvent event )

88

{

89

setFields();

90

resultField.setText(

91

Integer.toString( value1 | value2 ) );

92

bits3Field.setText( getBits( value1 | value2 ) );

93

}

94}

95);

97

buttonPanel.add( inclusiveOrButton );

98

 

99

// button to perform bitwise exclusive OR

100

JButton exclusiveOrButton = new JButton( "Exclusive OR" );

101

 

102

exclusiveOrButton.addActionListener(

103

 

104

new ActionListener() {

105

 

106

// perform bitwise exclusive OR and display results

107

public void actionPerformed( ActionEvent event )

108

{

109

setFields();

110

resultField.setText(

111

Integer.toString( value1 ^ value2 ) );

112

bits3Field.setText( getBits( value1 ^ value2 ) );

113

}

114}

115);

117 buttonPanel.add( exclusiveOrButton );

Fig. 20.8 Demonstrating the bitwise AND, bitwise inclusive OR, bitwise exclusive OR and bitwise complement operators (part 3 of 6).

1182

Java Utilities Package and Bit Manipulation

Chapter 20

118

119// button to perform bitwise complement

120JButton complementButton = new JButton( "Complement" );

122

complementButton.addActionListener(

123

 

124

new ActionListener() {

125

 

126

// perform bitwise complement and display results

127

public void actionPerformed( ActionEvent event )

128

{

129

input2Field.setText( "" );

130

bits2Field.setText( "" );

131

 

132

int value = Integer.parseInt( input1Field.getText() );

133

 

134

resultField.setText( Integer.toString( ~value ) );

135

bits1Field.setText( getBits( value ) );

136

bits3Field.setText( getBits( ~value ) );

137

}

138}

139);

141 buttonPanel.add( complementButton );

142

143Container container = getContentPane();

144container.add( inputPanel, BorderLayout.WEST );

145container.add( bitsPanel, BorderLayout.EAST );

146container.add( buttonPanel, BorderLayout.SOUTH );

148setSize( 600, 150 );

149setVisible( true );

150}

151

152// display numbers and their bit form

153private void setFields()

154{

155value1 = Integer.parseInt( input1Field.getText() );

156value2 = Integer.parseInt( input2Field.getText() );

158bits1Field.setText( getBits( value1 ) );

159bits2Field.setText( getBits( value2 ) );

160}

161

162// display bit representation of specified int value

163private String getBits( int value )

164{

165// create int value with 1 in leftmost bit and 0s elsewhere

166int displayMask = 1 << 31;

167

168// buffer to build output

169StringBuffer buffer = new StringBuffer( 35 );

Fig. 20.8 Demonstrating the bitwise AND, bitwise inclusive OR, bitwise exclusive OR and bitwise complement operators (part 4 of 6).

Chapter 20

Java Utilities Package and Bit Manipulation

1183

170

171// for each bit append 0 or 1 to buffer

172for ( int bit = 1; bit <= 32; bit++ ) {

174

// use displayMask to isolate bit and determine whether

175

// bit has value of 0 or 1

176

buffer.append(

177

( value & displayMask ) == 0 ? '0' : '1' );

178

 

179

// shift value one position to left

180

value <<= 1;

181

 

182

// append space to buffer every 8 bits

183

if ( bit % 8 == 0 )

184buffer.append( ' ' );

185}

186

187return buffer.toString();

188}

189

190// execute application

191public static void main( String args[] )

192{

193MiscBitOps application = new MiscBitOps();

195 application.setDefaultCloseOperation(

196JFrame.EXIT_ON_CLOSE );

197}

198

199 } // end class MiscBitOps

Fig. 20.8 Demonstrating the bitwise AND, bitwise inclusive OR, bitwise exclusive OR and bitwise complement operators (part 5 of 6).

1184

Java Utilities Package and Bit Manipulation

Chapter 20

 

 

 

 

 

 

Fig. 20.8 Demonstrating the bitwise AND, bitwise inclusive OR, bitwise exclusive OR and bitwise complement operators (part 6 of 6).

The bitwise inclusive OR operator sets specific bits to 1 in an operand. The second output window for Fig. 20.8 shows the results of combining the value 15 and the value 241 by using the bitwise OR operator—the result is 255. Figure 20.9 summarizes the results of combining two bits with the bitwise inclusive OR operator.

Common Programming Error 20.2

Using the logical OR operator (||) for the bitwise OR operator (|) is a common program- ming error.

The bitwise exclusive OR operator (^) sets each bit in the result to 1 if exactly one of the corresponding bits in its two operands is 1. The third output of Fig. 20.8 shows the results of combining the value 139 and the value 199 by using the exclusive OR oper- ator—the result is 76. Figure 20.10 summarizes the results of combining two bits with the bitwise exclusive OR operator.

Bit 1

Bit 2

Bit 1 | Bit 2

 

 

 

0

0

0

1

0

1

0

1

1

1

1

1

Fig. 20.9 Results of combining two bits with the bitwise inclusive OR operator (|).

Chapter 20

Java Utilities Package and Bit Manipulation

1185

 

 

 

 

Bit 1

Bit 2

Bit 1 ^ Bit 2

 

 

 

 

 

0

0

0

 

1

0

1

 

0

1

1

 

1

1

0

 

Fig. 20.10 Results of combining two bits with the bitwise exclusive OR operator (^).

The bitwise complement operator (~) sets all 1 bits in its operand to 0 in the result and sets all 0 bits to 1 in the result—otherwise referred to as “taking the one's complement of the value.” The fourth output window for Fig. 20.8 shows the results of taking the one’s complement of the value 21845. The result is -21846.

The program of Fig. 20.11 demonstrates the left shift operator (<<), the right shift operator with sign extension (>>) and the right shift operator with zero extension (>>>). Method getBits (lines 113–138) obtains a String containing the bit representation of the integer values. The program allows the user to enter an integer into a JTextField and press Enter to display the bit representation of the integer in a second JTextField. The the user can press a button representing a shift operation to perform a 1-bit shift and view the results of the shift in both integer and bitwise representation.

1// Fig. 20.11: BitShift.java

2 // Using the bitwise shift operators.

3

4 // Java core packages

5import java.awt.*;

6 import java.awt.event.*;

7

8 // Java extension packages

9 import javax.swing.*;

10

11public class BitShift extends JFrame {

12private JTextField bitsField;

13private JTextField valueField;

14

15// set up GUI

16public BitShift()

17{

18super( "Shifting bits" );

20Container container = getContentPane();

21container.setLayout( new FlowLayout() );

23 container.add( new JLabel( "Integer to shift " ) );

24

25// textfield for user to input integer

26valueField = new JTextField( 12 );

Fig. 20.11 Demonstrating the bitwise shift operators (part 1 of 5).

1186

Java Utilities Package and Bit Manipulation

Chapter 20

 

 

 

27

container.add( valueField );

 

28

 

 

29

valueField.addActionListener(

 

30

 

 

31

new ActionListener() {

 

32

 

 

33

// read value and display its bitwise representation

34

public void actionPerformed( ActionEvent event )

35

{

 

36

int value = Integer.parseInt( valueField.getText() );

37

bitsField.setText( getBits( value ) );

 

38

}

 

39}

40);

42// textfield to display bitwise representation of an integer

43bitsField = new JTextField( 33 );

44bitsField.setEditable( false );

45container.add( bitsField );

46

47// button to shift bits left by one position

48JButton leftButton = new JButton( "<<" );

49

 

50

leftButton.addActionListener(

51

 

52

new ActionListener() {

53

 

54

// left shift one position and display new value

55

public void actionPerformed( ActionEvent event )

56

{

57

int value = Integer.parseInt( valueField.getText() );

58

value <<= 1;

59

valueField.setText( Integer.toString( value ) );

60

bitsField.setText( getBits( value ) );

61

}

62}

63);

65 container.add( leftButton );

66

67// button to right shift value one position with sign extension

68JButton rightSignButton = new JButton( ">>" );

69

 

70

rightSignButton.addActionListener(

71

 

72

new ActionListener() {

73

 

74

// right shift one position and display new value

75

public void actionPerformed( ActionEvent event )

76

{

77

int value = Integer.parseInt( valueField.getText() );

78

value >>= 1;

79

valueField.setText( Integer.toString( value ) );

 

 

Fig. 20.11

Demonstrating the bitwise shift operators (part 2 of 5).

Chapter 20

Java Utilities Package and Bit Manipulation

1187

 

 

 

80

bitsField.setText( getBits( value ) );

 

81

}

 

82}

83);

85 container.add( rightSignButton );

86

87// button to right shift value one position with zero extension

88JButton rightZeroButton = new JButton( ">>>" );

89

 

90

rightZeroButton.addActionListener(

91

 

92

new ActionListener() {

93

 

94

// right shift one position and display new value

95

public void actionPerformed( ActionEvent event )

96

{

97

int value = Integer.parseInt( valueField.getText() );

98

value >>>= 1;

99

valueField.setText( Integer.toString( value ) );

100

 

101

bitsField.setText( getBits( value ) );

102

}

103}

104);

106 container.add( rightZeroButton );

107

108setSize( 400, 120 );

109setVisible( true );

110}

111

112// display bit representation of specified int value

113private String getBits( int value )

114{

115// create int value with 1 in leftmost bit and 0s elsewhere

116int displayMask = 1 << 31;

117

118// buffer to build output

119StringBuffer buffer = new StringBuffer( 35 );

121// for each bit append 0 or 1 to buffer

122for ( int bit = 1; bit <= 32; bit++ ) {

124

// use displayMask to isolate bit and determine whether

125

// bit has value of 0 or 1

126

buffer.append(

127

( value & displayMask ) == 0 ? '0' : '1' );

128

 

129

// shift value one position to left

130

value <<= 1;

131

 

 

 

Fig. 20.11 Demonstrating the bitwise shift operators (part 3 of 5).

1188

Java Utilities Package and Bit Manipulation

Chapter 20

132 // append space to buffer every 8 bits

133 if ( bit % 8 == 0 )

134buffer.append( ' ' );

135}

136

137return buffer.toString();

138}

139

140// execute application

141public static void main( String args[] )

142{

143BitShift application = new BitShift();

145 application.setDefaultCloseOperation(

146JFrame.EXIT_ON_CLOSE );

147}

148

149 } // end class BitShift

Fig. 20.11 Demonstrating the bitwise shift operators (part 4 of 5).

Chapter 20

Java Utilities Package and Bit Manipulation

1189

 

 

 

 

 

 

Fig. 20.11 Demonstrating the bitwise shift operators (part 5 of 5).

The left shift operator (<<) shifts the bits of its left operand to the left by the number of bits specified in its right operand (performed at line 58 in the program). Bits vacated to the right are replaced with 0s; 1s shifted off the left are lost. The first four output windows of Fig. 20.11 demonstrate the left shift operator. Starting with the value 1, the left shift button was pressed twice, resulting in the values 2 and 4, respectively. The fourth output window shows the result of value1 being shifted 31 times. Note that the result is a negative value. That is because a 1 in the high-order bit is used to indicate a negative value in an integer.

The right shift operator with sign extension (>>) shifts the bits of its left operand to the right by the number of bits specified in its right operand (performed at line 78 in the program). Performing a right shift causes the vacated bits at the left to be replaced by 0s if the number is positive or 1s if the number is negative. Any 1s shifted off the right are lost. The fifth and sixth output windows show the results of right shifting (with sign extension) the value in the fourth output window two times.

The right shift operator with zero extension (>>>) shifts the bits of its left operand to the right by the number of bits specified in its right operand (performed at line 98 in the program). Performing a right shift causes the vacated bits at the left to be replaced by 0s. Any 1s shifted off the right are lost. The eighth and ninth output windows show the results of right shifting (with zero extension) the value in the seventh output window two times.

Each bitwise operator (except the bitwise complement operator) has a corresponding assignment operator. These bitwise assignment operators are shown in Fig. 20.12.

1190

Java Utilities Package and Bit Manipulation

Chapter 20

 

 

Bitwise assignment operators

 

 

 

 

&=

Bitwise AND assignment operator.

 

|=

Bitwise inclusive OR assignment operator.

 

^=

Bitwise exclusive OR assignment operator.

 

<<=

Left shift assignment operator.

 

>>=

Right shift with sign extension assignment operator.

 

>>>=

Right shift with zero extension assignment operator.

 

Fig. 20.12 The bitwise assignment operators.

20.9 BitSet Class

Class BitSet makes it easy to create and manipulate bit sets. Bit sets are useful for representing a set of boolean flags. BitSets are dynamically resizable. More bits can be added as needed, and a BitSet object will grow to accommodate the additional bits. The statement

BitSet b = new BitSet();

creates a BitSet that initially is empty. Also, a program can specify the size of a BitSet with the statement

BitSet b = new BitSet( size );

which creates a BitSet with size bits. The statement

b.set( bitNumber );

sets bit bitNumber “on.” This makes the underlying value of that bit 1. Note that bit numbers are zero based, like Vectors. The statement

b.clear( bitNumber );

sets bit bitNumber “off.” This makes the underlying value of that bit 0. The statement

b.get( bitNumber );

gets the value of bit bitNumber. The result is returned as true if the bit is on, false if the bit is off.

The statement

b.and( b1 );

performs a bit-by-bit logical AND between BitSets b and b1. The result is stored in b. Bitwise logical OR and bitwise logical XOR are performed by the statements

b.or( b1 ); b.xor( b2 );

Chapter 20

Java Utilities Package and Bit Manipulation

1191

The expression

b.size()

returns the size of the BitSet. The expression

b.equals( b1 )

compares the two BitSets for equality. The expression

b.toString()

creates a String representation of the BitSet contents. This is helpful for debugging. Figure 20.13 revisits the Sieve of Eratosthenes for finding prime numbers, which we dis-

cussed in Exercise 7.27. This example uses a BitSet rather than an array to implement the algorithm. The program displays all the prime numbers from 2 to 1023 in a JTextArea and provides a JTextField in which the user can type any number from 2 to 1023 to determine whether that number is prime (in which case a message is displayed in a JLabel).

1// Fig. 20.13: BitSetTest.java

2 // Using a BitSet to demonstrate the Sieve of Eratosthenes.

3

4 // Java core packages

5import java.awt.*;

6 import java.awt.event.*;

7 import java.util.*;

8

9 // Java extension packages

10 import javax.swing.*;

11

12public class BitSetTest extends JFrame {

13private BitSet sieve;

14private JLabel statusLabel;

15private JTextField inputField;

16

17// set up GUI

18public BitSetTest()

19{

20super( "BitSets" );

22 sieve = new BitSet( 1024 );

23

24 Container container = getContentPane();

25

26statusLabel = new JLabel( "" );

27container.add( statusLabel, BorderLayout.SOUTH );

29

JPanel inputPanel = new JPanel();

30

 

31

inputPanel.add( new JLabel(

32

"Enter a value from 2 to 1023" ) );

Fig. 20.13 Demonstrating the Sieve of Eratosthenes using a BitSet (part 1 of 3).

1192

Java Utilities Package and Bit Manipulation

Chapter 20

33

34// textfield for user to input a value from 2 to 1023

35inputField = new JTextField( 10 );

36

 

37

inputField.addActionListener(

38

 

39

new ActionListener() {

40

 

41

// determine whether value is prime number

42

public void actionPerformed( ActionEvent event )

43

{

44

int value = Integer.parseInt( inputField.getText() );

45

 

46

if ( sieve.get( value ) )

47

statusLabel.setText(

48

value + " is a prime number" );

49

 

50

else

51

statusLabel.setText( value +

52

" is not a prime number" );

53

}

54}

55);

57inputPanel.add( inputField );

58container.add( inputPanel, BorderLayout.NORTH );

60 JTextArea primesArea = new JTextArea();

61

62 container.add( new JScrollPane( primesArea ),

63 BorderLayout.CENTER );

64

65// set all bits from 1 to 1023

66int size = sieve.size();

67

68 for ( int i = 2; i < size; i++ ) 69 sieve.set( i );

70

71// perform Sieve of Eratosthenes

72int finalBit = ( int ) Math.sqrt( sieve.size() );

74

for ( int i = 2; i < finalBit; i++ )

75

 

76

if ( sieve.get( i ) )

77

 

78

for ( int j = 2 * i; j < size; j += i )

79

sieve.clear( j );

80

 

81// display prime numbers from 1 to 1023

82int counter = 0;

83

Fig. 20.13 Demonstrating the Sieve of Eratosthenes using a BitSet (part 2 of 3).

Chapter 20

Java Utilities Package and Bit Manipulation

1193

 

 

 

84

for ( int i = 2; i < size; i++ )

 

85

 

 

 

86

 

if ( sieve.get( i ) ) {

 

87

 

primesArea.append( String.valueOf( i ) );

 

88

 

primesArea.append( ++counter % 7 == 0 ? "\n" : "\t" );

89

 

}

 

90

 

 

 

91setSize( 600, 450 );

92setVisible( true );

93}

94

95// execute application

96public static void main( String args[] )

97{

98BitSetTest application = new BitSetTest();

100 application.setDefaultCloseOperation(

101JFrame.EXIT_ON_CLOSE );

102}

103

104 } // end class BitSetTest

Fig. 20.13 Demonstrating the Sieve of Eratosthenes using a BitSet (part 3 of 3).

Line 22 creates a BitSet of 1024 bits. We ignore the bit at index 0 in this program. Lines 68–69 set all the bits in the BitSet to on with BitSet method set. Lines 72–79 determine all the prime numbers from 2 to 1023. The integer finalBit specifies when the algorithm is complete. The basic algorithm is that a number is prime if it has no divisors other than 1 and itself. Starting with the number 2, once we know a number is prime, we can eliminate all multiples of that number. The number 2 is only divisible by 1 and itself, so it is prime. Therefore, we can eliminate 4, 6, 8 and so on. Elimination of a value consists

1194

Java Utilities Package and Bit Manipulation

Chapter 20

of setting its bit to off with BitSet method clear. The number 3 is divisible by 1 and itself. Therefore, we can eliminate all multiples of 3 (keep in mind that all even numbers have already been eliminated). After the list of primes is displayed, the user can type a value from 2 to 1023 in the textfield and press enter to determine whether the number is prime. Method actionPerformed (lines 42–53) uses BitSet method get (line 46) to determine whether the bit for the number the user entered is set. If so, lines 47–48 display a message indicating that the number is prime. Otherwise, lines 51–52 display a message indicating that the number is not prime.

SUMMARY

Class Vector manages dynamically resizable arrays. At any time the Vector contains a certain number of elements which is less than or equal to its capacity. The capacity is the space that has been reserved for the array.

If a Vector needs to grow, it grows by an increment that you specify or by a default assumed by the system. If you do not specify a capacity increment, the system automatically doubles the size of the Vector each time additional capacity is required.

Vectors store references to Objects. To store values of primitive data types in Vectors, use the type-wrapper classes (Byte, Short, Integer, Long, Float, Double, Boolean and

Character) to create objects containing the primitive data type values.

Class Vector provides three constructors. The no-argument constructor creates an empty Vector. The constructor that takes one argument creates a Vector with an initial capacity specified by the argument. The constructor that takes two arguments creates a Vector with an initial capacity specified by the first argument and a capacity increment specified by the second argument.

Vector method addElement adds its argument to the end of the Vector. Method insertElementAt inserts an element at the specified position. Method setElementAt sets the element at a specific position.

Vector method removeElement removes the first occurrence of its argument. Method removeAllElements removes every element from the Vector. Method removeElementAt removes the element at the specified index.

Vector method firstElement returns a reference to the first element. Method lastElement returns a reference to the last element.

Vector method isEmpty determines whether the Vector is empty.

Vector method contains determines whether the Vector contains the searchKey specified as an argument.

Vector method indexOf gets the index of the first location of its argument. The method returns –1 if the argument is not found in the Vector.

Vector method trimToSize cuts the capacity of the Vector to the Vector’s size. Methods size and capacity determine the number of elements currently in the Vector and the number of elements that can be stored in the Vector without allocating more memory, respectively.

Vector method elements returns a reference to an Enumeration containing the elements of the Vector.

Enumeration method hasMoreElements determines whether there are more elements. Method nextElement returns a reference to the next element.

Class Stack extends class Vector. Stack method push adds its argument to the top of the stack. Method pop removes the top element of the stack. Method peek returns an Object ref-

Chapter 20

Java Utilities Package and Bit Manipulation

1195

erence to the top element of the stack without removing the element. Stack method empty determines whether the stack is empty.

A Dictionary transforms keys to values.

Hashing is a high-speed scheme for converting keys into unique array subscripts for storage and retrieval of information.The load factor is the ratio of the number of occupied cells in a hash table to the size of the hash table. The closer this ratio gets to 1.0, the greater the chance of collisions.

The no-argument Hashtable constructor creates a Hashtable with a default capacity of 101 elements and a default load factor of .75. The Hashtable constructor that takes one argument specifies the initial capacity; the constructor that takes two arguments specifies the initial capacity and load factor, respectively.

Hashtable method put adds a key and a value into a Hashtable. Method get locates the value associated with the specified key. Method remove deletes the value associated with the specified key. Method isEmpty determines whether the table is empty.

Hashtable method containsKey determines whether the key specified as an argument is in the Hashtable (i.e., a value is associated with that key). Method contains determines whether the Object specified as its argument is in the Hashtable. Method clear empties the Hashtable. Method elements obtains an Enumeration of the values. Method keys obtains an Enumeration of the keys.

A Properties object is a persistent Hashtable object. Class Properties extends Hashtable. Keys and values in a Properties object must be Strings.

The Properties no-argument constructor creates an empty Properties table with no default properties. There is also an overloaded constructor that is passed a reference to a default Properties object containing default property values.

Properties method getProperty locates the value of the key specified as an argument. Method store saves the contents of the Properties object to the OutputStream object specified as the first argument. Method load restores the contents of the Properties object from the InputStream object specified as the argument. Method propertyNames obtains an Enumeration of the property names.

Java provides extensive random-number generation capabilities in class Random. Class Random’s no-argument constructor uses the time to seed its random-number generator differently each time it is called. To create a pseudorandom-number generator with repeatability, use the Random constructor that takes a seed argument.

Random method setSeed sets the seed. Methods nextInt and nextLong generate uniformly distributed random integers. Methods nextFloat and nextDouble generate uniformly distributed values in the range 0.0 <= x < 1.0.

The bitwise AND (&) operator sets each bit in the result to 1 if the corresponding bit in both operands is 1.

The bitwise inclusive OR (|) operator sets each bit in the result to 1 if the corresponding bit in either (or both) operand(s) is 1.

The bitwise exclusive OR (^) operator sets each bit in the result to 1 if the corresponding bit in exactly one operand is 1.

The left shift (<<) operator shifts the bits of its left operand to the left by the number of bits specified in its right operand.

The right shift operator with sign extension (>>) shifts the bits in its left operand to the right by the number of bits specified in its right operand—if the left operand is negative, 1s are shifted in from the left; otherwise, 0s are shifted in from the left.

1196

Java Utilities Package and Bit Manipulation

Chapter 20

The right shift operator with zero extension (>>>) shifts the bits in its left operand to the right by the number of bits specified in its right operand—0s are shifted in from the left.

The bitwise complement (~) operator sets all 0 bits in its operand to 1 in the result and sets all 1 bits to 0 in the result.

Each bitwise operator (except complement) has a corresponding assignment operator.

The no-argument BitSet constructor creates an empty BitSet. The one-argument BitSet constructor creates a BitSet with the number of bits specified by its argument.

BitSet method set sets the specified bit “on.” Method clear sets the specified bit “off.” Method get returns true if the bit is on, false if the bit is off.

BitSet method and performs a bit-by-bit logical AND between BitSets. The result is stored in the BitSet that invoked the method. Similarly, bitwise logical OR and bitwise logical XOR are performed by methods or and xor.

BitSet method size returns the size of a BitSet. Method toString converts a BitSet to a String.

TERMINOLOGY

addElement method of class Vector and method of class BitSet

bit set

BitSet class

bitwise assignment operators &= (bitwise AND)

^= (bitwise exclusive OR) |= (bitwise inclusive OR) <<= (left shift)

>>= (right shift)

>>>= (right shift with zero extension) bitwise manipulation operators

& bitwise AND

^ bitwise exclusive OR | bitwise inclusive OR ~ one’s complement << left shift

>> right shift

>>> right shift with zero extension capacity increment of a Vector capacity method of class Vector capacity of a Vector

clear method of class BitSet clear method of class Hashtable clone method of class BitSet collision in hashing

contains method of class Vector containsKey method of class Hashtable defaults

Dictionary class dynamically resizable array

elementAt method of class Vector

elements method of class Dictionary elements method of class Vector EmptyStackException class enumerate successive elements

Enumeration interface equals method of class Object

firstElement method of class Vector get method of class BitSet

get method of class Dictionary getProperty method of class Properties hashCode method of class Object

hashing

Hashtable class

hasMoreElements method (Enumeration) indexOf method of class Vector

initial capacity of a Vector insertElementAt method of class Vector isEmpty method of class Dictionary isEmpty method of class Vector

iterate through container elements java.util package

key in a Dictionary key/value pair

keys method of class Dictionary lastElement method of class Vector list method of class Properties

load factor in hashing

load method of class Properties nextDouble method of class Random nextElement method of Enumeration nextFloat method of class Random nextInt method of class Random

Chapter 20

Java Utilities Package and Bit Manipulation

1197

nextLong method of class Random NoSuchElementException class

NullPointerException or method of class BitSet peek method of class Stack persistent hash table

pop method of class Stack Properties class

propertyNames method of Properties pseudorandom numbers

push method of class Stack

put method of class Dictionary Random class

remove method of class Dictionary removeAllElements method of Vector removeElement method of class Vector

removeElementAt method of class Vector search method of class Stack

seed of a random-number generator set method of class BitSet

setElementAt method of class Vector setSeed method of class Random setSize method of class Vector

size method of class Dictionary size method of class Vector Stack class

store method of class Properties trimToSize method of class Vector Vector class

white-space characters

xor method of class BitSet

SELF-REVIEW EXERCISES

20.1Fill in the blanks in each of the following statements:

a)

Java class

 

provides the capabilities of array-like data structures that can re-

 

size themselves dynamically.

 

 

 

 

b)

If you do not specify a capacity increment, the system will

 

the size of the

 

Vector each time additional capacity is needed.

 

 

c)

If storage is at a premium, use the

 

method of the Vector class to trim a

 

Vector to its exact size.

 

 

 

 

20.2State whether each of the following is true or false. If false, explain why.

a)Values of primitive data types may be stored directly in a Vector.

b)With hashing, as the load factor increases, the chance of collisions decreases.

20.3Under what circumstances is an EmptyStackException thrown?

20.4Fill in the blanks in each of the following statements:

a)

Bits in the result of an expression using operator

 

 

 

 

are set to 1 if the corre-

 

sponding bits in each operand are set to 1. Otherwise, the bits are set to zero.

b)

Bits in the result of an expression using operator

 

 

 

 

are set to 1 if at least one

 

of the corresponding bits in either operand is set to 1. Otherwise, the bits are set to zero.

c)

Bits in the result of an expression using operator

 

 

 

 

are set to 1 if exactly one

 

of the corresponding bits in either operand is set to 1. Otherwise, the bits are set to zero.

d)

The bitwise AND operator (&) is often used to

 

 

bits, that is, to select certain

 

bits from a bit string while zeroing others.

 

 

 

 

 

e)

The

 

 

operator is used to shift the bits of a value to the left.

f)

The

 

 

operator shifts the bits of a value to the right with sign extension, and

 

the

 

 

operator shifts the bits of a value to the right with zero extension.

ANSWERS TO SELF-REVIEW EXERCISES

20.1a) Vector. b) double. c) trimToSize.

20.2a) False; a Vector stores only Objects. A program must use the type-wrapper classes (Byte, Short, Integer, Long, Float, Double, Boolean and Character) from package java.lang to create Objects containing the primitive data type values. b) False; as the load fac-

1198

Java Utilities Package and Bit Manipulation

Chapter 20

tor increases, there are fewer available slots relative to the total number of slots, so the chance of selecting an occupied slot (a collision) with a hashing operation increases.

20.3When a program calls pop or peek on an empty Stack object, an EmptyStackException occurs.

20.4a) bitwise AND (&). b) bitwise inclusive OR (|). c) bitwise exclusive OR (^). d) mask. e) left shift operator (<<). f) right shift operator with sign extension (>>), right shift operator with zero extension (>>>).

EXERCISES

20.5Define each of the following terms in the context of hashing:

a)key

b)collision

c)hashing transformation

d)load factor

e)space–time trade-off

f)Hashtable class

g)capacity of a Hashtable

20.6Explain briefly the operation of each of the following methods of class Vector:

a)addElement

b)insertElementAt

c)setElementAt

d)removeElement

e)removeAllElements

f)removeElementAt

g)firstElement

h)lastElement

i)isEmpty

j)contains

k)indexOf

l)trimToSize

m)size

n)capacity

20.7Explain why inserting additional elements into a Vector object whose current size is less than its capacity is a relatively fast operation and why inserting additional elements into a Vector object whose current size is at capacity is a relatively slow operation.

20.8In the text, we state that the default capacity increment of doubling the size of a Vector might seem wasteful of storage, but it is actually an efficient way for Vectors to grow quickly to be “about the right size.” Explain this statement. Explain the pros and cons of this doubling algorithm. What can a program do when it determines that the doubling is wasting space?

20.9Explain the use of the Enumeration interface with objects of class Vector.

20.10By extending class Vector, Java’s designers were able to create class Stack quickly. What are the negative aspects of this use of inheritance, particularly for class Stack?

20.11Explain briefly the operation of each of the following methods of class Hashtable:

a)put

b)get

c)remove

d)isEmpty

Chapter 20

Java Utilities Package and Bit Manipulation

1199

e)containsKey

f)contains

g)clear

h)elements

i)keys

20.12Explain how to use the Random class to create pseudorandom numbers with the repeatability required for debugging purposes.

20.13Use a Hashtable to create a reusable class for choosing one of the 13 predefined colors in class Color. The name of the color should be used as keys and the predefined Color objects should be used as values. Place this class in a package that can be imported into any Java program. Use your new class in an application that allows the user to select a color and draw a shape in that color.

20.14Modify your solution to Exercise 13.18—the polymorphic painting program—to store every shape the user draws in a Vector of MyShape objects. For the purpose of this exercise, create your own Vector subclass called ShapeVector that manipulates only MyShape objects. Provide the following capabilities in your program:

a)Allow the user of the program to remove any number of shapes from the Vector by clicking an Undo button.

b)Allow the user to select any shape on the screen and move it to a new location. This requires the addition of a new method to the MyShape hierarchy. The method’s first line should be

public boolean isInside()

This method should be overridden for each subclass of MyShape to determine whether the coordinates where the user pressed the mouse button are inside the shape.

c)Allow the user to select any shape on the screen and change its color.

d)Allow the user to select any shape on the screen that can be filled or unfilled and change its fill state.

20.15What does it mean when we state that a Properties object is a “persistent” Hashtable object? Explain the operation of each of the following methods of the Properties class:

a)load

b)store

c)getProperty

d)propertyNames

e)list

20.16Why might you want to use objects of class BitSet? Explain the operation of each of the following methods of class BitSet:

a)set

b)clear

c)get

d)and

e)or

f)xor

g)size

h)equals

i)clone

j)toString

k)hashCode

20.17Write a program that right shifts an integer variable 4 bits with sign extension and then right shifts the same integer variable 4 bits with zero extension. The program should print the integer in

1200

Java Utilities Package and Bit Manipulation

Chapter 20

bits before and after each shift operation. Run your program once with a positive integer and once with a negative integer.

20.18Show how shifting an integer left by 1 can be used to simulate multiplication by 2 and how shifting an integer right by 2 can be used to simulate division by 2. Be careful to consider issues related to the sign of an integer.

20.19Write a program that reverses the order of the bits in an integer value. The program should input the value from the user and call method reverseBits to print the bits in reverse order. Print the value in bits both before and after the bits are reversed to confirm that the bits are reversed properly. You might want to implement both a recursive and an iterative solution.

20.20Modify your solution to Exercise 19.10 to use class Stack.

20.21Modify your solution to Exercise 19.12 to use class Stack.

20.22Modify your solution to Exercise 19.13 to use class Stack.