Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in Java
Prev Contents / Index Next

Array initialization

Initializing arrays in C is error-prone and tedious. C++ uses aggregate initialization to make it much safer.[25] Java has no “aggregates” like C++ does, since everything is an object in Java. It does have arrays, and these are supported with array initialization.

An array is simply a sequence of either objects or primitives that are all the same type and packaged together under one identifier name. Arrays are defined and used with the square-brackets indexing operator [ ]. To define an array, you simply follow your type name with empty square brackets:

int[] a1;


You can also put the square brackets after the identifier to produce exactly the same meaning:

int a1[];


This conforms to expectations from C and C++ programmers. The former style, however, is probably a more sensible syntax, since it says that the type is “an int array.” That style will be used in this book.

The compiler doesn’t allow you to tell it how big the array is. This brings us back to that issue of “references.” All that you have at this point is a reference to an array, and there’s been no space allocated for the array. To create storage for the array, you must write an initialization expression. For arrays, initialization can appear anywhere in your code, but you can also use a special kind of initialization expression that must occur at the point where the array is created. This special initialization is a set of values surrounded by curly braces. The storage allocation (the equivalent of using new) is taken care of by the compiler in this case. For example:

int[] a1 = { 1, 2, 3, 4, 5 };


So why would you ever define an array reference without an array?

int[] a2;


Well, it’s possible to assign one array to another in Java, so you can say:

a2 = a1;


What you’re really doing is copying a reference, as demonstrated here:

//: c04:Arrays.java
// Arrays of primitives.
import com.bruceeckel.simpletest.*;

public class Arrays {
  static Test monitor = new Test();
  public static void main(String[] args) {
    int[] a1 = { 1, 2, 3, 4, 5 };
    int[] a2;
    a2 = a1;
    for(int i = 0; i < a2.length; i++)
      a2[i]++;
    for(int i = 0; i < a1.length; i++)
      System.out.println(
        "a1[" + i + "] = " + a1[i]);
    monitor.expect(new String[] {
      "a1[0] = 2",
      "a1[1] = 3",
      "a1[2] = 4",
      "a1[3] = 5",
      "a1[4] = 6"
    });
  }
} ///:~


You can see that a1 is given an initialization value but a2 is not; a2 is assigned later—in this case, to another array.

There’s something new here: All arrays have an intrinsic member (whether they’re arrays of objects or arrays of primitives) that you can query—but not change—to tell you how many elements there are in the array. This member is length. Since arrays in Java, like C and C++, start counting from element zero, the largest element you can index is length - 1. If you go out of bounds, C and C++ quietly accept this and allow you to stomp all over your memory, which is the source of many infamous bugs. However, Java protects you against such problems by causing a run-time error (an exception, the subject of Chapter 9) if you step out of bounds. Of course, checking every array access costs time and code and there’s no way to turn it off, which means that array accesses might be a source of inefficiency in your program if they occur at a critical juncture. For Internet security and programmer productivity, the Java designers thought that this was a worthwhile trade-off.

What if you don’t know how many elements you’re going to need in your array while you’re writing the program? You simply use new to create the elements in the array. Here, new works even though it’s creating an array of primitives (new won’t create a nonarray primitive):

//: c04:ArrayNew.java
// Creating arrays with new.
import com.bruceeckel.simpletest.*;
import java.util.*;

public class ArrayNew {
  static Test monitor = new Test();
  static Random rand = new Random();
  public static void main(String[] args) {
    int[] a;
    a = new int[rand.nextInt(20)];
    System.out.println("length of a = " + a.length);
    for(int i = 0; i < a.length; i++)
      System.out.println("a[" + i + "] = " + a[i]);
    monitor.expect(new Object[] {
      "%% length of a = \\d+",
      new TestExpression("%% a\\[\\d+\\] = 0", a.length)
    });
  }
} ///:~


The expect( ) statement contains something new in this example: the TestExpression class. A TestExpression object takes an expression, either an ordinary string or a regular expression as shown here, and a second integer argument that indicates that the preceding expression will be repeated that many times. TestExpression not only prevents needless duplication in the code, but in this case, it allows the number of repetitions to be determined at run time.

