Session 6 Lecture Notes for First Course in Java

18-JULY-2005

This lecture covers the reading in Chapter 7: Methods and Classes (continued)

 

0(syllabus and calendar)

REVIEW

POLYMORPHISM


JVM MEMORY

Stack and Heap


ENCAPSULATION


STRINGS


ACTION ITEMS

Review by Demonstration Programs

An Array of Objects

The Output is:

Volume is 3000.0
myStringArray One and Two are...StringOne and StringTwo and mybox.toString(): Bo
x@82ba41
length of String array: 4
myObjectArray has the following: StringOne and StringTwo and Box@82ba41
length of object array: 4

Note: When you are at the Object level, you can only see that methods that belong to that class, such as toString(). The Object class doesn't know anything about what a subclass might or might not have. If you want to access the class members of a subclass, you have to work with that subclass.

A Calendar Program

 

About Methods

myObject.MethodOnThatObject();

myObject.PropertyOnThatObject;

A class has methods and properties. An instance of that class inherits those methods and properties.
It is common to say, "This is a property of the class", and "This is a property on the object".

Objects have data (instance variables) and behavior (methods).

An instance variable is data that is also a property (also called an attribute or a field).

Static variables and methods are at the class level and independent of the creation of an instance of that class.

Java does not support direct concatenation of methods in the way Unix shell scripting uses the pipe ( | ), which goes left to right.

ls -f  | more

Instead of a data pipe, think of communication, or messages.
You can pass the return value of one method as an argument to another method:

myObject.UseOutputOfAnotherMethod( myObject.MethodOnThatObject() );

Method nesting is unlimited:

myObject.UseOutputOfAnotherMethod( myObject.MethodOnThatObject( anotherObj.someMethod() );

The sequence of method calls goes from right to left.

Arrays: Two ways to Populate Them

You can populate an array in the same statement as the declaration.

Or, you can populate the array with a series of assignments after the declaration statement.

The arraycopy method belongs to what class? Does it belong to an object? What does the arraycopy method do?

Why would the arraycopy  method be a static method on the System object?

public static void arraycopy(Object src,
                             int srcPos,
                             Object dest,
                             int destPos,
                             int length)

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/System.html#arraycopy(java.lang.Object, int, java.lang.Object, int, int)

The array class provides methods that are static.

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Array.html

Arrays have the length property

There is something funny about arrays... they are implemented as objects!
Every instance of the Array class has a property called length.
The length of an array is NOT necessarily the number of values in the array.
The length of an array is the total possible memory slots (elements) available for holding values or objects.
The length is the capacity, not the contents. A typical egg carton is an array with what length?

What is the output of this application?

class MyArray {
    public static void main(String[] args) {
        int myArray[]= {25, 35, 85};
        System.out.println(myArray.length);
    }
}


A note about if statements

The three statements below are equivalent to each other.

  1. if(n==1) return 1; // one-line if statement
  2. // 2-line if statement
    if(n==1)
    return 1; 
  3. // 4-line simple if statement
    if(n==1)
    {
       return 1;
    }

keywords: this and super

this

Typically, within an object's method body you can refer directly to the object's member variables.
However, sometimes you need to specify the member variable name if one of the arguments to the method has the same name.

For example, the following constructor for the HSBColor class initializes some of an object's member variables according to the arguments passed to the constructor.
Each argument to the constructor has the same name as the object's member variable whose initial value the argument contains.

class HSBColor {
    int hue, saturation, brightness;
    HSBColor (int hue, int saturation, int brightness) { // arguments
        this.hue = hue;  // this.hue refers to the member variable
        this.saturation = saturation;
        this.brightness = brightness;
    }

You must use the this keyword in this constructor because you have to distinguish the argument hue from the member variable hue (and so on with the other arguments). Writing hue = hue; makes no sense. Argument names take precedence and hide member variables with the same name. So to refer to the member variable you must do so through the current object--using the this keyword to refer to the current object--explicitly (and using the dot operator).

Some programmers prefer to always use the this keyword when referring to a member variable of the object whose method the reference appears. In their view, this makes the intent of the code explicit and reduces errors based on name sharing.

You can also use the this keyword to call one of the current object's methods. Again this is only necessary if there is some ambiguity in the method name and is often used to make the intent of the code clearer.

super

If your method hides one of its superclass's member variables (by having the same name), your method can refer to the hidden variable through the use of the super keyword. Similarly, if your method overrides one of its superclass's methods (by having the same name with a different signature), your method can invoke the overridden method through the use of the super keyword.

In which line does the subclass hide a variable of the superclass?
In which line does the subclass override a method of the superclass?
 

Here is the output:


  

Overloading a method: polymorphism

Let's look at this demonstration:

Sometimes it is convenient to have one name for something even it takes several slightly different forms.
For example, we say "drive" a motocycle and "drive" a car, even though someone who can drive a car does not necessarily know how to drive a motorcycle.
And, to "ride" a bicycle requires a different kind of balance than to "ride" a crowded city bus.
The drive method has a different form for motorcycles than for cars.
The ride method means different behavior for bicycles than for buses.
The English words "drive" and "ride" are polymorphic, because there is a different form of driving or riding, depending on the class of the vehicle.

If the only difference is that between one car and another car, the drive method remains the same. We have a different in properties (data), but not in behavior.
If the only difference is that between one bus (city bus) and another bus (inter-city Greyhound), the ride method remains the same. The properties (data, such as destination) are different, but not the behavior.

Polymorphism has to do with behavior (methods).
We "greet" different people with different levels of formality. We behave in different forms, or many forms: poly-morphic.

It makes our language more simple when we can use the same word for closely related forms.
The same word means different things in different contexts.
Otherwise, we would need to have many more words, and that would be inconvenient.

Java has its counterpart to this flexibility of natural language.

The compiler looks for the "signature" of a method. Multiple methods can have the same method name, and yet have different signatures.
For example:

We say that  myMethod() is overloaded, and has six signatures.
A signature consists of a specific number of parameters, and the order (or position) of their specific types.
Therefore, a method with one argument can have multiple signatures with one argument if that argument has a different data type for each signature.

Indeed, we can say that a given method can have multiple forms. Overloading is an example of polymorphism.
Because a single class can have one or more overloaded methods, overloading helps make it practical to have encapsulation by class.
Every instance of a class--that is, every object--inherits all the properties and methods of that class, including any overloaded methods.

Note: Java classes are only polymorphic insofar as the methods of those classes are polymorphic. Polymorphism is a concept relate to behavior (methods).

Overloading Constructors

Default Constructor

If you do not define any constructor(s) for a class, Java automatically provides a default constructor that has no arguments.
However, if you define any constructor(s) for a class, then you must define them all, and Java provides no default constructor.

Let's review two examples of using constructors to create box objects.

Constructors

In this example, we use the object constructor (lines10-15) to assign hard-coded values to box objects.

Going a step further, here the constructor definition (lines 10-14) defines a signature that allows us to pass in actual values when we call the constructor to make objects (lines 26-27).
The constructor has a signature that facilitates making each box object different.

The flexibility for objects of the same class having different properties (data) often appears as a series of overloaded constructors.

The output is similar to the following, but the random number generator forces different ID numbers for each run:

name=Harry,id=2125,salary=40000.0
name=Employee #2126,id=2126,salary=60000.0
name=Mary,id=2127,salary=80000.9
name=,id=2128,salary=0.0
name=Employee #2129,id=2129,salary=68888.0

Using Objects as Parameters

This example compares two string objects by using  the equals() method and passing it a parameter that is a reference to a string object.

Comparing Objects

java.lang.Object defines an equals() method, but the default implementation is a = = test. 
Some objects override this method (which is polymorphism applied to inheritance).

When you compare Strings, the = = operator tests for identical objects.
However, generally you want to test for identical values being stored in the String variables.
Every String object has an equals() method for this test of equivalent values being stored in two string variables.

Whereas line 5 creates a second reference (or variable) to the original object, line 11 reassigns that variable to a new and different object.

Here's another example in which we pass an object as a parameter, but this time, it is a parameter to a constructor.

The following example has two constructors that take a single argument.
Which are the lines the code that call these two constructors, and how does the
javac compiler know the difference between the two constructors?

Passing Arguments by Value and Reference

In this section, we review the fundamental difference of calling by value, which is for primitives, to calling by reference, which is for objects.

Even though line 22 calls the meth() method, the result of lines 23-24 show that these lines see the same values as those declared in line 16.

However, an object is a special type that has, if you will, a history or a "state" of existence, which is something that a primitive type does not have.

Calling the constructor in line 25 passes in values that get assigned to a and b in lines 8-9.
However, in this example, a and b are not just integers: they are fields on an object.
Therefore, the logic of lines 16-17 operates on data belonging to an object of type Test (ob is an instance of the class Test ) which is called o.
Line 30 passes an object as a parameter to the meth method.
Line 25 calls the Test constructor with initializing parameters that get assigned to the member variables a and b.

Returning Objects

An object is a custom data type. We saw that a method can take an object as a parameter (previous example, line 30). Similarly, an object can also be the return value of a method.


Recursion

A recursive method is a method that calls itself.
For example, a method that calls itself upon the previous result of calling itself.
Factorial:
  5! = 5 * 4 * 3 * 2 * 1
Note that factorial 0 = 1 by definition.

Recursion with an array

Which method calls which method in line 7?

Notes:


Stack and Heap

The stack is the part of memory that provides speed, and primitives are loaded onto the stack.
The heap is the part of memory that affords capacity for custom types. The heap is slower but more versatile.
When we create an object with the new operator, the Java virtual machine allocates memory for that object on the heap.
Class members that are static are available separate from the heap.

Question: Why is it possible for a recursive method to cause the stack to overrun?

ENCAPSULATION

Stack Class and Access Control

The Java virtual machine has its own stack, as does the underlying operating system. However, sometimes the application program needs to implement a stack for the application.

The following program uses the Stack class, which is part of the java.lang package: http://java.sun.com/j2se/1.4.2/docs/api/java/util/Stack.html

The output is:

Stack in mystack1:
9
8
7
6
5
4
3
2
1
0
Stack in mystack2:
19
18
17
16
15
14
13
12
11
10

 


Access Control: modifiers

Access Control: Summary

What can be made private? How about an entire class? No. A private class would allow no access and would be useless. There are only two access levels for a class: public or the default, which is accessible within the package.

If you declare a class to be public:

Class Specifier within the package outside the package
public X X
default (undeclared) X  

In Week 8, we will learn more about packages.

For now, let's focus on access levels to class members.

http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html

Controlling Access to Members of a Class: Four Levels

Encapsulation: One of the benefits of classes is that classes can protect their member variables and methods from access by other objects. Why is this important? Well, consider this. You're writing a class that represents a query on a database that contains all kinds of secret information, say employee records or income statements for your startup company.

Certain information and queries contained in the class, the ones supported by the publicly accessible methods and variables in your query object, are OK for the consumption of any other object in the system. Other queries contained in the class support the operation of the class--such as an "internal engine"--but should not be used by objects of another type. You want to protect secret information from, say, programmers in other departments in your company. Or, you want to keep your program stable while third parties make calls into your code using application programming interfaces (API calls) you expose. 

In Java, you can use access specifiers to protect both class variables and methods. You use the access specifier as part of your declaration.
The Java language supports four distinct access levels for member variables and methods: private, protected, public, and, if left unspecified, package.

The following chart shows the access level permitted by each specifier.  

Class Member Specifier class subclass package world
private X      
protected X X
limitation
X  
public X X X X
package X   X  

The class column indicates whether the class itself has access to the member defined by the access specifier.
A class always has access to its own members.
The subclass column indicates whether subclasses of the class (regardless of which package they are in) have access to the member.
The package column indicates whether classes in the same package as the class (regardless of their parentage) have access to the member.
The world column indicates whether all classes have access to the member.

Public

The easiest access specifier is public. Any class, in any package, has access to a class's public members. Declare public members only if such access cannot produce undesirable results if an outsider uses them. There are no personal or family secrets here; this is for stuff you don't mind anybody else knowing.

To declare a public member, use the keyword public. For example,

package Greek;

public class Alpha {
    public int iampublic;
    public void publicMethod() {
        System.out.println("publicMethod");
    }
}

Let's rewrite our Beta class one more time and put it in a different package than Alpha and make sure that it is completely unrelated to (not a subclass of) Alpha:

package Roman;

import Greek.*;

class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iampublic = 10;       // legal
        a.publicMethod();       // legal
    }
}

As you can see from the above code snippet, Beta can legally inspect and modify the iampublic variable in the Alpha class and can legally invoke publicMethod.

Private

The most restrictive access level is private. A private member is accessible only to the class in which it is defined. Use this access to declare members that should only be used by the class. This includes variables that contain information that if accessed by an outsider could put the object in an inconsistent state, or methods that, if invoked by an outsider, could jeopardize the state of the object or the program in which it's running. Private members are like secrets you never tell anybody.

To declare a private member, use the private keyword in its declaration. The following class contains one private member variable and one private method:

class Alpha {
    private int iamprivate;
    private void privateMethod() {
        System.out.println("privateMethod");
    }
}

Objects of type Alpha can inspect or modify the iamprivate variable and can invoke privateMethod, but objects of other types cannot.
For example, the Beta class defined here:

class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamprivate = 10;      // illegal
        a.privateMethod();      // illegal
    }
}

cannot access the iamprivate variable or invoke privateMethod on an object of type Alpha because Beta is not of type Alpha.

When one of your classes is attempting to access a member variable to which it does not have access, the compiler prints an error message similar to the following and refuses to compile your program:

Beta.java:9: Variable iamprivate in class Alpha not 
accessible from class Beta.
        a.iamprivate = 10;     // illegal
         ^
1 error

Also, if your program is attempting to access a method to which it does not have access, you will see a compiler error like this:

Beta.java:12: No method matching privateMethod()
found in class Alpha.
        a.privateMethod();         // illegal
1 error

New Java programmers might ask if one Alpha object can access the private members of another Alpha object. This is illustrated by the following example. Suppose the Alpha class contained an instance method that compared the current Alpha object (this) to another object based on their iamprivate variables:

class Alpha {
    private int iamprivate;
    boolean isEqualTo(Alpha anotherAlpha) {
        if (this.iamprivate == anotherAlpha.iamprivate)
            return true;
        else
            return false;
    }
}

This is perfectly legal. Objects of the same type have access to one another's private members. This is because access restrictions apply at the class or type level (all instances of a class) rather than at the object level (this particular instance of a class).

Note: this is a Java language keyword that refers to the current object. For more information about how to use this see The Method Body.


Package

The package access level is what you get if you don't explicitly set a member's access to one of the other levels.
The package access level allows classes in the same package as your class to access the members.
This level of access assumes that classes in the same package are trusted friends.
The existence of inheritance outside the package does not grant access: subclasses that are not in the package do not have access.
This level of trust is like that which you extend to your closest friends but wouldn't trust even to your family.

For example, this version of the Alpha class declares a single package-access member variable and a single package-access method. Alpha lives in the Greek package:

package Greek;

class Alpha {
    int iampackage;
    void packageMethod() {
        System.out.println("packageMethod");
    }
}

The Alpha class has access both to iampackage and packageMethod. In addition, all the classes declared within the same package as Alpha also have access to iampackage and packageMethod. Suppose that both Alpha and Beta were declared as part of the Greek package:

package Greek;

class Beta {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iampackage = 10;     // legal
        a.packageMethod();     // legal
    }
}

Beta can legally access iampackage and packageMethod as shown.


Protected [Note: Limitation on Subclasses]

Protected access means the members of all the following have access:

Use the protected access level when it's appropriate for a class's subclasses to have access to the member, but not unrelated classes.
Protected members are like family secrets--you don't mind if the whole family knows, and even a few trusted friends, but you hide your family secrets from outsiders in the world at large.

To declare a protected member, use the keyword protected. First, let's look at how the protected specifier affects access for classes in the same package. Consider this version of the Alpha class, which is now declared to be within a package named Greek, and which has one protected member variable and one protected method declared in it:

package Greek;

public class Alpha {
    protected int iamprotected;
    protected void protectedMethod() {
        System.out.println("protectedMethod");
    }
}

Now, suppose that the class Gamma was also declared to be a member of the Greek package (and is not a subclass of Alpha).
The Gamma class can legally access an Alpha object's iamprotected member variable and can legally invoke its protectedMethod:

package Greek;

class Gamma {
    void accessMethod() {
        Alpha a = new Alpha();
        a.iamprotected = 10;    // legal
        a.protectedMethod();    // legal
    }
}

That's pretty straightforward. Now, let's investigate how the protected specifier affects access for subclasses of Alpha.

