Declaring Fields

You can declare a field within a class's body by minimally specifying a type name, followed by an identifier that names the field, followed by a semicolon character (;). Listing 2-2 presents a pair of field declarations.

Listing 2-2. Declaring owner and balance fields In the CheckingAccount class class CheckingAccount {

String owner; // name of person who owns this checking account int balance; // number of dollars that can be withdrawn

Listing 2-2 declares two fields named owner and balance. By convention, a field's name begins with a lowercase letter, and the first letter of each subsequent word in a multiword field name is capitalized.

A field's type identifies the kind of values that can be assigned to the field. The owner field is of type String, which is one of Java's predefined classes. String objects contain sequences of characters; the character sequence in any String object assigned to owner will contain the name of the account's owner.

The balance field is of type integer, which is implied by reserved word int. (In common practice, we say that balance is of type int.) This field can store the account balance as a whole number without a fraction.

Integer is one of several primitive types (types whose values are not objects) that are supported by Java. Table 2-1 describes all of Java's primitive types except for void (discussed later).

Table 2-1. Primitive Types

Primitive Type

Reserved Word

Size

Min Value

Max Value

Boolean

boolean

--

--

--

Character

char

16-bit

Unicode 0

Unicode 216 - 1

Byte integer

byte

8-bit

-1 28

+127

Short integer

short

16-bit

-215

+215 - 1

Integer

int

32-bit

-231

+231 - 1

Long integer

long

64-bit

-263

+263 - 1

Floating-point

float

32-bit

IEEE 754

IEEE 754

Double precision floating-point

double

64-bit

IEEE 754

IEEE 754

Table 2-1 expresses primitive type sizes in terms of the number of bits (binary digits-each digit is either 0 or 1) that a value of that type occupies in memory. A group of eight bits is known as a byte.

Also, Unicode 0 is shorthand for "the first Unicode character," and IEEE 754 (http://en.wikipedia.org/wiki/IEEE_754) refers to a standard for representing floatingpoint numbers in memory.

Except for Boolean, whose size is implementation dependent (one Java implementation might store a Boolean value in a single bit, whereas another implementation might require an eight-bit byte for performance efficiency), each primitive type's implementation has a specific size.

NOTE: Unlike their C and C++ counterparts, Java's primitive types have the same size in each Java implementation, which partly accounts for the portability of Java applications.

Except for Boolean, whose only values are true and false, each primitive type has a minimum and a maximum value. By studying these limits, you can deduce that the character type is unsigned (all values are positive). In contrast, each numeric type is signed (the type supports positive and negative values).

NOTE: Developers who argue that everything in Java should be an object are not happy about the inclusion of primitive types in the language. However, Java was designed to include primitive types to overcome the speed and memory limitations of early 1990s-era devices, to which Java was originally targeted.

The owner and balance fields are examples of non-array fields because each field can hold only one value—an array is a multivalue variable; each array element (storage slot) holds one of these values. Java also lets you declare array-based fields, which, as Listing 2-3 reveals, are identified by the presence of square brackets ([ and ]).

Listing 2-3. Declaring cities and temperatures array-based fields In a WeatherData class class WeatherData {

String country; String[] cities; double[][]temperatures;

Listing 2-3 declares a WeatherData class that holds temperature extremes for a variety of cities in a specific country. The one-dimensional cities array contains the names of these cities; the two-dimensional temperatures array contains the maximum and minimum temperature values for each city.

A one-dimensional array is a sequential list of values; it is identified in source code by one pair of square brackets. A two-dimensional array is a table of values; it is identified in source code by two pairs of square brackets. These brackets can appear on either side of the field name, but are often shown with the type name. (Java also supports higher-dimensional arrays.)

CheckingAccount's owner and balance fields, and WeatherData's country, cities, and temperatures fields are examples of instance fields because they associate with objects. Each CheckingAccount instance is given its own copy of owner and balance when the object is created. Similarly, each WeatherData instance is given its own copy of country, cities, and temperatures when the object is created. Modifying any field's value does not affect the value in any other copy of that field.

In many situations, instance fields are all that you need. However, you might encounter a situation where you need a single copy of a field no matter how many objects are created.

For example, suppose you want to track the number of CheckingAccount objects that have been created, and introduce a counter field (initialized to 0) into this class. You also place code in the class's constructor (which I will present when I discuss constructors) to increase counter's value by 1 when an object is created. However, because each object has its own copy of the counter field, this field's value never advances past 1.

You can solve this problem by declaring counter to be a class field, a field that associates with a class instead of with that class's objects. Listing 2-4 accomplishes this task by prefixing counter's declaration with the static reserved word.

Listing 2-4. Adding a counter class field to CheckingAccount class CheckingAccount {

String owner; int balance; static int counter;

Listing 2-4's static prefix implies that there is only one copy of the counter field, not one copy per object. Each time an object is created, counter will increase by 1, and you will get an accurate tally of all CheckingAccount objects that have been created.

Each of owner and balance is created when a CheckingAccount object is created, and destroyed when the object is destroyed. In contrast, counter is created when CheckingAccount is loaded into memory, and destroyed when this class is removed from memory (when the application ends). This quality is known as lifetime.

Each of owner and balance can be accessed only from an instance context (such as a constructor). In contrast, counter can be accessed from instance and class contexts (such as a class method, discussed later in this chapter). This quality is known as scope.

Was this article helpful?

0 0

Post a comment