Chapter 3. Fundamental Types

Fundamental types include the Java primitive types and their corresponding wrapper classes/reference types. There is provision for automatic conversion between these primitive and reference types through autoboxing and unboxing. Numeric promotion is applied to primitive types where appropriate.

Primitive Types

There are eight primitive types in Java: each is a reserved keyword. They describe variables that contain single values of the appropriate format and size (see Table 3-1). Primitive types are always the specified precision, regardless of the underlying hardware precisions (e.g., 32- or 64-bit).

Table 3-1. Primitive types
Type Detail Storage Range

boolean

true or false

1 bit

Not applicable

char

Unicode character

2 bytes

u0000 to uFFFF

byte

Integer

1 byte

–128 to 127

short

Integer

2 bytes

–32768 to 32767

int

Integer

4 bytes

–2147483648 to 2147483647

long

Integer

8 bytes

–263 to 263 –1

float

Floating point

4 bytes

1.4e–45 to 3.4e+38

double

Floating point

8 bytes

5e–324 to 1.8e+308

Tip

Primitive types byte, short, int, long, float, and double are all signed. Type char is unsigned.

Literals for Primitive Types

All primitive types except boolean can accept character, decimal, hexadecimal, octal, and Unicode literal formats, as well as character escape sequences. Where appropriate, the literal value is automatically cast or converted. Remember that bits are lost during truncation. The following is a list of primitive assignment examples.

The boolean primitive’s only valid literal values are true and false:

boolean isEndogamous = true;

The char primitive represents a single Unicode character. Literal values of the char primitive that are greater than two bytes need to be explicitly cast.

