home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Java Language Reference

Previous Chapter 4
Expressions
Next
 

4.2 Allocation Expressions

An allocation expression is a primary expression that creates an object or an array. An allocation expression also produces a reference to the newly created object or array:

[Graphic: Figure from the text]

[Graphic: Figure from the text]

When AllocationExpression contains parentheses, the allocation expression creates a non-array object. When AllocationExpression contains square brackets, the allocation expression creates an array.

An object created by an allocation expression continues to exist until the program terminates or it is freed by the garbage collector (see Object Destruction). Consider the following code:

class X {
    Double perm;
    void foo() {
        Double d = new Double(8.9473);
        int a[] = new int [2];
        d = new Double(3.1415926);
        a[0] = d.intValue();
        perm = d;
    }
}

The first line of foo() creates a Double object and uses it as the initial value of the variable d. The second line creates an array of integers and uses it as the initial value of the variable a. At this point, neither of the two objects that has been created is a candidate for garbage collection because there is a variable referencing each of them.

The third line of foo creates another Double object and assigns it to the variable d. Now there is nothing that refers to the first Double object that we created, so that object can now be garbage collected at any time.

When the block in this example finishes executing, the variables declared inside of the block, a and d, pass out of scope. Now there is nothing referring to the array object that we created; now that object can be garbage-collected at any time. However, because the variable perm now refers to the second Double object we created, that object is not a candidate for garbage collection.

References ArgumentList 4.1.8; ClassBody 5.4; Variable initializers; Expression 4; Identifiers; Object Creation; Object Destruction; Primary Expressions; Type 3

Object Allocation Expressions

An allocation expression that contains parentheses creates a non-array object; that is, an instance of a class. For example:

new Double(93.1872)

The Type in an object allocation expression must be a class or interface type. The argument list supplied between the parentheses provides the actual arguments to be passed to the object's constructor. However, if a ClassBody follows the parentheses, no arguments may appear between the parentheses, and different rules apply. (These rules are discussed in Allocating instances of anonymous classes.)

If new is preceded by a PrimaryExpression and a dot, the PrimaryExpression must produce a reference to an object. Furthermore, the object's class must be an inner or nested top-level class that is named by the identifier that follows new. If the specified class is a non-static inner class, the object created by the allocation expression has the object referenced by the PrimaryExpression as its enclosing instance. For example:

class Z {
    class Y {
    ...
    } 
    public static void main(String[] argv) {
        Z myZ = new Z();
        Z.Y myY = myZ.new Y();
    } 
} 

In the preceding example, we must supply an explicit enclosing instance of Z to create a Z.Y object because main() is a static method. A non-static method of Z could create an instance of Z.Y without supplying an explicit enclosing instance of Z because the method itself is associated with an instance of Z. However, because a static method is not associated with an instance of its class, it must supply an explicit enclosing instance when creating an instance of an inner class.

The syntax that allows new to be preceded by a PrimaryExpression and a dot is not supported prior to Java 1.1.

The remainder of this section applies only to allocation expressions that contain parentheses but no ClassBody. Allocation expressions that contain a ClassBody are described in Allocating instances of anonymous classes.

An object allocation expression performs the following steps:

  1. Creates a new object with all of its instance variables set to their default values. The default values for these variables are determined by their types.

  2. Calls the constructor that matches the given argument list.

  3. Produces a reference to the initialized object.

The process of selecting the appropriate constructor to call is similar to the process used to select the method invoked by a method call expression. The compiler determines which constructors have formal parameters compatible with the given arguments. If there is more than one suitable constructor, the compiler must select the constructor that most closely matches the given arguments. If the compiler cannot select one constructor as a better match than the others, the constructor selection process fails and an error message is issued.

Here are the details of the constructor selection process:

Step One

The constructor definitions are searched for constructors that, taken in isolation, could be called by the allocation expression. A constructor is a candidate if it meets the following criteria:

  • The constructor is accessible to the allocation expression, based on any access modifiers specified in the constructor's declaration.

  • The number of formal parameters declared for the constructor is the same as the number of actual arguments provided in the allocation expression.

  • The data type of each actual parameter is assignment-compatible with the corresponding formal parameter.

Step Two

If more than one constructor meets the criteria in Step One, the Java compiler tries to determine if one constructor is a more specific match than the others. If there is no constructor that matches more specifically, the constructor selection process fails and an error message is issued.

Given two constructors that are both candidates to be invoked by the same object allocation expression, one constructor is more specific than another constructor if each parameter of the first constructor is assignment-compatible with the corresponding parameter of the second constructor.

When an object allocation expression is evaluated, the constructor selected in Step Two is invoked. This constructor returns a reference to the newly created object.

Here's an example that shows how the constructor selection process works:

class Consel {
    Consel() { }
    Consel(Object o, double d) {}
    Consel(String s, int i) {}
    Consel(int i, int j) {}
    public void main(String[] argv) {
        Consel c = new Consel("abc",4);
    }
}

The main() method in the Consel class creates a new Consel object. The process of selecting which constructor to call proceeds as follows:

  1. The compiler finds all of the constructors that are accessible to the new operator. Since all of the constructors are accessible, the compiler then narrows its choices to those constructors that have the same number of formal parameters as the number of actual arguments in the allocation expression. This step eliminates the constructor with no formal parameters, so now there are three choices. The compiler again narrows its choices to those constructors with formal parameters that are assignment-compatible with the actual values. Because a String is not assignment-compatible with an int variable, the compiler eliminates the constructor that takes two int parameters.

  2. Now the compiler must choose which of the two remaining constructors is more specific than the other. Because a String object reference can be assigned to an Object variable and an int value can be assigned to a double variable, the constructor Consel(String s, int i) is the more specific of the two. This constructor is the one that is invoked to create the Consel object.

References Allocating instances of anonymous classes; Assignment Compatibility; ClassBody 5.4; Class Types; Constructors; Interface Types; Primary Expressions

Allocating instances of anonymous classes

An allocation expression that contains a ClassBody creates an instance of an anonymous class. It is called an anonymous class because it has no name of its own. The variables and methods of an anonymous class are defined in the ClassBody. If the type specified after new is a class, the anonymous class is a subclass of that class. If the type specified after new is an interface, the anonymous class implements that interface and is a subclass of Object. For example:

public class MainFrame extends Frame {
...
    public MainFrame(String title) {
        super(title);
        WindowAdapter listener;
        listener = new WindowAdapter() {
            public void windowClosing(WindowEvent evt) {
                exit();
            } 
        };
        addWindowListener(listener);
    } 
...
} 

The example creates an instance of an anonymous subclass of the WindowAdapter class. If an allocation expression contains a ClassBody, it cannot contain any arguments between the parentheses because an anonymous class cannot declare any constructors. Instead, an anonymous class must use instance initializers to handle any complex initialization.

The body of an anonymous class cannot declare any static variables, static methods, static classes, or static initializers. Anonymous classes are not supported prior to Java 1.1.

References Anonymous classes; ClassBody 5.4; Constructors; Instance Initializers; Methods; Nested Top-Level and Member Classes; Static Initializers; Variables

Array Allocation Expressions

An allocation expression that contains square brackets creates an array, such as:

new int[10]

An array allocation expression performs the following steps:

  1. Allocates storage for the array

  2. Sets the length variable of the array and initializes the array elements to their default values

  3. Produces a reference to the initialized array

Although Java does not support multi-dimensional arrays, it does support arrays of arrays. The most important distinction between a multi-dimensional array and an array of arrays is that in an array of arrays, each array need not be of the same length. Because arrays of arrays are most often used to represent multi-dimensional arrays, this book refers to them as multi-dimensional arrays, even though that is not precisely correct.

The type of the array created by an array allocation expression can be expressed by removing both the word new and the expressions from within the square brackets. For example, here is an allocation expression:

new int[3][4][5]

The type of the array produced by that expression is:

int[][][]

This means that the number of dimensions in the array produced by an allocation expression is the same as the number of pairs of square brackets in the allocation expression.

The expressions that appear in the square brackets must be of type int, short, char, or byte. Each of the expressions specifies the length of a single dimension of the array that is being created. For example, the allocation expression above creates an array of 3 arrays of 4 arrays of 5 int values. The length supplied for an array must not be negative. At runtime, if an expression in square brackets produces a negative array length, a NegativeArraySizeException is thrown.

The syntax of an array allocation expression specifies that the first pair of square brackets must contain an expression, while the trailing square brackets do not need to. This means that an array allocation expression can be written to build fewer dimensions of an array than there are dimensions in the array's type. For example, consider this allocation expression:

new char [10][]

The array produced by this allocation expression is an array of arrays of char. The allocation expression creates a single array of 10 elements, where each of those elements is a char array of unspecified length.

Array allocation expressions are often used to initialize array variables. Here are some examples:

int j[] = new int[10];          // array of 10 ints
ing k[][] = new float[3][4];    // array of 3 arrays
                                // of 4 floats

Here's an example that builds an array of different length arrays, or in other words a non-rectangular array of arrays:

int a[][] = new int [3][];
a[0] = new int [5];
a[1] = new int [6];
a[2] = new int [7];

None of the array allocation expressions presented so far have used array initializers. When an array allocation expression does not include an array initializer, the array is created with all of its elements set to a default value. The default value is based on the type of the array. Table 4-1 shows the default values used for the various types in Java.

Table 4.1: Default Values for Array Elements

Array Type

Default Value

byte

0

char

'\u0000'

short

0

int

0

long

0L

float

0.0F

double

0.0

Boolean

false

Object reference

null

If you want to create an array that contains elements with different initial values, you can include an ArrayInitializer at the end of the allocation expression. For example:

new int [] { 4,7,9 }

Notice that there is no expression between the square brackets. If an allocation expression contains square brackets and no ArrayInitializer, at least the first pair of square brackets must contain an expression. However, if an allocation expression does contain an ArrayInitializer, there cannot be any expressions between any of the square brackets. An allocation expression that contains an ArrayInitializer can be used to create an anonymous array: one that is created and initialized without using a variable initializer.

The syntax that allows an ArrayInitializer in an allocation expression is not supported prior to Java 1.1.

References Array Types; Variable initializers; Index Expressions


Previous Home Next
Primary Expressions Book Index Increment/Decrement Operators

Java in a Nutshell Java Language Reference Java AWT Java Fundamental Classes Exploring Java