GNU Java Training Wheels 1.1: Tutorial 9 Mapping class variables to instance variables (also known as properties) and functions to methods

Next: Tutorial 10 Object arrays, Previous: Tutorial 8 Accessing functions and class variables from another class, Up: J.T.W. Tutorials [Contents][Index]

### 4.9 Tutorial 9 Mapping class variables to instance variables (also known as properties) and functions to methods

#### 4.9.1 Elementary classes: using a single class for everything

For the purpose of the text that follows, O.O.P. stands for Object Oriented Programming.

Question 4.9.1: Study, compile and run the following code:

    class PersonDriver1
    begin
        classVar String homersName = "Homer Simpson";
        classVar int    homersAge  = 40; // Homer's age in years

        classVar String fredsName  = "Fred Flintstone";
        classVar int    fredsAge   = 45; // Fred's age in years

        classVar String darthsName = "Darth Vader";
        classVar int    darthsAge  = 55; // Darth's age in years

        function void growHomer()
        begin
            homersAge = homersAge + 1;
        end
        function void growFred()
        begin
            fredsAge = fredsAge + 1;
        end
        function void growDarth()
        begin
            darthsAge = darthsAge + 1;
        end

        function void knightHomer()
        begin
            homersName = "Sir " + homersName;
        end
        function void knightFred()
        begin
            fredsName = "Sir " + fredsName;
        end
        function void knightDarth()
        begin
            darthsName = "Sir " + darthsName;
        end

        function void printHomer()
        begin
            System.out.println("I am " + homersName + ", my age is " + homersAge);
        end
        function void printFred()
        begin
            System.out.println("I am " + fredsName + ", my age is " + fredsAge);
        end
        function void printDarth()
        begin
            System.out.println("I am " + darthsName + ", my age is " + darthsAge);
        end

        beginMain
            growHomer();
            knightHomer();
            printHomer();
            printFred();
            printDarth();
        endMain
    end

Question 4.9.2: By copying the pattern established in the existing code write a some new class variables to represent a new person called Barak Obama. Note that he was born August 4, 1961 so at the time of writing this manual he is 54 years old.

Question 4.9.3: Then write some functions to work with this new person.

Question 4.9.4: Finally call those functions from the `main` `function`.

#### 4.9.2 Improved classes: one object per class

As your program gets large (say over 1000 lines) then it becomes no longer practical to put all of your code in the same class. So it is natural to put each piece of related code in its own class. The J.T.W. programming language supports splitting a class into its constituent methods and having one file for each method. Simply use the `include` directive and J.T.W. will include the file for you like so:

`include "a.method";`

will include a method named `a`.

Question 4.9.5: Study, compile and run the following code: Each of these classes can be put in their own file. For each class `X`, this class can be put into a file called `X.jtw`. However for the purposes of this tutorial you will probably find it easier to merge all of the classes into the same file into a file called `PersonDriver2.jtw`

    class Homer
    begin
        classVar String name = "Homer Simpson";
        classVar int    age  = 40;) // Homer's age in years

        function void grow()
        begin
            age = age + 1;
        end
        function void knight()
        begin
            name = "Sir " + name;
        end
        function void print()
        begin
            System.out.println("I am " + name + ", my age is " + age);
        end
    end

    class Fred
    begin
        classVar String name = "Fred Flintstone";
        classVar int    age  = 45;) // Fred's age in years

        function void grow()
        begin
            age = age + 1;
        end
        function void knight()
        begin
            name = "Sir " + name;
        end
        function void print()
        begin
            System.out.println("I am " + name + ", my age is " + age);
        end
    end

    class Darth
    begin
        classVar String name = "Darth Vader";
        classVar int    age  = 55;) // Darth's age in years

        function void grow()
        begin
            age = age + 1;
        end
        function void knight()
        begin
            name = "Sir " + name;
        end
        function void print()
        begin
            System.out.println("I am " + name + ", my age is " + age);
        end
    end

    class PersonDriver2
    begin
        beginMain
            Homer.grow();
            Fred.knight();
            Homer.print();
            Fred.print();
            Darth.print();
        endMain
    end

Question 4.9.6: By copying the pattern established in the existing code write a new class to represent Barak Obama.

Question 4.9.7: Call the functions from the `main` `function` of the driver class.

#### 4.9.3 True O.O.P.: more than one object per class

To allow for more than one object per class, most if not all class variables needs to be made into what are called instance variables (or more simply and more commonly known as properties) and most if not all functions need to be made into what are called methods.

Question 4.9.8: Study, compile and run the following code:

    class Person
    begin )
        /*
        * NOTE: the use of the "property" keyword here instead of the
        * "classVar" keyword.
        */
        property String name; // Person's full name
        property int    age;  // Person's age in years

        /*
        * NOTE: the use of the "method" keyword here instead of the
        * "function" keyword.
        */
        method void grow()
        begin
            age = age + 1;
        end

        method void knight()
        begin
            name = "Sir " + name;
        end

        method void print()
        begin
            System.out.println("I am " + name + ", my age is " + age);
        end

        beginMain

            var Person h = new Person();
            h.name = "Homer Simpson";
            h.age  = 40;

            var Person f = new Person();
            f.name = "Fred Flintstone";
            f.age  = 45;

            var Person d = new Person();
            d.name = "Darth Vader";
            d.age  = 55;

            h.grow();
            h.knight();
            h.print();
            f.print();
            d.print();
        endMain
    end