// 'atDNA'
  char[] cArray = {
  ''', // '
  'u0061', // a
  't', // t
  0x0044, // D
  0116, // N
  (char) (65 + 131072) , // A
  0b00100111}; // '

The byte primitive has a four-byte signed integer as its valid literal. If an explicit cast is not performed, the integer is implicitly cast to one byte:

final byte CHROMOSOME_PAIRS = 12;
final byte CHROMOSOME_TOTAL = (byte) 48;

The short primitive has a four-byte signed integer as its valid literal. If an explicit cast is not performed, the integer is implicitly cast to two bytes:

short firstCousins = 6;
short secondCousins = (short) 18;

The int primitive has a four-byte signed integer as its valid literal. When char, byte, and short primitives are used as literals, they are automatically cast to four-byte integers, as in the case of the short value within vipSeats. Floating-point and long literals must be explicitly cast:

int thirdCousins = 104;
int forthCousins = (int) 648.0D;
int fifthCousins = (short) 3_888;

The long primitive has an eight-byte signed integer as its valid literal. It is designated by an L or l postfix. The value is cast from four bytes to eight bytes when no postfix or cast is applied:

long sixthCousins = 23_000;
long seventhCousins = (long) 138_000;
long eighthCousins = 828_000l;
long ninthCousins = 4_968_000L;

The float primitive has a four-byte signed floating point as its valid literal. An F or f postfix or an explicit cast designates it. Even though no explicit cast is necessary for an int literal, an int will not always fit into a float where the value exceeds about 223:

float totalSharedCentimorgansX = 0;
float totalSharedCentimorgansAutosomal = (float) 285.5;
float largestSharedCentimorgansX = 0.0f;
float largestSharedCentimorgansAutosomal = 71F;

The double primitive uses an eight-byte signed floating-point value as its valid literal. The literal can have a D, d, or explicit cast with no postfix. If the literal is an integer, it is implicitly cast:

double centimorgansSharedFloor = 0;
double centimorgansSharedCeiling = 6766.20;
double centimorgansShared = (double) 888;
double centimorgansUnShared = 5878.0d;
double centimorgansPercentShared = 13.12D;

See Chapter 2 for more details on literals.

Floating-Point Entities

Positive and negative floating-point infinities, negative zero, and not a number (NaN) are special entities defined to meet the IEEE 754-1985 standard (see Table 3-2).

The Infinity, –Infinity, and –0.0 entities are returned when an operation creates a floating-point value that is too large to be traditionally represented.

Table 3-2. Floating-point entities
Entity Description Examples

Infinity

Represents the concept of positive infinity

1.0 / 0.0, 1e300 / 1e–300, Math.abs (–1.0 / 0.0)

–Infinity

Represents the concept of negative infinity

–1.0 / 0.0, 1.0 / (–0.0), 1e300/–1e–300

–0.0

Represents a negative number close to zero

–1.0 / (1.0 / 0.0), –1e–300 / 1e300

NaN

Represents undefined results

0.0 / 0.0, 1e300 * Float.NaN, Math.sqrt (–9.0)

Positive infinity, negative infinity, and NaN entities are available as double and float constants:

Double.POSITIVE_INFINITY; // Infinity
Float.POSITIVE_INFINITY;  // Infinity
Double.NEGATIVE_INFINITY; // –Infinity
Float.NEGATIVE_INFINITY;  // –Infinity
Double.NaN; // Not-a-Number
Float.NaN;  // Not-a-Number

The Double and Float wrapper classes have methods to determine if a number is finite, infinite, or NaN:

Double.isFinite(Double.POSITIVE_INFINITY); // false
Double.isFinite(Double.NEGATIVE_INFINITY); // false
Double.isFinite(Double.NaN); // false
Double.isFinite(1); // true
// true
Double.isInfinite(Double.POSITIVE_INFINITY);
// true
Double.isInfinite(Double.NEGATIVE_INFINITY);
Double.isInfinite(Double.NaN); // false
Double.isInfinite(1); // false
Double.isNaN(Double.NaN); // true
Double.isNaN(1); // false

Operations Involving Special Entities

Table 3-3 shows the results of special entity operations where the operands are abbreviated as INF for Double.POSITIVE_INFINITY, –INF for Double.NEGATIVE_INFINITY, and NAN for Double.NaN.

For example, column 4’s heading entry (–0.0) and row 12’s entry (* NAN) have a result of NaN, and could be written as follows:

// 'NaN' will be printed
System.out.print((-0.0) * Double.NaN);
Table 3-3. Operations involving special entities
INF (–INF) (–0.0)

* INF

Infinity

–Infinity

NaN

+ INF

Infinity

NaN

Infinity

– INF

NaN

–Infinity

–Infinity

/ INF

NaN

NaN

–0.0

* 0.0

NaN

NaN

–0.0

+ 0.0

Infinity

–Infinity

0.0

+ 0.5

Infinity

–Infinity

0.5

* 0.5

Infinity

–Infinity

–0.0

+ (–0.5)

Infinity

–Infinity

–0.5

* (–0.5)

–Infinity

Infinity

0.0

+ NAN

NaN

NaN

NaN

* NAN

NaN

NaN

NaN

Tip

Any operation performed on NaN results in NaN; there is no such thing as –NaN.

Numeric Promotion of Primitive Types

Numeric promotion consists of rules that are applied to the operands of an arithmetic operator under certain conditions. Numeric promotion rules consist of both unary and binary promotion rules.

Unary Numeric Promotion

When a primitive of a numeric type is part of an expression, as listed in Table 3-4, the following promotion rules are applied:

  • If the operand is of type byte, short, or char, the type will be promoted to type int.

  • Otherwise, the type of the operand remains unchanged.

Table 3-4. Expression for unary promotion rules
Expression

Operand of a unary plus operator

Operand of a unary minus operator –

Operand of a bitwise complement operator ~

All shift operators >>, >>>, or <<

Index expression in an array access expression

Dimension expression in an array creation expression

Binary Numeric Promotion

When two primitives of different numerical types are compared via the operators listed in Table 3-5, one type is promoted based on the following binary promotion rules:

  • If either operand is of type double, the non-double primitive is converted to type double.

  • If either operand is of type float, the non-float primitive is converted to type float.

  • If either operand is of type long, the non-long primitive is converted to type long.

  • Otherwise, both operands are converted to int.

Table 3-5. Operators for binary promotion rules
Operators Description

+ and –

Additive operators

*, /, and %

Multiplicative operators

<, <=, >, and >=

Comparison operators

== and !=

Equality operators

&, ^, and |

Bitwise operators

? :

Conditional operator (see next section)

Special Cases for Conditional Operators

  • If one operand is of type byte and the other is of type short, the conditional expression will be of type short:

    short = true ? byte : short
  • If one operand R is of type byte, short, or char, and the other is a constant expression of type int whose value is within range of R, the conditional expression is of type R:

    short = (true ? short : 1967)
  • Otherwise, binary numeric promotion is applied, and the conditional expression type will be that of the promoted type of the second and third operands.

Wrapper Classes

Each of the primitive types has a corresponding wrapper class/reference type, which is located in package java.lang. Each wrapper class has a variety of methods, including one to return the type’s value, as shown in Table 3-6. These integer and floating-point wrapper classes can return values of several primitive types.

Table 3-6. Wrapper classes
Primitive types Reference types Methods to get primitive values

boolean

Boolean

booleanValue()

char

Character

charValue()

byte

Byte

byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()

short

Short

byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()

int

Integer

byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()

long

Long

byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()

float

Float

byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()

double

Double

byteValue(), shortValue(), intValue(), longValue(), floatValue(), doubleValue()

Autoboxing and Unboxing

Autoboxing and unboxing are typically used for collections of primitives. Autoboxing involves the dynamic allocation of memory and the initialization of an object for each primitive. Note that the overhead can often exceed the execution time of the desired operation. Unboxing involves the production of a primitive for each object.

Computationally intensive tasks using primitives (e.g., iterating through primitives in a container) should be done using arrays of primitives instead of collections of wrapper objects.

Autoboxing

Autoboxing is the automatic conversion of primitive types to their corresponding wrapper classes. In this example, the diploid chromosome number for each species (e.g., 60, 46, and 38) are automatically converted to their corresponding wrappers class because collections store references, not primitive values:

// Create hash map of weight groups
HashMap<String, Integer> diploidChromosomeNumberMap
    = new HashMap<String, Integer> ();
diploidChromosomeNumberMap.put("Canis latrans", 78);
diploidChromosomeNumberMap.put("Bison bison", 60);
diploidChromosomeNumberMap.put("Homo sapiens", 46);
diploidChromosomeNumberMap.put("Sus scrofa", 38);
diploidChromosomeNumberMap.put("Myrmecia pilosula", 2);

The following example shows an acceptable but not recommended use of autoboxing:

// Set number of autosomal (atDNA) chromosomes
Integer atDnaChromosomeSet = 22; //improper

As there is no reason to force autoboxing, the preceding statement should instead be written as follows:

Integer atDnaChromosomeSet = Integer.valueOf(22);

Unboxing

Unboxing is the automatic conversion of the wrapper classes to their corresponding primitive types. In this example, a reference type is retrieved from the hash map. It is automatically unboxed so that it can fit into the primitive type:

// Get the DCN of a homo sapien, performing unboxing
int homoSapienDcn = diploidChromosomeNumberMap.get("Homo sapiens");

System.out.println(homoSapienDcn);
$ 46

The following example shows an acceptable but not recommended use of unboxing:

// Establish the total number of chromosomes
Integer atDnaChromosomeSet = 22;
int multiplier = 2;
int xChromosomes = 2; // 1 or 2
int yChromosome = 0;  // 0 or 1
// Mixing int and Integer; not recommended
int dcn = xChromosomes + yChromosome
  + (multiplier * atDnaChromosomeSet);

It is better to write this expression with the intValue() method, as shown here:

int dcn = xChromosomes + yChromosome
  + (multiplier * atDnaChromosomeSet.intValue());
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset