![]()
Object-Oriented
Programming Basics 1
Topics covered include :
Java Classes
Java is an object-oriented programming language. Objects are useful for representing just about anything imaginable. A particular object may have fields and methods associated with it. The fields of an object are the characteristics of the object and hold the object's 'state'. Non-constant (i.e. non-'final') fields may be modified either directly from a reference to the object, or via a method.
However, access restrictions on fields and methods may limit their accessibility to external classes.
If a field is not specified as private or public it takes the default value of 'protected' - in effect this means that the field is accessible only to classes within the same package. If public, it is accessible to all classes. If private, it is only directly accesible within the same class. The same applies to methods.
If class A has a field called x that is public we can reference it from class B with a.x - assuming that a is an instance of class A (or if field x is protected and class B is in the same package as class A). We can do the same thing for methods. Generally, however, fields are accessed through 'accessor methods' whose names generally start with 'get' (or 'is' when returning a boolean value) and 'set'.
The methods of a class define it's 'behaviour' - what it knows how to do.
Java objects are described by a Java class file that is compiled from the source file. At run-time when a class is instantiated, the constructor of the class is executed to initialize the object, including the values of its fields.
The following code gives an example of a Java class :
public class Person {private String name;
// Constructorpublic Person(String name) {this.name = name;}
public String getName() {return name;}
public void setName(String newName) {name = newName;}}
This class has one field (name), a constructor, and two methods. The methods in this class are for getting and setting the value of the field (they are 'accessor methods').
Inheritance - extending a class
One powerful capability of Java, and other object-oriented programming languages, is inheritance. Classes may extend other classes in order to inherit the capabilities of the parent class (also called 'superclass') and extend the features of that class with extra or modified fields and methods.
The following class extends our Person class to add extra information and capabilities; it is a more specialised class, a more specialised type of Person. We shall call it TaskPerson.
public class TaskPerson extends Person {private String taskType;
// Constructorpublic TaskPerson(String name, String taskType) {super(name);this.taskType = taskType;}
public String getTaskType() {return taskType;}
public void setTaskType(String newType) {taskType = newType;}}
This class does not specify anything having to do with the 'name' field but because it extends the Person class, it inherits that field as well as the methods used to access it.
Notice that the first line of the constructor for TaskPerson calls the constructor of the superclass (i.e. parent class) with the appropriate name parameter. When using the keyword super to refer to the superclass, that statement must be the first statement of the method.
Now let's create a third class. This class will also extend class Person; we shall call it RolePerson.
public class RolePerson extends Person {private String roleType;
// Constructorpublic RolePerson(String name, String roleType) {super(name); // call superclass constructorthis.roleType = roleType;}
public String getName() {return "RolePerson Name --> " + super.getName();}
public String getRoleType() {return roleType;}
public void setRoleType(String newRole) {roleType = newRole;}}
Notice that both child classes call the superclass's constructor from their constructor. Note that even if no call to a superclass constructor is explicitly written in the source code, a call to the no-argument (no-parameter) constructor of the superclass is put into the compiled class file by the compiler. This is so that the inherited fields will be initialised.
The two classes TaskPerson and RolePerson both extend class Person. That is, they inherit the fields and methods of class Person but add extra functionality and so are more specialised. An arrow pointing to the parent class is standard UML notation to indicate an inheritance relationship. We can say that 'class TaskPerson extends class Person'. |
A class may be the parent for a child class and at the same time be a child of another class. Just as with human relationships, a person is a child of some humans and a parent to others.
Java allows 'Single Inheritance' which means that a parent class can have many children but that, crucially, each child can have only one parent. This is the case with our three classes as shown in the diagram above. Thus, classes in Java form a tree-like hierarchy. At the top of this hierarchy in Java is class Object. Hence, class Object is the only class without a parent and is termed the 'root' of the hierarchy tree. Any class that does not explicitly extend another class implicitly extends class Object.
A number of terminologies exist for talking about the inheritance relationship :
|
When we say that RolePerson extends Person, we could also say that RolePerson sub-classes Person, or that RolePerson is derived from (i.e. inherits from) class Person; in all cases the meaning is the same.
If we take a look at the member fields of class RolePerson we see that one is inherited from the superclass Person and one is defined by the RolePerson class itself.
Class RolePerson - Member Fields
| We could make a similar table for methods. In such tables, some members or methods might be inherited from the parent of the parent, or the parent of the parent of the parent ... |
With these three classes, we are ready to build a simple Java program that creates some instances of these classes. You can think of classes as blueprints or designs, and objects (i.e. instances) as the end of production-line real thing.
Using our class hierarchy
Since everything in Java must belong to a class, we will create a fourth class to create instances of our 3 Person type classes and put them to use. This fourth class has just one method: a public static main() method. (If a field or method is static, it does not belong to any particular instance of the class of which it is a part.) A public static main() method that takes an array of String arguments and has no return value is a special method that may be called by the Java Virtual Machine's interpreter to begin execution of a Java program.
public class PersonProgram {public static void main(String[] arguments) {Person[] people = new Person[3];
people[0] = new Person("person0");people[1] = new TaskPerson("person1", "person1 task");people[2] = new RolePerson("person2", "person2 role");
for (int pInd=0; pInd<people.length; ++pInd) {Person person = people[pInd];System.out.println("Person #" + pInd+":");System.out.println(" Name: " + person.getName());if (person instanceof TaskPerson) {System.out.println(" Task: " + ((TaskPerson)person).getTaskType());}if (person instanceof RolePerson) {System.out.println(" Role: " + ((RolePerson)person).getRoleType());}} // end: for loop}}
Class Casting
This program creates an array of type Person and then fills the array with new instances of various types of Person object. Then a simple for loop is used to examine each of the elements of the array. Various information extracted from the Person objects is printed to the standard output stream of the system.
If this program is executed from a command line terminal or command prompt, the information is simply displayed in the same command line window. If run in TJI, you will see the output in the 'System In / Out' frame.
First, the getName() method is called to obtain and print the name of each Person. This works the same for all types of Person object. Then, if the current Person object is a TaskPerson object, its task type is obtained by calling the getTaskType() method and printed. This only works for the Person object in position 1, since that is the only TaskPerson object. The getTaskType() method can only be called from an instance of the TaskPerson class.
However, the array in this program is not an array of type TaskPerson, it is an array of type Person. Therefore, if we come across an instance of TaskPerson, we can first make the program treat the instance as an instance of TaskPerson instead of an instance of class Person. We can do this by 'class casting' - after checking the class type with the instanceof operator.
To cast an object as an instance of another object, you just put the name of the desired class type in parentheses just before the object variable in your code. This allows us to temporarily treat the second entry in the array as a TaskPerson so that we can find out its task type. Be careful with casting, though. If you cast an object to a type that it actually is not, Java will generate a ClassCastException, which will cause your program to halt unless it is specifically caught.
The last part of our example program displays the role type of the Person object if it is an instance of class RolePerson.
Polymorphism - method overriding
The above program demonstrates inheritance. Also demonstrated is another powerful object-oriented concept known as polymorphism. Polymorphism is similar to inheritance, but has a special twist. It is shown here with the getName() method of the RolePerson class. The RolePerson class inherits the method getName() from its superclass, but it reimplements it so that if that method is called on an instance of RolePerson, specialized behavior for that class is exhibited instead. This is known as method overriding (reimplementing a method).
In our example program, we have an array of type Person. Even though the call to the getName() method is done on an object that is treated as an instance of class Person (rather than a TaskPerson or RolePerson instance), the specialised getName() method of the RolePerson class is invoked if the object happens to be an instance of that class - even without first class-casting the instance to class type RolePerson.
Top level class Object has a toString() method that returns a String designed to be a useful description of the state of the object. Most derived classes overide this method to produce a more meaningful return description for their own case. So this is a good example of method overriding.
A call to the superclass using the keyword 'super' is also possible in a method that is overrided. For example :
public String toString() {String s=super.toString();s=s + "\n" + getName(); // "\n" is the 'new-line' characterreturn s;}
Finally, the output of this program is :
Person #0:Name: person0Person #1:Name: person1Task: person1 taskPerson #2:Name: RolePerson Name --> person2Role: person2 role
| Download and run ...
An improved version of the example program is available for download as a TJI project from the 'Resources' page of our web site. Simply download the zip file and then choose 'Project Import' from the 'Project' menu. Select the zip file and the project will be imported and setup automatically. Now simply click on the 'Run' button to compile and run. |
Note : This document was partly based on material by Bradley Kjell at the Central Connecticut State University.