Section 5 : Operators and Assignments
Determine the result of applying
any operator, including assignment operators,
instanceof, and casts to operands of any type, class,
scope, or accessibility, or any combination of these.
Converting and Casting
Automatic, non-explicit (done by compiler or Java)
type changing is known as conversion. On the other
hand explicitly changing the type of a value is called
casting. Both are governed by certain rules.
Primitives and conversion
All
conversion of primitive data type takes place at
compile time. This is because all the information,
needed to determine whether or not conversion is
legal, is available at compile time.
Assignment
Assignment conversion happens when you assign a value
to a variable of a different type from the original
value. The general rules are:
-
A boolean
may not be converted to any other type.
-
A non boolean
may be converted to another non
boolean type, provided
the conversion is a widening conversion.
-
A non boolean
may not be converted to another non
boolean type, if the
conversion is narrowing.
You
cannot convert a byte to
a char or a
char to a
short, even though it
seems reasonable to do so.
Method call:
Another kind of conversion is method-call-conversion.
This happens when you pass a value of one type as an
argument to a method that expects a different type.
Here too, widening conversions are permitted, not
narrowing.
Arithmetic
promotion:
These
too, are widening conversions.
Unary
operators:
-
If the operand is a
byte, a
short or a
char, it is converted
to an int.
-
If the operand is of any other type,
it is not converted.
Binary operators:
-
If one of the operands is
double, the other
operand is converted to a
double.
-
Else if one of the operand is a
float, the other operand is converted to a float.
-
Else if one of the operand is
long, the other operand
is converted to a long.
-
Else both operands are converted to
int.
Primitives and casting
Casting
means explicitly telling Java to make a conversion. A
casting may widen or narrow its argument. But casting
is required when you want to perform a narrowing
conversion.
Narrowing runs the risk of losing information; the
cast tells the compiler that you accept the risk.
During casting the lower order bits are preserved and
higher order bits are discarded depending on the
operands. The rules are:
Note
that while casting is ordinarily used when narrowing,
it is perfectly legal to cast when widening. The cast
is unnecessary, but provides clarity.
*** if
you cast a negative number to a char, ? is printed in
S.o.p(); also any number less than 0 and greater than
255 gives the same output.
Object reference conversion
Reference conversion, like primitive conversion, takes
place at compile time, because the compiler has all
the information it needs to determine whether the
conversion is legal.
Object reference assignment conversion:
There
are generally three kinds of object reference type:
-
A
class type
-
An
interface type
-
An
array type
Assignment conversion looks like this:
OldType
x = new OldType();
NewType
y = x; // reference assignment conversion.
In
general, object reference conversion is permitted when
the direction of the conversion is ‘up’ the
inheritance hierarchy; that is old type should inherit
from the new type. The rules are:
-
An
interface type may only
be converted to an interface
type or to Object. If the new type is an
interface, it must be a
super interface of the
old type.
-
A
class type may be converted to a class type or to an
interface type. If
converting to a class type, the new type must be a
superclass of the old type. If converting to an
interface type, the old
type must implement the
interface.
-
An
array may be converted to the class Object, to the
interface Cloneable, or
to an array. Only an array of object reference types
may be converted to an array, and the old element
type must be convertible to the new element type.
|
OldType is
a class |
OldType is
an interface |
OldType is
an array |
NewType is a class
|
OldType must
be a subclass of NewType. |
NewType must
be Object |
NewType must
be Object |
NewType is
an interface |
OldType must
implement interface NewType |
OldType must
be a sub-interface of NewType |
NewType must
be Cloneable/Serializable |
NewType is
an array |
Compiler
Error |
Compiler
Error |
OldType must
be an array of some object reference type that can
be converted to whatever NewType is an array of. |
Object method call conversion:
Rules
are same as above.
To see
how the rules make sense in the context of method
calls, consider the extremely useful Vector class. You
can store anything you like in a Vector (anything
non-primitive) by calling the method
addObject (Object ob);
whatever
you pass to the above method, will be converted to
Object. The automatic conversion means that the people
who wrote the Vector class did not have to write a
separate method for every possible type of object that
anyone might conceivably want to store in a Vector.
Object
reference casting:
Object
reference casting is like primitive-casting: by using
a cast, you convince the compiler to let you do a
conversion that otherwise might not be allowed.
Any kind
of conversion that is allowed for assignments or
method calls is allowed for explicit casting, though
it is not needed (done by compiler implicitly). The
power of casting appears when you explicitly cast to a
type that is not allowed by the rules of implicit
conversion.
It is
important to understand the difference between objects
and object reference variables. Every object (almost)
is constructed via the ‘new’
operator. The argument to the ‘new’
determines for all time the true class of the object.
Java programs do not deal directly with the objects
but with references to objects. The objects themselves
live in memory somewhere in JVM. The reference
variable contains something similar to the address of
the object. This address is known as reference to the
object. References are stored in variables, and
variables have types that are specified by the
programmer at compile time.
While an
object’s class is unchanging, it may be referenced by
variable of many different types.
The type
of a reference variable is obvious at compile time.
However, the class of an object referenced by such a
variable cannot be known until runtime. This lack of
knowledge is not a shortcoming of Java: it results
from a fundamental principle of computer science.
The
rules for casting are a bit broader than those for
conversion. Some of these rules concern reference type
and can be enforced by the compiler at compile time.
Other rules concern object class and can only be
enforced during runtime. The table below demonstrates
compile time rules.
|
OldType is
a non-final class |
OldType is
a final class |
OldType is
an interface |
OldType is
an array |
NewType is
a non-final class |
OldType must
extend NewType or vice versa |
OldType must
extend NewType |
Always OK |
NewType must
be Object |
NewType is
a final class |
NewType must
extend OldType |
OldType and
NewType must be the same class |
NewType must
implement interface OldType |
Compiler
Error |
NewType is
an interface |
Always OK |
OldType must
implement interface NewType |
Almost always
OK |
OldType must
be Object |
NewType is
an array |
OldType must
be Object |
Compiler
error |
Compiler
Error |
OldType must
be an array of some type that can be cast to
whatever NewType is an array of. |
Assuming
that a desired cast survives compilation, a second
check must occur at runtime. The second check
determines whether the class of the object being cast
is compatible with the new type.
Compile time rules:
-
When both OldType and NewType are
classes, one must be a subclass of the other.
-
When both are arrays, both arrays
must contain reference types, and it must be legal
to cast an element of OldType to an element of
NewType.
-
You can always cast between an
interface and a
non-final object.
Runtime rules:
Remember
that the conversion to NewType must actually be
possible.
-
If NewType is a class, the class of
the expression being converted must be NewType or
must inherit from NewType.
-
If NewType is an
interface, the class of
the expression being converted must implement
NewType.
section5-1-1 | section5-1-2 | section5-2 | section5-3 | section5-4
Sections :
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11
|