referemces: 'The Java1.1
Study Certification Guide', Heller&Roberts 'Just Java' , P.V. Linden
An array
is
an ordered collection of primitives,
objects
or other arrays.
In Java there
are three common, non-primitive, object reference types, classes,
interfaces
and
arrays.
Arrays are like classes in that they are
1) assigned to references,
2) are allocated with the new operator and
3) have Object class as a parent.
Arrays are not like classes in that they
1) can't be subclassed
2) they have their own syntax and
3) can't have custom methods defined.
Further,
1) a given array's elements are all of the same type.
2) Java array indexes start at 0.
3) Arrays can be passed as arguments.
4) An array's length is available through the final, data field,
length.
//an array's length field is easy to confuse with the String class method length( )
Array Declaration
int I [ ]; //
is the same as
int [ ] I ;
// and declares an array of integers
double _2D [ ][ ];
// is the same as
double[ ][ ] _2D;
or double [ ] _2D [ ] ;
//and declares an array of an arrays of doubles
More on Array Declarations
int [] i, j: // is the same as declaring the two arrays seperately as follows int[] i; int[]j; int [] k, l[], m[][]; // is the same as declaring the following arrays int []k; int [][]l; int [][][]m; // note how the first part of
the multiple array declaration (int []) , distributes
|
Construction
Like a class, size is allocated at construction via the new keyword at runtime.
int I [];
// declaration
I = new int [15]; //
instantiation (or construction) is coupled with setting the initial size
of an array
int size = 20;
I = new int [size];
// size can also be set via a variable
String[] s = new String [99]; // It is common for declaration & construction to appear on the same line
When first constructed, array elements are initialized
to
the default values for the type the
array contains. For example, an int array will have each of
it's elements set by default to 0.
An array of type double will have each of it's elements set
by default to 0.0 .
Inititialization
1) Arrays can be initialized with a set of like types matching the type of the array. For example
String[ ] s = {
"one", "two", "three" }; //
or
double[ ] d = { 1.1, 2.2,
3.3, 4.4, 5.5 };
2) Arrays can also be initialized by explicit assignment as in the following example.
short [ ] cubes = new short[25];
for( int i =0; i < cubes.length;
i ++)
cubes[i] = i * i * i;
3) JDK 1.1 introduced an array creation expression with the form
new types[] { values. . . };
Example
byte b[ ] = new byte[ ] { 5, 5, 5 };
// an array expression statement used in an assignment
1) The clone( ) method can be used
to make an exact copy of an array. The clone(
) method
returns type Object.
When using this method the return value is cast
back
to the array type..
For example,
int Z [] = new int []{1,9,11};
int Y [] = (int [ ] )
Z.clone( ); // Y array
will be a perfect copy of Z containing 1,9, & 11
The type in brackets, (
int [ ] ) ,
is a cast and,
changes the method's return value back to
an array type
2) arraycopy( ) is a System
class
method that can copy all or part of an array. Here is how
it is defined.
public static native void arraycopy
(Object src, int src_position,
Object dst, int st_position, int length);
// Following is how the operation of the method is described in the API.
Copies an array from the specified
source array, beginning at the specified position, to the specified
position of the destination
array .... The number of components copied is equal to the length
argument.
The components at positions
srcOffset through srcOffset+length-1 in the source array are copied into
positions dstOffset through
dstOffset+length-1, respectively, of the destination array.
Code Example
class arrayCopy{
public static void main(String[]
args){
// a couple of String arrays are created by different techniques
String[] statement
= new String[] { "It's", "not", "true", "it", "was", "my", "plan"};
String[] out_of_context=
new String[ 4];
// the method arraycopy() is demonstrated
System.arraycopy(statement,
3, out_of_context, 0, 4);
for(int
i=0; i <out_of_context.length; i++)
System.out.print(out_of_context[i].toUpperCase( ) + " " );
System.out.println(""); // just for a space
// the clone() method is used to duplicate the String array referenced
by statement
//
and assign the copy to the twin String
array
String[] twin= ( String[]
) statement.clone( );
for(int
i=0; i <3; i++)
System.out.print( twin[i] + " " );
}
}
Array of Arrays
Java describes it's compound arrays as arrays of arrays (rather than multidimensional arrays).
Chev cars [ ][ ]; // an array of array(s) declared but not allocated
Ford fords[ ][ ] = new Ford[9] [999]; //
a declaration where fords references an array of 9 element.
// And each of these elements is an array of 999 Ford objects.
The subarrays don't have to be a single size. Here's an array creation
to fill a triangle where
each subarray is a different size
int Triangle[ ][ ]= new int[ ][ ]{
new int[ ]{1},
// or just put {1},
new int[ ]{2,2},
//
{2,2},
new int[ ]{3,3,3}, //
{3,3,3},
new int[ ]{4,4,4,4} //
{4,4,4,4}
};
int [ ][ ][ ] giga = new int[1000][1000][1000]; // a gigabyte array
//Van der Linden warns to watch
the size the compound arrays you create
/* This
class shows an assignment to one of the array elements and a printout of
it and
the following value which will have the default value for an int stored in it. The default values stored in arrays correspond to the type associated with the array. */ class a2T{ public static void main(String[] args){ int [ ][ ][ ] giga = new int[100][100][100]; giga[51][52][53] =55; System.out.println(giga[51][52][53] +" "+ giga[51][52][54]); } } // prints out 55 and zero |
To return an array from a method it is suggested to use
int[ ] method( ) {
return new int[9];
}
// rather than the following C style
int method( ) [] {
return new int [11];
}
This supports the thought of those that puts the
square braces after the type but before the
identifier. For example, main ( String [] args)
vs main (String args []). The first form clearly
shows an array of type String is being returned
by the method. A hasty look at the second
method form might give the impression that it
returns just a String.
Before looking at Operators, we should define what an expression is
An expression
is something that evaluates to something. If I said my age was (10
x 5 ) you would
know I really meant 50. (10 x 5 ) is an expression that evaluates to
the number 50.
In Java anything that evaluate to 1) variable,
2) a value or 3) a void is an expression..
The (10 x 5 ) expression evaluates to a value,
50. An instantiatiation of a class
evaluates to a reference value that can be stored
in a variable. Sometimes an
expression doesn't resolve to a value, but only
to a variable. You can think of
2*x as resolving to the variable 2x. A method
can return specific values but also
can return void. A method call is considered
an expression. When a expression
is concluded with a semi-colon, the expression
becomes a statement. The semi-
colon is not the only way an statement ends.
A block of code enclosed in curly
braces is also considered a statement.
Example class
Expresso{
public static void main(String[] args){
System.out.println( "The square root of 91: " + Math.sqrt(91) );
// an expression that resolves to a value
double sqrt2=Math.sqrt(111);
// an expression used in a statement
System.out.println("The square root of 111: " + sqrt2);
}
}
Output
C:\NewCode\Expressions>java Expresso
The square root of 91: 9.539392014169456
The square root of 111: 10.535653752852738
Operators are the basic symbols
a language uses to do rudimentary operations. An
operand is a value or variable
that is acted on in someway by an operator. If the
operator works on a single operand it is called a unary
operator, an example is x ++.
This is the post-increment operator and increases the value that is
stored in x by one.
If an operator works on two operands at once it is often called a binary
operator.
An example is * , the multiplication operator which works on two numbers
as in
( int x = 3 * 3 ; ). There is only one ternary
operator
in java, which works on three
operands and it gets the name the ternary operator. We look at the
ternary operator
near the end of this section.
Operations are ordered according to the rules of precedence,
associativity & order
of evaluation
Precedence
Precedence is the idea that certain operations
will occur before others. We expect
multiplication to occur before addition.
Example 1 3 + 2 * 2 evaluates to 7 not 10
We can use round brackets to overrule the rule of precedence.
Example 2
(3 + 2) * 2 does evaluate to 10
Associativity
Associativity is the property that decides which
operation goes first between operations
which have equal precedence. For instance, the
multiplicaton and modula operators
have the same precedence. What these operators
are explained shortly.
Example 4 * 5 % 10 // division and multiplication have the same precedence which goes first.
The CoffePot
rule is used to decide between operators with equal precedence. The name
abreviates Code
Order
For
Finding
Evaluating
Equal
Precedence
Operator
Textstrings.
The rule states that multiplication and division
are left-associative an so are evaluated from
left to right as in ( 4 * 5 ) % 10.
Order of Evaluation
Order of Evaluation describes the sequence in
which operands are evaluated. Java is
strictly a left to right language for order of
evaluation. In the following example operands
are evaluated left to right. The left operand is evaluated before the
right even in an
assignment.
// Example from the Java Certification Guide, Heller&Roberts
int [] a = new int [2];
int b =1;
a [ b] = b = 0;
Which value of b is used?
First, evaluating left to right, a[b] is evaluated so it is a reference
to the array element at a[1].
Next, b is evaluated, a reference to the variable called b. The constant
expression 0 is next
evaluated which is no work. Now the operations take place in order
of precedence and
associativity. The value zero is assigned to variable b and then the
value zero is assigned the
last element (a[1]) of the array a.
(see coffee pot rule that states assignment is right associative)
Java Operators in order of precedence
Unary | ++ -- - + ! ~ ( type cast ) |
Arithmetic | * / % - + |
Shift | << >> >>> |
Comparison | < <= > >= instanceof |
Bitwise | & ^ | |
Short Circuit | && || |
Ternary | ? : |
Assignment | = or of the form
op =
( where op is * , / , % ,+ , - ,<< , >> , >>> , & , ^ , or ! ) |
Coffee Pot rule for determining
Associativity // higher
# corresponds to higher precedence
left associative operators | precedence | right associative operators | precedence |
post-increment & decrement | 15 | ++ pre-increment & decrement | 16 |
* / % multiplicative | 12 | ~ inversion (bit flip) | 14 |
+ - add and subtract | 11 | ! logical not | 14 |
<< >> >>> bit wise shift | 10 | - + arithmetic negative & positive | 14 |
instanceof < <= > >= relational | 9 | type conversion (cast) | 13 |
== != equality | 8 | . | . |
& bitwise AND | 7 | . | . |
^ exclusive OR | 6 | . | . |
| bitwise (inclusive) OR | 5 | . | . |
&& conditional AND | 4 | tertiary (conditional) operator | 2 |
| | conditional OR | 3 | assignment =
*= /= %= +=
-= <<= >>= >>>= &= ^= != |
1 |
Unary Operators
The increment and decrement Operators ++ and --
Operators which modify the value of an expression by adding or subtracting
1. They come
in pre- and post- versions. The pre-increment/decrement types
carry out the operation
before they are used, say in an assignment, while the post versions
result in the original
value being used or assigned before the operation of incrementation
takes place.
Example 1
int start = 7;
int getPost = start ++;
// in post-increment, getPost has value 7 assigned then start is incremented to 8
Example 2
int start2 = 11;
int getPre = ++start2;
// in pre-increment, first start2
is incremented to 12, then getPre is assigned 12
The Unary + and - Operators
Unary +
and - are
distinct from the binary +
and - which
usually refer to add and
subtract.
Unary +
explicitly labels a numeric literal as being positive. Unary -
negates
an expression.
The Bitwise Inversion Operator ~
The ~ operator performs bitwise inversion on integral
types. The 0s and 1s of the
binary representation are inverted; zeros become
ones and ones become zeros.
For example, applying the bitwise inversion operator
to the byte value 5 causes
it's binary representation, 0000 0101 to becomes
1111 1010.
The Boolean Complement Operator !
The ! operator inverts the value of a boolean expression. !true evaluates to false.
The Cast Operator (type)
Casts can be made to explicitly change the type
of an expression. Casts can be
applied to primitive values as well as reference
values though there are a lot of
rules covering which casts are legal or not.
For example,
double d = 1.412;
int i = (int) d;
// results in 1.412 being
converted to the int value 1
Arithmetic Operators
Multiplication and Division Operators * and /
The * and / operators perform multiplication and
division on primitive numeric types including
char type. Multiplying two integer types
may result in overflow,
the condition where a number
is too large to be represented by the range of
it's type. In this case a meaningless value is
obtained. Dividing with integers may result in
the loss of fractional information so a loss
of
precision
occurs.
(Integer
division truncates towards zero. 9/5 is 1.8 and truncates to 1.
-9/2 is -4.5 and truncates to -4 ) Examples:
int bigInt= 2147483647;
// the biggest int before overflow
int lever= 1;
int tooBig = bigInt + lever;
// adding one overflows to the largest negative int value, -2147483648
int x = 9;
int y = 5;
int z = x / y;
// case of integer imprecision shows the value of 9/5 being equal
to 1
If forced to do an operation that involves both
a multiplication that will go out of range and lose
meaning and a division that will lose precision,
it is better to divide and lose presision first and
then to multiply, staying in range, as you are
at least left with at value that has some meaning.
The Modulo Operator %
Also called the remainder operator, returns the remainder of a
division. It is usually
used with integer values but may also by used with floating point types.
Example:
int h = -7 % 2; //
h is assigned the value -1
More on the Modulo Operator //
from The Java Certification Guide, Heller&Roberts
A rule of thumb for calculating modulo results from negative numbers: Drop the negative signs from either operand. Calculate the result. If the original left-hand operand was negative, negate the result. The sign of the right hand operand is irrelevant. As with integer types a division by zero involving a modulo operator can throw an Arithmetic Exception. |
The Addition and Subtraction Operators + and -
+ and - operators perform addition and subtraction. The addition operator
+ is overloaded
to do String concatenation. Examples:
int j = 1;
int k = 2;
int l = j + k;
System.out.println ("One plus two is " + l + "." +
"The numeric literal " + (1+"") +
", here is promoted to String type");
Shift Operators << >> >>>
Shift operators work on the the binary form of integral type numbers,
shifting the bit pattern left
or right. Because of arithmetic promotion,
where integral types lower than int get promoted
to int automatically before an operation is started, shift operations
should generally just be used
on int and long types. Also shifts shouldn't exceed the
number of bits in the type being shifted.
// above a shift of 32 for an int the value 'rotates'. i.e A shift of 2 on an int is the same as a shift of 34
>> The
signed right shift operator moves the bit pattern right, filling
the top most bit
position with the value that was
there before the shift. For example, the number 8,
represented as an int in
binary form is
| 0000 0000 | 0000 0000 | 0000 0000 | 0000 1000 | // bars are just for our view
int v = 8 >> 2;
The above statement results
in the pattern being right shift two places. The right most
two ones are lost and the
top two bit, at the left are replaced with what was there, in
this case zeros. The result
is
| 0000 0000 | 0000 0000 |0000 0000 | 0000 0010 |
This is the binary representation
for the number 2. The net effect is a division by two
for each time the bit pattern
is shifted. ( If the top most value was a binary one the
value would be a negative
number and the added values would have retained this
sign by adding two more
binary ones.
Example of right shifting a negative number
| 1111 1111 | 1111 1111 | 1111 1111 | 1111 1000 |
int v = -8 >> 2;
| 1111
1111 | 1111 1111 | 1111 1111 | 1111
1110 |
<< The
signed left shift operator works
opposite to the right shift operator shifting values
to the left, filling the
least significant bit positions with zeros. The net effect of the shift
is a
multiplication of the value
by two for each shift of the bits left.
>>> The unsigned
right shift operator shifts
in the same way the signed right shift operator
does
except
it zero fills the most significant digit whether it was a 1 or a zero.
Thus
the
unsigned right shift operator will always make the resultant number positive.
//
1100 0000 0000 0000 >>> goes to 0011 0000 0000 0000 with the
top bits zero filled
The Comparison Operators
The ordinal comparison operators < <= > >=
The ordinal comparison operators are used to compare
numbers. They evaluate to a boolean
value, true or false. For example,
int p = 12;
double d= 244;
if (p < d )
System.out.println(" True, p is less than d");
The instanceof Operator
The instanceof operator is unique in that it is represented as
a keyword. It does comparison
on reference types. It returns true if the class type represented by
the reference in the left
argument is the same type represented in the right-hand argument. For
this to be true the left
argument type must be the same class or a subclass of the type represented
in the right-side
argument.
Example
String s ="X";
if ( s instanceof Object )
System.out.println("The boolean
must evaluate to true as all classes descend from Object \n");
The Equality and Inequality Operators = = and !=
= =
and !=,
are the symbols for equality and inequality and return a boolean
value. For
primitives, actual values are compared. For reference
types, memory locations are compared.
These operators are not for use in comparing
the contents of objects, (where the memory
address points). Doing so tests if two references
point to the same object rather than if they
each contain two objects which are equivalent.
The Bitwise Operators
The bitwise operators &
| and
^
provide
bitwise AND OR and
Exclusive OR
operations, taking two boolean or integral type operands.
They follow the boolean algebra rules where
1) 1 AND 1 yields 1, all other combinations
produce zero.
2) 0 OR 0 yields 0, all other combinations
produce 1.
3) 1 XOR 0 and 0
XOR 1 both produce 1, and any other combination results in zero.
In a boolean context the same rules apply except applied to true and
false values as if they
are one and zero.
Short Circuit Operators
The short circuit operators &&||,
also
called the conditional AND / OR operators
only take boolean values. If the first boolean evaluates to true the
second is not evaluated
There is no short circuit XOR operator. It is useful to avoid doing
a test that may result in
an exception being thrown by whatever is being tested in the second
boolean expression.
For example,
if ( ( theClass != null && ( theClass.getTextLength( ) >1) )
This operator allows testing if a class is null
and avoiding calling a method on the class if it is
which would result in a NullPointerException
The Ternary and Assignment Operators
The Ternary Operator ? ... :
The ternary if... else operator is a short form of the if ... else construct. It has the form
boolean bool = true ;
x = bool ? y : z ;
where bool a boolean which, if true
results in y being assigned to x,
else
if bool is false,
z assigned to
x. The variables x, y and z have
to have to be compatible types.
Assignment Operators
The assignment operators have abbreviated combined forms such as add
and assign.
An example is
i += 5;
// is the same as
i = i +5;