In the above code, note the use of three references h, f and d.

Question 4.9.9: By copying the pattern established in the existing code add some code to the `main` `function` add some code to create a new person for Barak Obama.

#### 4.9.4 A common design pattern: `private` properties,`public` `constructor` and `public` getters

A common design pattern in Java and one that I present for you in the following code is to make all of the properties of a class effectively read-only to all client classes by making all of the properties private and providing non-private getter methods for getting the values of the properties. It is possible for the original class to change the values of the properties but other classes (such as PersonTest below) are not capable of doing this, without calling a method of the original class such the grow and knight methods of the Person class. Finally an additional thing known as a `constructor` is used to ensure that objects are initialized with meaningful values for their properties.

Question 4.9.10: Study, compile and run the following code:

    class Person
    begin

        private property String name;
        private property int    age; // Age in years
    )
        //
        // NOTE: Getter methods
        //
        public method String getName()
        begin
            return name;
        end

        public method int getAge()
        begin
            return age;
        end

        public constructor Person(String aName, int anAge)
        begin
            this.name = aName;
            this.age  = anAge;
        end

        public method void grow()
        begin
            age = age + 1;
        end

        public method void knight()
        begin
            name = "Sir " + name;
        end

        public method void print()
        begin
            System.out.println("I am " + name + ", my age is " + age);
        end
    end

    class PersonDriver3
    begin
        beginMain
            //
            // NOTE: In the following constructor calls the age and name are set by the constructor
            //
            var Person h = new Person("Homer Simpson",40);
            var Person f = new Person("Fred Flintstone",45);
            var Person d = new Person("Darth Vader",55);

            h.grow();
            h.knight();
            h.print();
            f.print();
            d.print();

            h.name = "Luke Skywalker";)                 // ERROR: name is private
            h.age = h.age + 1;                          // ERROR: age is private

            System.out.println("name=" + h.name);       // ERROR: name is private
            System.out.println("age="  + h.age);        // ERROR: age is private

            System.out.println("name=" + h.getName());  // OK: getter is non-private
            System.out.println("age="  + h.getAge());   // OK: getter is non-private
        endMain
    end

Note that you will have to remove the error lines from the above file for the code to compile.

Question 4.9.11: By copying the pattern established in the existing code add some code to the `main` `function` to create a new person called Hillary Clinton. Hillary Clinton was born on October 26, 1947 so at the time of writing this manual she was 68 years old

#### 4.9.5 Comparing strings

Question 4.9.12: Add a method unknight() which removes the "Sir " title if he has one. One trap for young players in J.T.W. or Java is to use the operator == to compare strings like so:

    function boolean myCompare(String a, String b)
    begin
        return a == b;) // Works but not as expected!
    end

It compiles without error, but doesn’t give you the result you were expecting. Instead you need to use the equals method of the String class like so:

    function boolean myCompare(String a, String b)
    begin
        return a.equals(b);
    end

More generally, if x and y are a references to objects, then x == y returns whether or not x and y are pointing to the same object, whereas x.equals(y) returns whether or not the contents of the objects referred to by x and y are equal. The meaning of the word contents varies from class to class, but in the case of strings it means that the strings contain the same data.

You will also find the `String` class’ substring and (`toUpperCase` or `toLowerCase`) methods useful here too. See the class `String` in the package `java.lang` at http://docs.oracle.com/javase/1.5.0/docs/api for more details of these two methods.

#### 4.9.6 The `null` value for references

As soon as you learn how to use references you need to know that all reference variables could conceivably hold the value `null`, meaning no value. In particular when properties are themselves references as you will discover in Tutorial 11, then those properties are initialized to `null` by default. Object arrays that you will learn about in Tutorial 10 using the second of two initialization syntaxes are also initialized to `null` by default.

#### 4.9.7 Why the toString method is better than any other method or

property for debugging

If x is a reference to a class `X` (including this for the current class) and if `m` is a `method` of `X` and `p` is a `property` of `X`, and if `x` is currently `null`, then the following lines result in a `NullPointerException` being thrown when executed:

    x.p;
    x.m();

whereas if `x` is `null` then

    System.out.println(x); and
    System.out.println("x=" + x);

prints out, respectively:

    null, and
    x=null.

If `x` is not `null`, it calls

    System.out.println(x.toString());
    System.out.println("x=" + x.toString());

so these expressions are safer to use than any other method or property in situations where `x` might be null. The syntax of the `toString` `method` is as follows:

    public method String toString()
    begin
        // Code goes here...
    end

Importantly for reasons which will be explained later the toString method must be declared with `public` visibility. For other properties and methods to be used safely with `null` references you need to wrap a conditional if construct around the calling of the `method` or `property` like so for properties:

    if (x != null)
    then begin
        System.out.println(x.p);
    end

or like so for methods:

    if (x != null)
    then begin
        System.out.println(x.m());
    end

Therefore the `toString` `method` is more convenient than any other `method` or `property`.

Question 4.9.13: Change the `print` `method` above from a `method` that prints out to the screen to a `method` called `toString` that returns a `String`.

Question 4.9.14: Call the `toString` `method` instead of the `print` methods in the `main` `function`.

Next: Tutorial 10 Object arrays, Previous: Tutorial 8 Accessing functions and class variables from another class, Up: J.T.W. Tutorials [Contents][Index]