Thinking in Java - 4th Edition
1079 pág.

Thinking in Java - 4th Edition

Disciplina:Programação Orientada a Objetos1.257 materiais32.010 seguidores
Pré-visualização50 páginas
*/
 }
} /* Output:
Data type Initial value

Initialization & Cleanup 125 

boolean false
char [ ]
byte 0
short 0
int 0
long 0
float 0.0
double 0.0
reference null
*///:~

You can see that even though the values are not specified, they automatically get initialized
(the char value is a zero, which prints as a space). So at least there’s no threat of working
with uninitialized variables.

When you define an object reference inside a class without initializing it to a new object, that
reference is given a special value of null.

Specifying initialization

What happens if you want to give a variable an initial value? One direct way to do this is
simply to assign the value at the point you define the variable in the class. (Notice you cannot
do this in C++, although C++ novices always try.) Here the field definitions in class
InitialValues are changed to provide initial values:

//: initialization/InitialValues2.java
// Providing explicit initial values.
public class InitialValues2 {
 boolean bool = true;
 char ch = ‘x’;
 byte b = 47;
 short s = 0xff;
 int i = 999;
 long lng = 1;
 float f = 3.14f;
 double d = 3.14159;
} ///:~

You can also initialize non-primitive objects in this same way. If Depth is a class, you can
create a variable and initialize it like so:

//: initialization/Measurement.java
class Depth {}
public class Measurement {
 Depth d = new Depth();
 // ...
} ///:~

If you haven’t given d an initial value and you try to use it anyway, you’ll get a runtime error
called an exception (covered in the Error Handling with Exceptions chapter).

You can even call a method to provide an initialization value:

//: initialization/MethodInit.java
public class MethodInit {
 int i = f();
 int f() { return 11; }

126 Thinking in Java Bruce Eckel

} ///:~

This method can have arguments, of course, but those arguments cannot be other class
members that haven’t been initialized yet. Thus, you can do this:

//: initialization/MethodInit2.java
public class MethodInit2 {
 int i = f();
 int j = g(i);
 int f() { return 11; }
 int g(int n) { return n * 10; }
} ///:~

But you cannot do this:

//: initialization/MethodInit3.java
public class MethodInit3 {
 //! int j = g(i); // Illegal forward reference
 int i = f();
 int f() { return 11; }
 int g(int n) { return n * 10; }
} ///:~

This is one place in which the compiler, appropriately, does complain about forward
referencing, since this has to do with the order of initialization and not the way the program
is compiled.

This approach to initialization is simple and straightforward. It has the limitation that every
object of type InitialValues will get these same initialization values. Sometimes this is
exactly what you need, but at other times you need more flexibility.

Constructor initialization
The constructor can be used to perform initialization, and this gives you greater flexibility in
your programming because you can call methods and perform actions at run time to
determine the initial values. There’s one thing to keep in mind, however: You aren’t
precluding the automatic initialization, which happens before the constructor is entered. So,
for example, if you say:

//: initialization/Counter.java
public class Counter {
 int i;
 Counter() { i = 7; }
 // ...
} ///:~

then i will first be initialized to 0, then to 7. This is true with all the primitive types and with
object references, including those that are given explicit initialization at the point of
definition. For this reason, the compiler doesn’t try to force you to initialize elements in the
constructor at any particular place, or before they are used—initialization is already
guaranteed.

Order of initialization

Within a class, the order of initialization is determined by the order that the variables are
defined within the class. The variable definitions may be scattered throughout and in

Initialization & Cleanup 127 

between method definitions, but the variables are initialized before any methods can be
called—even the constructor. For example:

//: initialization/OrderOfInitialization.java
// Demonstrates initialization order.
import static net.mindview.util.Print.*;
// When the constructor is called to create a
// Window object, you’ll see a message:
class Window {
 Window(int marker) { print("Window(" + marker + ")"); }
}
class House {
 Window w1 = new Window(1); // Before constructor
 House() {
 // Show that we’re in the constructor:
 print("House()");
 w3 = new Window(33); // Reinitialize w3
 }
 Window w2 = new Window(2); // After constructor
 void f() { print("f()"); }
 Window w3 = new Window(3); // At end
}
public class OrderOfInitialization {
 public static void main(String[] args) {
 House h = new House();
 h.f(); // Shows that construction is done
 }
} /* Output:
Window(1)
Window(2)
Window(3)
House()
Window(33)
f()
*///:~

In House, the definitions of the Window objects are intentionally scattered about to prove
that they’ll all get initialized before the constructor is entered or anything else can happen. In
addition, w3 is reinitialized inside the constructor.

From the output, you can see that the w3 reference gets initialized twice: once before and
once during the constructor call. (The first object is dropped, so it can be garbage collected
later.) This might not seem efficient at first, but it guarantees proper initialization—what
would happen if an overloaded constructor were defined that did not initialize w3 and there
wasn’t a “default” initialization for w3 in its definition?

static data initialization

There’s only a single piece of storage for a static, regardless of how many objects are created.
You can’t apply the static keyword to local variables, so it only applies to fields. If a field is a
static primitive and you don’t initialize it, it gets the standard initial value for its type. If it’s
a reference to an object, the default initialization value is null.

If you want to place initialization at the point of definition, it looks the same as for non-
statics.

128 Thinking in Java Bruce Eckel

To see when the static storage gets initialized, here’s an example:

//: initialization/StaticInitialization.java
// Specifying initial values in a class definition.
import static net.mindview.util.Print.*;
class Bowl {
 Bowl(int marker) {
 print("Bowl(" + marker + ")");
 }
 void f1(int marker) {
 print("f1(" + marker + ")");
 }
}
class Table {
 static Bowl bowl1 = new Bowl(1);
 Table() {
 print("Table()");
 bowl2.f1(1);
 }
 void f2(int marker) {
 print("f2(" + marker + ")");
 }
 static Bowl bowl2 = new Bowl(2);
}
class Cupboard {
 Bowl bowl3 = new Bowl(3);
 static Bowl bowl4 = new Bowl(4);
 Cupboard() {
 print("Cupboard()");
 bowl4.f1(2);
 }
 void f3(int marker) {
 print("f3(" + marker + ")");
 }
 static Bowl bowl5 = new Bowl(5);
}
public class StaticInitialization {
 public static void main(String[] args) {
 print("Creating new Cupboard() in main");
 new Cupboard();
 print("Creating new Cupboard() in main");
 new Cupboard();
 table.f2(1);
 cupboard.f3(1);
 }
 static Table table = new Table();
 static Cupboard cupboard = new Cupboard();
} /* Output:
Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)

Initialization & Cleanup 129 

Cupboard()
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard()
f1(2)
f2(1)
f3(1)
*///:~

Bowl allows you to view the creation of a class, and Table and Cupboard have static
members of Bowl scattered through their class definitions. Note that Cupboard creates a
non-static Bowl bowl3 prior to the static definitions.

From the output,