Let's introduce a new class, Delta, that derives from Alpha but lives in a different package--Latin. The Delta class can access both iamprotected and protectedMethod, but only on objects of type Delta or its subclasses. The Delta class cannot access iamprotected or protectedMethod on objects of type Alpha.
The Delta class has access to what Delta inherits as a subclass of Alpha, but Alpha itself is protected from encroachment by its subclass in a foreign package.
accessMethod
in the following code sample attempts to access the iamprotected member variable on an object of type Alpha, which is illegal, and on an object of type Delta, which is legal.
Similarly, accessMethod attempts to invoke an Alpha object's protectedMethod, which is also illegal:

package Latin;

import Greek.*;

class Delta extends Alpha {
    void accessMethod(Alpha a, Delta d) {
        a.iamprotected = 10;    // illegal
        d.iamprotected = 10;    // legal
        a.protectedMethod();    // illegal
        d.protectedMethod();    // legal
    }
}

If a class is both a subclass of and in the same package as the class with the protected member, then the class has access to the protected member.


Access example with a stack (Review)

http://java.sun.com/j2se/1.4.2/docs/api/java/util/Stack.html

The output is:

Stack in mystack1:
9
8
7
6
5
4
3
2
1
0
Stack in mystack2:
19
18
17
16
15
14
13
12
11
10

TestStack does not have access to the private array called stck in the Stack class.
Does TestStack have access to the tos property?
What visibility do the push and pop methods have?


static and final

The modifier keywords include

http://java.sun.com/docs/books/tutorial/reflect/class/getModifiers.html

static

The HelloWorld.java program is the first place we saw the keyword static.
 The main() method must be static because the Java Virtual Machine needs to call the main() method BEFORE any objects exist.

If a class has a static member (variable or method), then that method is independent of an object.
Static members exist before the coming and going of objects. They are in a different place in memory than the instance variables.
In the sense of their always being there, they are outstanding or pre-standing or standing by (standing in Latin is static).
Static members are efficient for memory: there is only one copy, no matter how many objects exist, Java stores static values in a separate place.

Static Variables and Methods

final

http://java.sun.com/docs/books/tutorial/java/nutsandbolts/finalVariables.html

Final Variables

Constant

A constant variable is a variable which is assigned a value once and cannot be changed afterward (during execution of the program). The compiler optimizes a constant for memory storage and performance.

Examples of constants

You can declare a variable in any scope to be final (in the glossary). The value of a final variable cannot change after it has been initialized. Such variables are similar to constants in other programming languages.

To declare a final variable, use the final keyword in the variable declaration before the type:

final int aFinalVar = 0;

The previous statement declares a final variable and initializes it, all at once. Subsequent attempts to assign a value to aFinalVar result in a compiler error. You may, if necessary, defer initialization of a final local variable by declaring the local variable and initializing it later:

final int blankfinal;
. . .
blankfinal = 0;

A final local variable that has been declared but not yet initialized is called a blank final.

http://java.sun.com/docs/books/tutorial/java/javaOO/final.html

String class (continued)

The output is:

First String
Second String
First String and Second String

The output is:

Length of strOb1: 12
Char at index 3 in strOb1: s
strOb1 != strOb2
strOb1 == strOb3

Command-line args

The output is:

args[0]: sky
args[1]: is
args[2]: blue
args[3]: 4
args[4]: you

Quiz

  1. Which tokens does the compiler use to locate and define the scope of any variable?
  2. What is a constructor?
  3. When you create a class, must you include a constructor? Why or why not?
  4. What is overloading and why is it useful?
  5. In what sense is an array like an object?
  6. In what sense is an array different from other objects?
  7. What are you likely to need to know about an array, and how can you find out that piece of information?
  8. Why does HelloWorld.java make the main() method static?
  9. Which keyword do you use to declare a constant?
  10. What is access control and why is it important?
  11. Which has more access specifiers: the class or its members?
  12. What do the public and private modifiers do?
  13. Which access specifier does the most hiding?
  14. Which access specifier grants access to the class, to its subclasses in any package, as well as to the package but at the same time denies subclasses in a foreign package the ability to tamper with their superclass directly?
  15. Which access specifier applies by default (even if you do not specify any access specifier)?
  16. What is recursion and why is it sometimes an advantage?
  17. Can a method accept an object as an argument?
  18. Under which circumstances does your if statement require curly braces?

Homework Assignment

Write a program that illustrates inheritance, uses access specifiers, and provides "getters and setters". For example, a Salary class might have a private setSalary() and a public getSalary(). This class might work with two subclasses of Employee, Machinist and Manager, and only Machinist has a bonus property.