The size of the array is chosen at random by using the Random.nextInt( ) method, which produces a value from zero to that of its argument. Because of the randomness, it’s clear that array creation is actually happening at run time. In addition, the output of this program shows that array elements of primitive types are automatically initialized to “empty” values. (For numerics and char, this is zero, and for boolean, it’s false.)

Of course, the array could also have been defined and initialized in the same statement:

int[] a = new int[rand.nextInt(20)];


This is the preferred way to do it, if you can.

If you’re dealing with an array of nonprimitive objects, you must always use new. Here, the reference issue comes up again, because what you create is an array of references. Consider the wrapper type Integer, which is a class and not a primitive:

//: c04:ArrayClassObj.java
// Creating an array of nonprimitive objects.
import com.bruceeckel.simpletest.*;
import java.util.*;

public class ArrayClassObj {
  static Test monitor = new Test();
  static Random rand = new Random();
  public static void main(String[] args) {
    Integer[] a = new Integer[rand.nextInt(20)];
    System.out.println("length of a = " + a.length);
    for(int i = 0; i < a.length; i++) {
      a[i] = new Integer(rand.nextInt(500));
      System.out.println("a[" + i + "] = " + a[i]);
    }
    monitor.expect(new Object[] {
      "%% length of a = \\d+",
      new TestExpression("%% a\\[\\d+\\] = \\d+", a.length)
    });
  }
} ///:~


Here, even after new is called to create the array:

Integer[] a = new Integer[rand.nextInt(20)];


it’s only an array of references, and not until the reference itself is initialized by creating a new Integer object is the initialization complete:

a[i] = new Integer(rand.nextInt(500));


If you forget to create the object, however, you’ll get an exception at run time when you try to use the empty array location.

Take a look at the formation of the String object inside the print statements. You can see that the reference to the Integer object is automatically converted to produce a String representing the value inside the object.

It’s also possible to initialize arrays of objects by using the curly-brace-enclosed list. There are two forms:

//: c04:ArrayInit.java
// Array initialization.

public class ArrayInit {
  public static void main(String[] args) {
    Integer[] a = {
      new Integer(1),
      new Integer(2),
      new Integer(3),
    };
    Integer[] b = new Integer[] {
      new Integer(1),
      new Integer(2),
      new Integer(3),
    };
  }
} ///:~


The first form is useful at times, but it’s more limited since the size of the array is determined at compile time. The final comma in the list of initializers is optional. (This feature makes for easier maintenance of long lists.)

The second form provides a convenient syntax to create and call methods that can produce the same effect as C’s variable argument lists (known as “varargs” in C). These can include unknown quantities of arguments as well as unknown types. Since all classes are ultimately inherited from the common root class Object (a subject you will learn more about as this book progresses), you can create a method that takes an array of Object and call it like this:

//: c04:VarArgs.java
// Using array syntax to create variable argument lists.
import com.bruceeckel.simpletest.*;

class A { int i; }

public class VarArgs {
  static Test monitor = new Test();
  static void print(Object[] x) {
    for(int i = 0; i < x.length; i++)
      System.out.println(x[i]);
  }
  public static void main(String[] args) {
    print(new Object[] {
      new Integer(47), new VarArgs(),
      new Float(3.14), new Double(11.11)
    });
    print(new Object[] {"one", "two", "three" });
    print(new Object[] {new A(), new A(), new A()});
    monitor.expect(new Object[] {
      "47",
      "%% VarArgs@\\p{XDigit}+",
      "3.14",
      "11.11",
      "one",
      "two",
      "three",
      new TestExpression("%% A@\\p{XDigit}+", 3)
    });
  }
} ///:~


You can see that print( ) takes an array of Object, then steps through the array and prints each one. The standard Java library classes produce sensible output, but the objects of the classes created here—A and VarArgs—print the class name, followed by an ‘@’ sign, and yet another regular expression construct, \p{XDigit}, which indicates a hexadecimal digit. The trailing ‘+’ means there will be one or more hexadecimal digits. Thus, the default behavior (if you don’t define a toString( ) method for your class, which will be described later in the book) is to print the class name and the address of the object.
Thinking in Java
Prev Contents / Index Next


 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire