Reading material

Additional material

Default initial values

Java assigns a default initial value to member variables if no initial value is specified. The Java program
class Default {
    int i;
    char c;
    boolean b;
    Object o;
 
    Default() {}
 
    public static void main(String[] args) {
        Default d = new Default();
        String s = "The default initial value of a member variable of type ";
        System.out.println(s + "int is " + d.i + ".");
        System.out.println(s + "char is " + d.c + ".");
        System.out.println(s + "boolean is " + d.b + ".");
        System.out.println(s + "Object is " + d.o + ".");
    }
}
produces the output
The default initial value of a member variable of type int is 0.
The default initial value of a member variable of type char is .
The default initial value of a member variable of type boolean is false.
The default initial value of a member variable of type Object is null.
Java does not assign any default initial value to local variables. You must initialize local variables before using them.

null is a reference to no object and null is assignable to any object reference type.

Type conversions

Java is strongly typed, which roughly means that it checks whether the type of the left hand side of an assignment is compatible with the right hand side of the assignment, and that expressions and method parameters satisfy similar compatibility requirements. For example, compilation of a class containing
boolean b = true;
int i = b;
results in the error
Conversion.java:4: Incompatible type for declaration. Can't convert boolean to int.
        int i = b;
            ^
1 error
In many cases, the type of the left hand side of an assignment is not the same as the type of the right hand side, but the latter can be converted, either implicitly or explicitly, into the former. We discuss these conversions in terms of assignments, but they also apply to expressions and method parameters.

Implicit conversions

Some kind of conversions happen automatically. These conversions are called implicit. There are two kinds of implicit conversions.

The first kind of implicit conversion applies to primitive types. Any value of a whole or real number type can be assigned to a variable the type of which supports a larger range of values. For example, the assignments

short s = 105;
int i = s;

float f = 9.1513144f;
double d = f;
are valid. A char can be used wherever an int is valid. For example,
char c = 'a';
int i = c;
Java also allows implicit conversion of whole number types to real number types, but not vice versa. For example,
int i = 6;
float f = i;

The second kind of implicit conversion is reference conversion. An object reference of one class can be used wherever an object reference of a superclass is required. For example, if class Y extends class X, then the assignment

X x = new Y();
is valid.

Explicit conversions

When one type cannot be converted implicitly to another type, often it can be converted explicitly to the other type. Explicit conversions are also called casts. A cast requests a new value of a new type that is the best available representation of the old value of the old type. For example, after the assignments
double d = 72.9;
int i = (int) d;
the value of i is 72. In the conversion, the fractional part is lost. Some casts are not allowed. For example,
boolean b = true;
int i = (int) b;
gives rise to the error
Conversion.java:4: Invalid cast from boolean to int.
int i = (int) b;
        ^
1 error
Whole number types are converted by chopping off the upper bits of their representation. For example, after the assignments
short s = -134;
byte b = (byte) s;
the value of b is 122 (recall that the range of byte is -128,...,127).

Explicit casts can also be used for reference types. Although an object of a class can be used wherever an object of a superclass is needed, the converse is generally not true. Suppose we have the following class hierarchy.

A reference of type X does not necessarily refer to an object of type Y. It might, for example, be of type Z. In many cases you cannot pass a reference of type X when a reference of type Y is expected. Such casting is called narrowing or downcasting. It is also called unsafe casting, because it is not always valid. Converting type Y into type X is called widening or upcasting. It is also called safe casting, since it is always valid. Sometimes you know that the X object is actually an instance of Y. In such a case, you can use downcasting. For example,
X x = (X) new Y(); // upcasting
Y y = (Y) x;       // downcasting
In other cases, downcasting like
X x = (X) new Z(); // upcasting
Y y = (Y) z;       // downcasting
results in the runtime error
java.lang.ClassCastException: Z
        at Y.main(Compiled Code)

The above is based on Section 5.13 of