System, but they may not be reproduced for publication



Yüklə 83 Mb.
Pdf görüntüsü
səhifə53/82
tarix19.04.2023
ölçüsü83 Mb.
#106251
1   ...   49   50   51   52   53   54   55   56   ...   82
Java A Beginner’s Guide, Eighth Edition ( PDFDrive )

auto­unboxing. Autoboxing/unboxing greatly simplifies and streamlines code that
must convert primitive types into objects, and vice versa. Because such situations are
found frequently in Java code, the benefits of autoboxing/unboxing affect nearly all
Java programmers. As you will see in 
Chapter 13
, autoboxing/unboxing also
contributes greatly to the usability of generics.
Autoboxing/unboxing is directly related to Java’s type wrappers, and to the way that
values are moved into and out of an instance of a wrapper. For this reason, we will
begin with an overview of the type wrappers and the process of manually boxing and
unboxing values.
TYPE WRAPPERS


As you know, Java uses primitive types, such as int or double, to hold the basic data
types supported by the language. Primitive types, rather than objects, are used for these
quantities for the sake of performance. Using objects for these basic types would add an
unacceptable overhead to even the simplest of calculations. Thus, the primitive types
are not part of the object hierarchy, and they do not inherit Object.
Despite the performance benefit offered by the primitive types, there are times when
you will need an object representation. For example, you can’t pass a primitive type by
reference to a method. Also, many of the standard data structures implemented by Java
operate on objects, which means that you can’t use these data structures to store
primitive types. To handle these (and other) situations, Java provides type wrappers,
which are classes that encapsulate a primitive type within an object. The type wrapper
classes were introduced briefly in 
Chapter 10
. Here, we will look at them more closely.
The type wrappers are Double, Float, Long, Integer, Short, Byte, Character, and
Boolean, which are packaged in java.lang. These classes offer a wide array of
methods that allow you to fully integrate the primitive types into Java’s object
hierarchy.
Probably the most commonly used type wrappers are those that represent numeric
values. These are Byte, Short, Integer, Long, Float, and Double. All of the numeric
type wrappers inherit the abstract class Number. Number declares methods that
return the value of an object in each of the different numeric types. These methods are
shown here:
byte byteValue( )
double doubleValue( )
float floatValue( )
int intValue( )
long longValue( )
short shortValue( )
For example, doubleValue( ) returns the value of an object as a double,
floatValue( ) returns the value as a float, and so on. These methods are implemented
by each of the numeric type wrappers.
All of the numeric type wrappers define constructors that allow an object to be


constructed from a given value, or a string representation of that value. For example,
here are the constructors defined for Integer and Double:
Integer(int num)
Integer(String str) throws NumberFormatException
Double(double num)
Double(String str) throws NumberFormatException
If str does not contain a valid numeric value, then a NumberFormatException is
thrown. However, beginning with JDK 9, the type­wrapper constructors have been
deprecated. Today, it is recommended that you use one of the valueOf( ) methods to
obtain a wrapper object. The valueOf( ) method is a static member of all of the
wrapper classes and all numeric classes support forms that convert a numeric value or a
string into an object. For example, here are two forms supported by Integer:
static Integer valueOf(int val)
static Integer valueOf(String valStr) throws NumberFormatException
Here, val specifies an integer value and valStr specifies a string that represents a
properly formatted numeric value in string form. Each returns an Integer object that
wraps the specified value. Here is an example:
After this statement executes, the value 100 is represented by an Integer instance.
Thus, iOb wraps the value 100 within an object.
All of the type wrappers override toString( ). It returns the human­readable form of
the value contained within the wrapper. This allows you to output the value by passing
a type wrapper object to println( ), for example, without having to convert it into its
primitive type.
The process of encapsulating a value within an object is called boxing. Prior to JDK 5,
all boxing took place manually, with the programmer explicitly constructing an instance
of a wrapper with the desired value, as just shown. Therefore, in the preceding example,
the value 100 is said to be boxed inside iOb.
The process of extracting a value from a type wrapper is called unboxing. Again, prior
to JDK 5, all unboxing also took place manually, with the programmer explicitly calling


