18-JULY-2005 This lecture covers the reading in Chapter 7: Methods and Classes (continued)
|
REVIEW
POLYMORPHISM
JVM MEMORY STRINGS ACTION ITEMS |
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.
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.
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)
The array class provides methods that are static.
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/reflect/Array.html
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);
}
}
The three statements below are equivalent to each other.
if(n==1) return 1; // one-line if statement
// 2-line if statement if(n==1) return 1;
// 4-line simple if statement if(n==1) { return 1; }
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 argumenthue
from the member variablehue
(and so on with the other arguments). Writinghue = 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 thethis
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.
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 thesuper
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:
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).
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.
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
This example compares two string objects by using the equals() method and passing it a parameter that is a reference to a string object.
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?
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.
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.
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.
Which method calls which method in line 7?
Notes:
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?
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
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
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
limitationX 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.
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 thanAlpha
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 theiampublic
variable in theAlpha
class and can legally invokepublicMethod
.
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 theiamprivate
variable and can invokeprivateMethod
, but objects of other types cannot.
For example, theBeta
class defined here:class Beta { void accessMethod() { Alpha a = new Alpha(); a.iamprivate = 10; // illegal a.privateMethod(); // illegal } }cannot access the
iamprivate
variable or invokeprivateMethod
on an object of typeAlpha
becauseBeta
is not of typeAlpha
.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 errorAlso, 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 errorNew Java programmers might ask if one
Alpha
object can access the private members of anotherAlpha
object. This is illustrated by the following example. Suppose theAlpha
class contained an instance method that compared the currentAlpha
object (this
) to another object based on theiriamprivate
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 usethis
see The Method Body.
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 theGreek
package:package Greek; class Alpha { int iampackage; void packageMethod() { System.out.println("packageMethod"); } }The
Alpha
class has access both toiampackage
andpackageMethod
. In addition, all the classes declared within the same package as Alpha also have access toiampackage
andpackageMethod
. Suppose that bothAlpha
andBeta
were declared as part of theGreek
package:package Greek; class Beta { void accessMethod() { Alpha a = new Alpha(); a.iampackage = 10; // legal a.packageMethod(); // legal } }
Beta
can legally accessiampackage
andpackageMethod
as shown.
Protected access means the members of all the following have access:
- the class itself
- subclasses
- all classes in the same package
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 theAlpha
class, which is now declared to be within a package namedGreek,
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 theGreek
package (and is not a subclass ofAlpha
).
TheGamma
class can legally access anAlpha
object'siamprotected
member variable and can legally invoke itsprotectedMethod
: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 ofAlpha
.Let's introduce a new class,
Delta
, that derives fromAlpha
but lives in a different package--Latin
. TheDelta
class can access bothiamprotected
andprotectedMethod
, but only on objects of typeDelta
or its subclasses. TheDelta
class cannot accessiamprotected
orprotectedMethod
on objects of typeAlpha
.The
Delta
class has access to whatDelta
inherits as a subclass ofAlpha
, butAlpha
itself is protected from encroachment by its subclass in a foreign package.in the following code sample attempts to access the
accessMethodiamprotected
member variable on an object of typeAlpha
, which is illegal, and on an object of typeDelta
, which is legal.
Similarly,accessMethod
attempts to invoke anAlpha
object'sprotectedMethod,
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.
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?
The modifier keywords include
http://java.sun.com/docs/books/tutorial/reflect/class/getModifiers.html
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.
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/finalVariables.html
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
. 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
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
The output is:
args[0]: sky args[1]: is args[2]: blue args[3]: 4 args[4]: you