Identifiers, Keywords and Types
Java uses Unicode
for representing characters internally. It is possible to represent a
Unicode
character directly by using \uxxxx.
This will make it easier to write international versions of software.
Identifiers can be any length in Java. They must start with a
letter,
underscore or dollar sign.
Non-ascii characters can be used in names, for instance:
miáéíóúña
There are two types of comments
/*
Comments as in C
*/
or
// Comments as in C++
There is also javadoc, the tool that was mentioned previously that
works
in conjunction with the compiler to produce web pages that document a
particular
project.
Comments of the form
/**
*
*/
are extracted by javadoc and associated with the closest class,
attribute
or method that follows.
The keywords in Java can be classified by their use:
| Name | Range of values | Purpose |
| boolean | false, true | |
| int | -2,147,483,648 to 2,147,483,647 | 4-byte integers - 32 bits |
| long | -263 to 263-1 | 8-byte integers - 64 bits |
| byte | -128 to 127 | 1-byte integers - 8 bits |
| short | -32,768 to 32,767 | 2-byte integers - 16 bits |
| double | -1.7E308 to 1.7E308 14-15 figures of accuracy | 64-bits floating point numbers - IEEE 754 standard |
| float | -3.4E38 to 3.4E38 6-7 figures of accuracy | 32-bits floating point numbers - IEEE 754 standard |
| char | Unicode values between 0 and 65,535 | Unicode characters 'a' (single quotes) |
String is a standard Java class. It is easier to use than the arrays
of characters terminated with '\0' used in C.
A string literal is surrounded by double quotes "This is a string.".
A String is an object.
Strings can be instantiated in two different ways:
String cat = new String("Garfield");
or one can use this shortcut:
String cat = "Garfield";
Strings can be concatenated by using the + operator (this is called operator overloading, the operator is used for an additional purpose).
The Object class has a toString() method. Everything is derived from Object, so any class will have a method toString() available. The regular version of toString() is not very friendly, but it is possible to override it when one writes a class.
If one needs to compare two strings, it is better to use the equals
method available in String.
if (s1.equals(s2))
...
It is possible to find the length of a String by using the method
length()
(Chapter 5 in Van der Linden´s book)
The general case of a name would be:
package1.package2.packageN.Class1.Class2.ClassM.memberN
For example:
java.lang.System.out.println("Hello world!");
java contains several packages.
java.lang is one of those packages.
java.lang.System is a class in the java.lang package.
java.lang.System contains a field called out, an object of the
class PrintStream.
println is a method of the class PrintStream.
Using these prefixes will allows us to distinguish among several identifiers or methods with the same name from different packages.
Java accepts the same name for a method, an attribute or a label.
They
are kept in separate name spaces.
It is a common custom in the OOP community to use verbs for methods,
nouns that start with lower case for attributes (variables) or
instances
and nouns that start with upper case for Classes.
It is possible to forward reference an identifier in Java.
Example:
class Fruit {
void foo() { grams = 22;
} // grams not declared yet
int grams;
}
| Expression | Example |
| a literal | 245 |
| this object reference | this |
| a field access | banana.grams |
| a method call | banana.getName() |
| an object creation | new Fruit("Kiwi",10) |
| an array creation | new int [29] |
| an array access | myArray[i][j] |
| any expression connected by operators | banana.grams * 1000 |
| any expression in parenthesis | ( banana.grams * 1000 ) |
The evaluation of an expression will yield:
Java is a strong typed language. The type of an expression will be evaluated either at compile time or at run time.
Arrays are objects in Java. Array types are reference types in Java,
an array variables is really a a reference to an array.
The subscripts always start at zero.
Array indexes are checked at runtime. If a subscript tries to access an element outside the bounds of its array, it causes an exception.
Arrays are allocated with the "new" operator. They are allocated on the heap, never on the stack.
One of the attributes of an array is its length. So it is possible
to
access it:
a.length
When declaring an array, one does not specify its size:
int carrot [];
Before one references an entry in this array, one should create the array with new or make it point to an existing array.
Depending on the kind of elements that will be stored in the array, one may obtain
or
Vegetable carrot[] = new Vegetable[256]; // Creates 256 references
to
Vegetables
carrot[11].grams =
32;
// Invalid, carrot[11] contains null at this time. A null pointer
exception
occurs
To be able to use the array carrots, one needs to allocate objects for each of the references:
for(int i=0;i<carrot.length;i++)
{
carrot[i] = new Fruit();
}
It is possible to create an initialize an array at the same time:
Examples:
byte b[] = {0, 1, 2, 3, 4};
String wkdays[] = new String[]
{"Mon","Tue","Wed","Thu","Fri"};
Arrays of Arrays
Java has arrays of arrays.
They are declared in this way:
int matrix [] [];
Again, it is necessary to use new to allocate them:
matrix = new int [rows][columns];
It is possible to use initialization with multidimensional arrays.
Example:
int smallMat [][] = new int [] [] { {0, 1, 2},
{3, 4, 5},
{6, 7, 8}};
In declarations, the brackets can be placed before or after the name
of the array:
Example:
int a [];
int [] b;
Both forms are valid.
This flexibility is useful when one is declaring a method that is returning an array.
int [] myMethod () // We state that
myMethod
returns an array of integers
{
return new int[10];
}
Because arrays are objects, they are never allocated in the stack. They are allocated from the heap.
Operators
Operations are evaluated left-to-right
| Symbol | Operation | Precedence
Highest number -> highest precedence |
Associativity |
| ++ -- | pre-increment, pre-decrement | 16 | right |
| ++ -- | post-increment, post-decrement | 15 | left |
| ~ | flip the bits of an integer | 14 | right |
| ! | logical not (reverse a boolean) | 14 | right |
| - + | arithmetic negation, plus | 14 | right |
| (typename) | type conversion | 13 | right |
| * / % | multiplicative operators | 12 | left |
| - + | additive operators | 11 | left |
| << >> >>> | left and right bitwise shift | 10 | left |
| instanceof < <=
> >= |
relational operators | 9 | left |
| == != | equality operators | 8 | left |
| & | bitwise and | 7 | left |
| ^ | bitwise exclusive or | 6 | left |
| | | bitwise inclusive or | 5 | left |
| && | conditional and | 4 | left |
| || | conditional or | 3 | left |
| ? : | conditional operator | 2 | right |
| = *= /= %= += -=
<<= >>= >>>= &= ^= |= |
assignment operators | 1 | right |
Precedence says that some operations bind more tightly than others:
Given a + b * c
The multiplication will be performed before the addition, because
multiplication
has a higher precedence than addition.
Associativity is the tie breaker for deciding the binding when we
have
several operators of equal precedence.
Given a * b * c
How should this be interpreted?
Because multiplication has left associativity, it should be interpreted
as (a*b)*c