a method on the wrapper to obtain its value. For example, this manually unboxes the
value in iOb into an int.
Here, intValue( ) returns the value encapsulated within iOb as an int.
The following program demonstrates the preceding concepts:
This program wraps the integer value 100 inside an Integer object called iOb. The
program then obtains this value by calling intValue( ) and stores the result in i.
Finally, it displays the values of i and iOb, both of which are 100.
The same general procedure used by the preceding example to manually box and unbox
values was required by all versions of Java prior to JDK 5 and may still be found in
legacy code. The problem is that it is both tedious and error­prone because it requires
the programmer to manually create the appropriate object to wrap a value and to
explicitly obtain the proper primitive type when its value is needed. Fortunately,
autoboxing/unboxing fundamentally improves on these essential procedures.
AUTOBOXING FUNDAMENTALS
Autoboxing is the process by which a primitive type is automatically encapsulated
(boxed) into its equivalent type wrapper whenever an object of that type is needed.
There is no need to explicitly obtain an object. Auto­unboxing is the process by which
the value of a boxed object is automatically extracted (unboxed) from a type wrapper
when its value is needed. There is no need to call a method such as intValue( ) or
doubleValue( ).
The addition of autoboxing and auto­unboxing greatly streamlines the coding of several
algorithms, removing the tedium of manually boxing and unboxing values. It also helps
prevent errors. With autoboxing it is not necessary to manually construct an object in


order to wrap a primitive type. You need only assign that value to a type­wrapper
reference. Java automatically constructs the object for you. For example, here is the
modern way to declare an Integer object that has the value 100:
Notice that the object is not explicitly boxed. Java handles this for you, automatically.
To unbox an object, simply assign that object reference to a primitive­type variable. For
example, to unbox iOb, you can use this line:
Java handles the details for you.
The following program demonstrates the preceding statements:
AUTOBOXING AND METHODS
In addition to the simple case of assignments, autoboxing automatically occurs
whenever a primitive type must be converted into an object, and auto­unboxing takes
place whenever an object must be converted into a primitive type. Thus,
autoboxing/unboxing might occur when an argument is passed to a method or when a
value is returned by a method. For example, consider the following:


This program displays the following result:
In the program, notice that m( ) specifies an Integer parameter. Inside main( ), m( )


is passed the int value 199. Because m( ) is expecting an Integer, this value is
automatically boxed. Next, m2( ) is called. It returns the int value 10. This int value is
assigned to iOb in main( ). Because iOb is an Integer, the value returned by m2( ) is
autoboxed. Next, m3( ) is called. It returns an Integer that is auto­unboxed into an
int. Finally, Math.sqrt( ) is called with iOb as an argument. In this case, iOb is auto­
unboxed and its value promoted to double, since that is the type expected by
Math.sqrt( ).
AUTOBOXING/UNBOXING OCCURS IN
EXPRESSIONS
In general, autoboxing and unboxing take place whenever a conversion into an object
or from an object is required. This applies to expressions. Within an expression, a
numeric object is automatically unboxed. The outcome of the expression is reboxed, if
necessary. For example, consider the following program:


The output is shown here:
In the program, pay special attention to this line:
This causes the value in iOb to be incremented. It works like this: iOb is unboxed, the
value is incremented, and the result is reboxed.
Because of auto­unboxing, you can use integer numeric objects, such as an Integer, to
control a switch statement. For example, consider this fragment:
When the switch expression is evaluated, iOb is unboxed and its int value is obtained.
As the examples in the program show, because of autoboxing/unboxing, using numeric
objects in an expression is both intuitive and easy. With early versions of Java, such
code would have involved casts and calls to methods such as intValue( ).
A Word of Warning
Because of autoboxing and auto­unboxing, one might be tempted to use objects such as
Integer or Double exclusively, abandoning primitives altogether. For example, with
autoboxing/unboxing it is possible to write code like this:


In this example, objects of type Double hold values, which are then averaged and the
result assigned to another Double object. Although this code is technically correct and
does, in fact, work properly, it is a very bad use of autoboxing/unboxing. It is far less
efficient than the equivalent code written using the primitive type double. The reason
is that each autobox and auto­unbox adds overhead that is not present if the primitive
type is used.
In general, you should restrict your use of the type wrappers to only those cases in
which an object representation of a primitive type is required. Autoboxing/unboxing
was not added to Java as a “back door” way of eliminating the primitive types.
STATIC IMPORT
Java supports an expanded use of the import keyword. By following import with the
keyword static, an import statement can be used to import the static members of a
class or interface. This is called static import. When using static import, it is possible to
refer to static members directly by their names, without having to qualify them with the
name of their class. This simplifies and shortens the syntax required to use a static
member.
To understand the usefulness of static import, let’s begin with an example that does not
use it. The following program computes the solutions to a quadratic equation, which
has this form:

Yüklə 83 Mb.

Dostları ilə paylaş:
1   ...   49   50   51   52   53   54   55   56   ...   82




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə