Java Basics

These notes present the basics of Java in outline form. They only discuss the ways in which Java differs from C++. If something is not discussed, such as for loops, if-then-else statements, or constructors, it is because they are identical in both C++ and Java.


I. Java's built-in types

    1. boolean -- true/false
    2. byte -- 8 bit integer
    3. char -- character
    4. double -- double precision floating point number
    5. float -- single precision floating point number
    6. int -- integer
    7. long -- long integer
    8. short -- short integer

II. The String class--String is a built-in class that replaces C++'s
    char * strings

    A. Strings are immutable--once they are created, their contents cannot
       be changed

       Example:  String a = "Hello";
                 a = a.concat(" World");

		 In this example, the concatenation operation creates a
		 completely new string to hold "Hello World" and then makes
		 a point to the new string. The old string object
		 remains unaltered with its contents still being "Hello".
		 Since no other variables point to it, it is eventually
		 garbage collected.

    B. Strings should be compared using a string's equals method.
      
      Example: String token;
               String day = "Wednesday";
               ...
	       if (token.equals("+")) ...
	       else if (token.equals(day)) ...

    C. Use a StringBuffer object if you want to modify/edit a string

III. Scope rules

    1. A variable may be declared within

        a. a class
	b. a method
	c. a block

    2. A variable may not be declared anywhere outside a class (i.e., there
       are no global variables in Java)

    3. A variable that is declared within a block cannot have the same
        name as a variable in an enclosing block or method. This rule is
	different from C/C++ where a variable may have any name when it is
	declared within a block.

	Example: The following code will cause the Java compiler to
	 generate an error message because j is declared
	 both in the body of the method and in the body of the
	 for loop:

	 int countPositive(int [] a) {
	     int count = 0;
	     int i, j;

	     for (i = 0; i < a.length; i++) {
	         int j = a[i];
		 if (j > 0) count++;
	     }
             j = a.length - count;
	     System.out.println("number of negatives = " + j);
	     return count;
	 }

IV. Arrays: They are objects, not primitive types
    1. Must be explicitly allocated using the new operator
    2. The declaration uses empty brackets since the size of the array
        is not known until it is allocated.

	a. The brackets can be either after the type name or after the
	    variable name

	e.g., int a [];
	      int [] b;
	      int c [] = new int[6];
	      int [] d = new int[10];

	b. You can also provide a set of items to initialize an array, in
	   which case new is not required:

	   String weekdays [] = {"Monday", "Tuesday", "Wednesday",
	                         "Thursday", "Friday"};

    3. The length field returns the number of elements

        e.g., System.out.println(c.length) will print 6

    4. Multi-dimensional arrays are arrays of arrays

        e.g., int a [][] = new int[4][5];
	      int b [][] = new int[4][];
	          b[0] = new int[5];
		  b[1] = new int[4];
		  ...

V. Type conversions

    1. Java automatically performs a type conversion if the conversion does
        not entail a loss of precision. For example, Java will convert an
	int to a double:

	int a;
	double b;

	b = a; // okay because there is no loss of precision

    2. Java will generate an error message if the type conversion would
        entail a loss of precision:

	a = b; // not okay because the fractional portion will be lost when
	       // b's value is assigned to a

	 a. In C++ such a conversion will only generate a warning message

    3. The programmer may explicitly downcast (also called narrowing)
        one type to a less precise type, in which case Java will perform
	a pre-defined narrowing operation:

	a = (int) b; // okay. Java will truncate the fractional part of b's
	             // value and assign it to a

VI. Classes

    A. Variables whose types are classes cannot be allocated on the stack.
       In other words, Java does not allow value objects. All objects are
       allocated from the heap by calling new.

       1. Java does not have a concept of pointers. When you create an
           object and assign the result to a variable, Java does indeed
	   assign a pointer to the object to the variable, but you do
	   not have access to the pointer like you do in C++ (e.g., in C++
	   you can increment or decrement a pointer). 

       2. All member accesses are performed via the dot (.) operator

       3. When an assignment statement such as a = b is executed,
           a is made to point to the same object to which b
	   points. If a modifies a member of this object, then
	   b will also appear to change. For example:

	   Stack a;
	   Stack b = new Stack();
	   b.push(3);
	   a = b;
	   a.push(5); // b's stack now contains both 3 and 5

	   a. this treatment is different than in C++ where a would
	      receive a copy of b's object because a and b
	      would both be value objects. In C++, a's stack would 
	      contain 3 and 5 after the push operation but b's stack
	      would only contain 3.

       4. The == operator compares pointers, not the contents of two objects.
          We say that the == operator performs a shallow comparison,
	  rather than a deep comparison. This comparision of pointers
	  is why you need to use a string's equals method to compare the
	  values of two strings.

    B. Declaration of instance variables in a class: Unlike C++, you may
        assign a default value to a variable when it is declared. Java
	will assign this value to the variable before the object's constructor
	is called. 

	Example: class Stack {
	            int size = 10;
		    int top = 0;
		    ...
		 }

		 To accomplish the same type of initialization in C++ you
		 would have to ensure that every constructor explicitly
		 performed this initialization or called a method that
		 performed this initialization.

    C. Initialization blocks: You can use an unnamed block, called an
        initialization block, to perform initialization actions on a
        class's members, before the constructor is called. 

       1. If you create an initialization block, then it will also be called 
           when an object is first created

       2. The code in the initialization block is executed after the default
           values are assigned to variables but before the constructor is 
	   called

       3. Example: class Calender {
	             String daysOfTheWeek [] = new String[7];

		     { // this is just an example. A better way to initialize
		       // the array would be to list the members when you
		       // declare the array

		         int i;
			 
			 daysOfTheWeek[0] = "Sunday";
			 daysOfTheWeek[1] = "Monday";
			 ...
			 daysOfTheWeek[6] = "Saturday";
		     }

    D. Static keyword: declares a variable to be a class member.
        
	1. A static variable is essentially a global variable for that class
	   and all instances of that class share its value. 
	2. There is only one copy of the variable and it is stored with the
	   class rather than with an instance

	   Example:  static String color = "red";

    E. static blocks: static blocks are similar to initialization blocks
        but are proceeded by the keyword static

       1. they are called when the class is first loaded and can
           be used to initialize static members

       2. this treatment differs from C++ in which a static member must be
           declared and initialized in a .cpp file as well as being declared
	   in a .h file.

    F. Finalize method: replaces C++'s destructor and is only needed to
       release non-Java resources, such as a file handle

        1. signature: void finalize() {...}
	2. is called by the garbage collector when the object is finally
	   destroyed
        3. cannot count on when it will be called because you cannot count
	   on when the object will be garbage collected

	   a. if you need to ensure that a final set of actions is performed
	      on an object, create your own method and then call it when
	      you are ready to release the object

	   b. do not call finalize yourself since it will also get
	      called by the garbage collector. Doing so may cause your
	      program to try to release the same set of resources twice, and
	      the second time you won't own them anymore. Trying to release
	      resources you don't own could create unpredictable results.

    G. Parameter passing

        1. Java uses pass-by-value, not pass-by-reference

	2. Can return objects since they're allocated off the heap

	3. Passing a reference to an object allows the method to modify
	     the contents of the object. This may seem like a contradiction
	     to the pass-by-value dictum but if you think about it, it
	     makes sense. The reference value (i.e., pointer value) gets
	     copied, and hence the parameter has a pointer to the same object
	     as the argument

	4. C++ uses both pass-by-value and pass-by-reference

	    a. Place an ampersand (&) after the type in a parameter declaration
	        to make the parameter a reference parameter:

		void swap(int &a, int &b) {
		    int temp = a;
		    a = b;
		    b = temp;
		}

		actual call: swap(x, y);

            b. When C++ sees a reference parameter, it passes a pointer to
	        the argument rather than a copy of the argument to the
		method. 

		i. When you assign a value to a reference parameter, the value
		    is assigned to the argument's memory location, thus
		    modifying the original argument

		ii. When you access a reference parameter on the right side
		     of an assignment statement, C++ return's the current
		     value at the argument's memory location

	    c. Reference parameters were introduced into C++ to reduce
	        the need to explicitly pass addresses of arguments to
		methods and to explicitly dereference parameters in methods.
		Compare how swap must be implement and called using the
		pass-by-value method as compared to the pass-by-reference
		method:

		void swap(*int a, int *b) {
		    int temp = *a;
		    *a = *b;
		    *b = temp;
		}

		actual call: swap(&x, &y)

		As you can see, there are many more opportunities to introduce
		an error when you have to explicitly take the address of
		arguments and dereference parameters.

	    d. Unfortunately, in practice reference parameters are confusing
	        to use and the designers of Java decided to do away with
		them. Note however that because of the way Java copies 
		reference values to parameters, Java really is doing 
		a form of pass-by-reference for objects.

    H. Nested classes: Classes can be nested inside a Java class just as
        in C++

        1. A nested class has access to all the members and methods of its 
	    enclosing class

	2. An instance of a nested class is associated with the instance of
	    the class which creates it. A nested class cannot be created
	    independently of its outer class

	    e.g., class foo {
	            ...
		    public class goo { ... }
		  }

		  foo.goo a = new foo.goo() will fail because a goo can only
		  be created by an instance of a foo

	    a. The java compiler creates a foo$x.class for goo
                where x is a number

    I. Final keyword: Java's way of creating a constant

        1. Memory for the final keyword is shared by all instances so you
	   do not have to declare them static.

VII. Inheritance

    A. You create a subclass using the extend keyword

    B. Access Modifiers

        1. public
	2. protected
	3. private

    C. Constructors

        1. use super to call the superclass constructor
	2. super must be the first statement in a constructor
	3. if super is omitted then the superclass's default 0-argument
	    constructor is called
	4. constructors are called in order of derivation, from superclass
	    to subclass
	5. super can be used to access any member of a superclass. It is
	    commonly used to access the superclass's method when you are
	    overriding it in the subclass.

    D. All methods are virtual by default

        1. Use the final keyword to prevent a method from being
	   overridden

	2. abstract methods with no method body can be created by prefixing
	    the method name with the abstract keyword

	3. classes that contain abstract methods must be declared abstract
	    themselves

	    a. subclasses must be declared abstract if they fail to define
	        an abstract method that they inherit from an abstract 
		superclass

    E. Object class: Implicit superclass for any class that is not defined
        to extend another class--all objects can be cast to Object