Page 5
Literal Constants
In JAVA, we can assign to data explicitly expressed values. These values
are called literal constants. Literal constants can be used for
assignment statements, comparisons, and calculations. But literal constants
have types just as our own data does, and we must be mindful of this
fact.
The numerical data types have, as literal constants, either the
integers or the reals. Any literal constant in which you include a decimal
point is automatically a decimal type (either floating point or
double precision floating point). When you do not include a decimal
point, it will be some integer type. For example, the literal constant 18
would be the integer eighteen, whereas the literal constant 18.0 would be the
decimal eighteen.
JAVA also allows a form of scientific notation, but only for decimal values.
To express a decimal in scientific notaiton, you can write in any value, followed
by either a capital or lowercase 'e', followed by an integer number. This result
is the first number multiplied the second number's power of ten. For example,
500 = 5 * 100 = 5 * 10^2 so you would write 5e2. Note that ^, the carrot
character, does not represent exponentiation in JAVA. Note also that
writing 5e2 does not stand for 25, the second power of 5.
The boolean type also has literal constants available to it. Since there
are only two values, JAVA made each of these values a JAVA keyword. They are
true and false.
The char type has, as its literal constants, any single character (or no
character at all) in single quotes. For example, 'a', 'b', and
'c'. Note that when we write out 1, this is an integer literal constant
whereas '1' is a character literal constant. The char value of '' is the
default value for chars.
Classes, in general, only have one literal constant value for their
object references. This is the JAVA keyword null. This keyword is often
very useful for comparisons between object references since they are, after
all, only references. A comparison between any object reference and the JAVA
keyword null will tell you immediately whether or not the reference is
actually referring to an actual object or not.
Two very specific Classes, the String class and the [] (array) class, have
their own unique literal constants. However, the array literal constants may
be only used for initialization. They may not be used for reassignment,
comparisons, or calculations. String literal constants are simliar to char
literal constants. They are formed somply by placing the desired value in
double quotes. For example, "Hello, World!" is a String literal
constant. Although String literal constants may be used for comparison with
the double equals comparison operator, since Strings are objects we will
always use the equals() method to for comparisons. We will never ever
ever use the dobule equals comparison
operator to compare String objects.
The array initialization lists are ordered lists, sourounded by curly
braces ( { and } ), and with a comma-separated list of the
successive values. For example, an int[] initialization list might look like
{1,2,3,4,5}, a char[] initialization list would look like
{'1','2','3','4','5'}, and a String[][] initialization list would look like {
{"hello","world"} , {"nice","to","see","you"} , {"again"} }. Note that
the array of arrays has as its initialization list an initialization list
of initialization lists, thus following the pattern.
Type Conversions
The studious, pragmatic, axiomatic mathematician will most likely want to
keep separate the differing numeric types as we so far have. He will realize
that the definitions for the different types are, in most set-theory classes,
unreconcilable. At most he would be willing to say that there is a subset of
real numbers that is isomorphic to the integers, or something really
complicated like that.
Fortunately, we are not so pragmatic! We wish to say at least that an
integer value may be assigned to a decimal value. But of course, we get stuck
going in the other direction. While we could repsent the integer 5 as the
decimal 5.0, we could not ever hope to represent the decimal 5.4 as any
integer. (The aforementioned pragmatic mathmetician will start ranting and
raving something utterly incoherent about "different sizes of infinity" or
some and other foolish notions). But ultimately, this means that we will need
to take all pairs of every single JAVA data type, and see if we can devise a
way to safely go from one to the other.
When looking at all the JAVA numeric primitives, we can see from the range
of the values that a well-ordering can be obtained from the smallest to the
largest. That is, a short can always step in and represent a byte, since
the range of a short covers at least the range of a byte. (Some may want to
say that one is a proper subset of another). Continuing in this fashion, we
arrive at the following ordering: byte --> short --> int --> long -->
float --> double . Whenever we take of advantage of this ordering in
comparison, assignment, or computation, we will call this numeric
promotion. For example, a double may be safely assigned the value of an
int, due to numeric promotion. In fact, the statement 'double x = 3;'
actually uses numeric promotion.
To go in the reverse order of numeric promotion runs the risk of losing
information. But we will allow ourselves to do this anyways through a process
called explicit casting. To explicitly cast ont type to another, simply
place the desired type in parentheses immediately in front of the data. For
example, if we had declared a double x and assigned it to 7.5, we could cast
it to an int, and then assign that value to an int y by saying: int y =
(int)x.
This ability to explicitly cast goes beyond numeric types,
however. Remember from inheritance that a subclass, by definition,
is an instance of the superclass. Therefore, we can impose at least a
hierarchical ordering on classes, and apply a kind of promotion when
necessary. Say we have two classes, Rectangle and Square. We can say the
following without any syntax errors: Rectangle a; Square b; a = b; (of course,
not on the same line!). A kind of promotion will occur during the last
assignment statement since a Square is a Rectangle. However, we could not hope
to perform the reverse assignment without casting, since we are not garunateed
that all Rectangles are Squares. For this assignment we would write the
following: Rectanlge a; Square b; b = (Square)a; We must first cast the
rectangle to a square, before assignment can occur. Note that while this
may not cause a syntax error, it would probably cause a runtime error if
a does not actually refer to a Square object.
The char type presents various possibilities. To account for integers, the
ASCII table was invented. ASCII stands for Ameircan Standard Code for
Information something or other, and it simply maps the type byte to char (and
vice vera). Take a look at the ASCII table to see
that the character 'a' maps to the integer 97 and the character '1' maps to
the number 49. Assignment from any numeric type to a char requires an explicit
cast, and assignment from a char to either a byte or a short requires an explicit
cast.
In general, object references of one class cannot be assigned to object
references of any other, without incurring either a compilation error or a
runtime error. The exception to this is, of course, inheritance. In that case,
promotion can occur upwards through the hierarchy tree, and explicit casting
may be possible downwards, but only if you really do have the type
required. Otherwise, Strings cannot be reconciled with arrays, or with
MainWindows, or Donuts, or anything of that sort.
Moreover, you cannot cast between object references and primitives. This
may seem strange in at least one case. We should think that we can at least
treat characters as Strings, but we can't. The best we can do is wait until we
learn about the String concatenation operator.