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

Thinking in Java - 4th Edition


DisciplinaProgramação Orientada A Objetos4.283 materiais60.937 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\u2019s 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 = \u2018x\u2019; 
 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\u2019t given d an initial value and you try to use it anyway, you\u2019ll 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\u2019t 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\u2019s one thing to keep in mind, however: You aren\u2019t 
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\u2019t try to force you to initialize elements in the 
constructor at any particular place, or before they are used\u2014initialization 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\u2014even 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\u2019ll see a message: 
class Window { 
 Window(int marker) { print("Window(" + marker + ")"); } 
} 
 
class House { 
 Window w1 = new Window(1); // Before constructor 
 House() { 
 // Show that we\u2019re 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\u2019ll 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\u2014what 
would happen if an overloaded constructor were defined that did not initialize w3 and there 
wasn\u2019t a \u201cdefault\u201d initialization for w3 in its definition? 
static data initialization 
There\u2019s only a single piece of storage for a static, regardless of how many objects are created. 
You can\u2019t apply the static keyword to local variables, so it only applies to fields. If a field is a 
static primitive and you don\u2019t initialize it, it gets the standard initial value for its type. If it\u2019s 
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\u2019s 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,