This is Lesson 1.8 of the Java programming course.
Example Java class to model an animal
Earlier a class called Animal
was specified capable of storing an animal's name, gender and age, and also capable of providing that information upon request. You will therefore start to write the Java source code for such a class. This new class, along with other related classes you will also develop in this course to represent zookeepers and visitors, can be thought of as being part of the core system of the zoo application. For reasons which will become clear later, it is useful to separate the core system classes (which are non-graphical) from those which will be part of the graphical user interface[1]. You will therefore create two sub-packages under virtualzoo
called core
and ui
to contain these classes respectively.
Right-click on the virtualzoo package node, select New | Java Package... and enter virtualzoo.core in the Package Name entry field:
Click the Finish button. Now repeat the same process by right-clicking the virtualzoo
package node again and creating another package called virtualzoo.ui
, after which the IDE should look like that shown below:
Ensure your package structure matches that in the illustration above before continuing. To summarise, you currently have three separate packages which will be used throughout this course for the following purposes:
- Package
virtualzoo
will only contain the classVirtualZoo
. This class will become the "launcher" of your application. - Package
virtualzoo.core
will contain the various non-graphical "core" classes which model the zoo application. - Package
virtualzoo.ui
will contain the various graphical user interface classes which liaise with the core system classes.
You are now in a position to create the Animal
class, so right-click on the virtualzoo.core
package node, select New | Java Class... and enter the class name Animal
into the Class Name box:
When you click the Finish button a new tab will appear for the Java source code for the new class:
The source code for Animal currently looks like this:
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package virtualzoo.core; /** * * @author Tony */ public class Animal { }
You will recall that so far there are three required attributes (i.e., name, gender, and age) and three behaviours (i.e., being able to provide each of the three attribute values to other objects that can make use of it).
Declaring attributes
The attributes of a class are stored in instance variables.
- The term instance refers to the fact that there are potentially any number of animals that may need to exist, and each individual animal object will be an instance of the
Animal
class (i.e., an actual entity in its own right where its values may be different to other instances). - The term variable refers to the fact that its value can be set to something, and possibly change over time (its age, being a prime example).
You can think of a variable as being a storage location for a value of some kind. In Java there are two categories of variable, as follows:
Primitive variables: This kind of variable holds values directly. The most used primitives are:
int
: used to store an integer value (i.e., a whole number), which may be either positive or negative. Examples: 3, 187, -2408.double
: used to store a numerical value with decimal places, which may be either positive or negative. Examples: 4.5, 527.0, -56.9.boolean
: used to store a "true/false" or "yes/no" value. The value of a boolean[1] variable can only be either true or false[2].
Reference variables: This kind of variable holds a reference, which you can think of as a "pointer") to an object (i.e., an instance) of a class. This could be either an object of a class supplied with Java or an object of a class that was written by you or someone else. Some example Java supplied classes are:
String
: objects of this type contain a "string" of characters, i.e., a piece of text.Date
: objects of this type contain a calendar date value.File
: objects of this type provide a means of gaining access to a file or directory.
Note the different naming convention to distinguish between primitive and reference types; primitive types start with a lower-case letter (e.g., int) while reference types start with an upper-case letter (e.g., String). This is because reference types are always classes, which should start with a capital letter according to Java conventions.
While most of Java revolves around classes and objects, primitive types exist primarily for efficiency reasons for frequently used numerical and logical types.
When you declare an instance variable you have to decide which type to use; firstly, whether it should be a primitive or a reference type, and then which specific primitive or reference type. An animal's name is always a string of characters, so the String
class would be a natural choice. An animal's age, measured in whole years, would most readily be stored using the primitive int
type. For an animal's gender you will, for the time being, also use a String
(which will be either "m" or "f").
Type the statements marked in bold below inside the class block part of the Animal source file:
package virtualzoo.core; public class Animal { // Declare instance variables to hold an animal's attributes private String name; // the animal's name private String gender; // the animal's gender ("m" or "f") private int age; // the animal's age in years // Rest of class will go here... }
- The keyword
private
means that the instance variable is only available from within this class – nothing else has direct access to it. This is very important to prevent another part of the application from modifying its value to a nonsensical value (for example, by making age a negative amount). Most of your instance variables should be private, although there are occasional exceptions to this. - The term
String
refers to the type of value that this variable will contain.String
is itself a class that is built-in to the Java language and which is capable of storing a piece of text. Therefore, this variable is a reference to aString
object. As previously noted, becauseString
is a class it adheres to the convention of starting with a capital letter. You will use other built-in classes later in the course. - The term
name
is simply the identifying name of this instance variable, which will be used to store the animal's name. The other two instance variables are namedgender
andage
. Note the initial letters are lower-case in compliance with the naming conventions for variables. - The semi-colon character
;
signifies the end of a Java statement. As mentioned, you must end all Java statements (except those which comprise a block) with a semi-colon. - Some comments, indicated by two forward slashes, have been included for each instance variable. These are completely optional, but if you include them, they must be either after the semi-colon or on a separate line of their own.
- The
int
keyword means that the instance variable named age will contain an integer value, that is, a whole number. Remember thatint
is a primitive type rather than an object reference type.
You will now define a constructor for the class. Constructors are used to create individual instances (i.e., objects) of the Animal
class to represent each separate animal that you need to do something with. When creating an instance, you can also specify the initial values of its variables. Add the statements marked in bold:
package virtualzoo.core; public class Animal { // Declare instance variables to hold an animal's attributes private String name; // the animal's name private String gender; // the animal's gender ("m" or "f") private int age; // the animal's age in years // Define constructor public Animal(String myName, String myGender, int myAge) { name = myName; gender = myGender; age = myAge; } // Rest of class will go here... }
- The keyword
public
means this this constructor is allowed to be invoked from objects in any package. - The term
Animal
matches the name of the class – you must do this when defining a constructor. - You then must have a pair of normal brackets ( ), although it is possible for there to be nothing inside them. In this case, however, there is a comma-separated list of arguments (sometimes called parameters) that define the incoming variables with each preceded by their type, into the constructor. In other words, when some other part of the application needs to create an Animal object, they must supply two
String
objects (for the name and gender) followed by anint
value (for the age). These incoming objects and value are supplied in the variables namedmyName
,myGender
andmyAge
. - There is another pair of opening and closing braces to mark the beginning and end of the constructor block.
- The statement
name = myName;
is known as an assignment. TheString
object referenced bymyName
(which was the first argument passed into the constructor) is assigned to the instance variablename
. This is done so that the incoming value is remembered once the constructor block has finished. - Likewise,
myGender
is assigned to the instance variablegender
, andmyAge
is assigned to the instance variableage
. - The references and values for
myName
,myGender
andmyAge
only exist for the duration of the constructor and are lost once it completes. They are said to be local to the constructor. However,name
,gender
andage
were defined as instance variables outside of the constructor and are therefore global, that is, available throughout the class (but not outside the class because they were defined to be private).
So far, you have written a class which is capable of instantiating (i.e., creating) one or more objects (i.e., instances) of the Animal
class, and you can supply the values for each instance.
To show how you could use this new class, modify the VirtualZoo
class as follows (changes marked in bold):
package virtualzoo; import virtualzoo.core.Animal; public class VirtualZoo { public static void main(String[] args) { Animal bruno; bruno = new Animal("Bruno", "m", 4); } }
Note the following:
- The statement
import virtualzoo.core.Animal;
is needed to import theAnimal
class you just developed because it exists within a different package to theVirtualZoo
class. IfAnimal
was defined in the same class, then animport
statement would not be needed. You will learn more about importing classes later. - The statement
Animal bruno;
declares a variable calledbruno
of typeAnimal
, although at this point an object for it does not yet exist. - The statement
bruno = new Animal("Bruno", "m", 4);
creates anAnimal
object and assigns it to the reference variablebruno
. Thenew
keyword tells Java to invoke the constructor of the class which follows. Inside the brackets two Strings and an int are sent to the constructor, representing the actual name, gender and age for this particular object. Strings are always defined by enclosing them inside double-quotation marks, although these do not form part of the string. Here, you have specified that the animal's name is Bruno, that it is male, and that it is four years old. - At this stage, it is not obvious what type of animal Bruno is, but for the time being this does not matter. Later in the course you will see how to specify different kinds of animal.
It is very common to combine the two declaration and instantiation statements into a single line, as follows:
public static void main(String[] args) { Animal bruno = new Animal("Bruno", "m", 4); }
You can run this application right now (by clicking the green arrow button in the toolbar) and the Output window should show that it completed successfully:
The Animal
object referenced by bruno
existed for the duration of the run and was then discarded when the program ended.
At this stage, of course, the program is not very useful as there is currently no way of getting the values out since the instance variables were declared to be private
.
You will now add the functionality needed to retrieve the data from each instance.
Declaring Java functionality
The behaviours of a class are defined by writing methods[1], where each method performs one piece of functionality. In an application, different objects send messages to each other, where each message results in a method being invoked. Some methods retrieve and return information while other methods might perform some internal processing such as modify some data.
You will now write a method to retrieve the animal's name. In the Animal class add the lines marked in bold:
[1]In some other languages methods are known as functions. Java always uses the term method.
package virtualzoo.core; public class Animal { // Declare instance variables to hold an animal's attributes private String name; // the animal's name private String gender; // the animal's gender ("m" or "f") private int age; // the animal's age in years // Define constructor public Animal(String myName, String myGender, int myAge) { name = myName; gender = myGender; age = myAge; } // Define instance methods // Return the animal's name public String getName() { return name; } // Rest of class will go here... }
- The keyword
public
means that the method is available to be invoked by other objects from any package. - The term
String
means that this method returns a reference to aString
object. Not all methods have to return something, but if they do you must define the type of thing that is being returned. If nothing is to be returned you must instead use the keywordvoid
. - The term
getName
defines the name of the method; it is followed by a pair of empty opening and closing brackets since this particular method does not need any arguments to be passed into it. If you have a method that does require arguments to be passed in you would follow a similar syntax as was used for the constructor earlier. - Note that since the method returns an instance variable it follows the naming convention of starting with
get
followed by the name of the instance variable (name
), except that the 'n' of name is now capitalised since it is not the very first letter of the method name. - Inside the method block the keyword
return
is a built-in command used to return (i.e., pass back) something to whoever made the request. In this case you are passing back a reference to the name instance variable object.
You will now define two additional methods to return the gender and the age:
public class Animal { // Declare instance variables to hold an animal's attributes private String name; // the animal's name private String gender; // the animal's gender ("m" or "f") private int age; // the animal's age in years // Define constructor public Animal(String myName, String myGender, int myAge) { name = myName; gender = myGender; age = myAge; } // Define instance methods // Return the animal's name public String getName() { return name; } // Return the animal's gender public String getGender() { return gender; } // Return the animal's age public int getAge() { return age; } // Rest of class will go here... }
The getGender()
method is very similar to getName()
except that it returns the gender
instance variable, which is also an object of type String
.
The getAge()
method is likewise similar, returning the int
value of the age
instance variable.
Trying out the new methods
Modify the VirtualZoo
class to invoke the three methods you just defined after the bruno
object has been instantiated:
public class VirtualZoo { public static void main(String[] args) { Animal bruno = new Animal("Bruno", "m", 4); // Output bruno's details String brunoName = bruno.getName(); System.out.println(brunoName); String brunoGender = bruno.getGender(); System.out.println(brunoGender); int brunoAge = bruno.getAge(); System.out.println(brunoAge); } }
The statement String brunoName = bruno.getName();
causes the getName()
method to be invoked upon the bruno
object. Since this method returns a String
you need to assign it to a String
object, which here is called brunoName
:
- The notation to invoke a method is to specify the name of the object, followed by a dot, followed by the name of the method including its brackets (which here are empty).
- Once this completes the
String
it returns is assigned to theString
referencebrunoName
.
The statement System.out.println(brunoName);
sends a line to the Output window containing the textual value of the variable brunoName
.
- The
getGender()
method is similarly invoked and assigned to aString
reference calledbrunoGender
, which is then also sent to the Output window. - The
getAge()
method is also similarly invoked and assigned to the int variable calledbrunoAge
, which is sent to the Output window.
If you run the project, you should see the following in the Output window:
It is possible to combine the invocation of the getter methods inside the statements which send to output:
public static void main(String[] args) { Animal bruno = new Animal("Bruno", "m", 4); // Output bruno's data System.out.println(bruno.getName()); System.out.println(bruno.getGender()); System.out.println(bruno.getAge()); }
The way the above works is by processing methods from the inside out; that is, the inner most pair of brackets relates to the getName()
method, which is nested inside another pair of brackets which relates to the println()
method. The processing follows this sequence:
- The
getName()
method is invoked upon thebruno
object reference. - The
getName()
method returns aString
reference (for the animal's name). - The
String
reference returned becomes the argument to the Java suppliedprintln()
method, so assuming theString
"Bruno" was returned it would have the effect of doing this:System.out.println("Bruno");
- The
String
Bruno is sent to the output window (which is what theprintln()
method does).
You can enhance the output by combining the variables with some explanatory text:
public static void main(String[] args) { Animal bruno = new Animal("Bruno", "m", 4); // Output bruno's data System.out.println("Name: " + bruno.getName()); System.out.println("Gender: " + bruno.getGender()); System.out.println("Age: " + bruno.getAge()); }
Note how you can use the + operator to concatenate together pieces of text, so the output should now show:
You can create as many Animal objects as you like:
Animal bruno = new Animal("Bruno", "m", 4); Animal cuddles = new Animal("Cuddles", "f", 2); Animal someDog = new Animal("Fido", "m", 3); Animal aGiraffe = new Animal("Gilly the Giraffe", "f", 7);
Each object so created has its own independent state (i.e., set of instance variable values), so you need to specify which one when invoking a method upon it:
String x = cuddles.getGender(); // what is cuddle's gender? int ga = aGiraffe.getAge(); // how old is Gilly the Giraffe?
As you have seen, you can name your objects anything you like, but it makes sense to use names which directly relate to the object, and which are easily remembered.
Building your projects
When you run your projects, NetBeans will automatically recompile any updated Java class files for you. Sometimes, however, it is helpful to run the compilation process without running the project, perhaps just to see if you have any errors. To do this, right-click on the VirtualZoo
project node and select Clean and Build. Alternatively, there is an icon on the toolbar that looks like a hammer and brush that performs the same action.
You may want to clean and build your projects periodically as you work your way through this course. Make sure the last line of the Output window says BUILD SUCCESSFUL. If the build failed, then there will be some preceding lines pinpointing the classes and statements that are in error.
This completes Section 1. In Section 2 we will cover object-oriented concepts.
Lesson 2.1 Object-oriented concepts