8.2 Java | Designing Classes & Making Objects

In this lesson I will be giving examples that show how classes are designed and how classes are used to make objects. Down below I will show a program that defines a Circle class that is used to make objects. The program will construct  3 circle objects that will have the radius of 1, 25, 125 and show their respective areas that are evaluated depending on the radius lengths. After that, the program will change the radius of the second circle object to 100 and display its new radius and area:

Table of Contents

Example 1

//Right below is main class
public class TestSimpleCircle {
    //Right below is main method
    public static void main(String[] args) {
        // Make a circle with radius 1
        SimpleCircle circle1 = new SimpleCircle();
        System.out.println("The area of the circle of radius " + circle1.radius + " is " + circle1.fetchArea());

        // Make a circle with radius 25
        SimpleCircle circle2 = new SimpleCircle(25);
        System.out.println("The area of the circle of radius " + circle2.radius + " is " + circle2.fetchArea());

        // Make a circle with radius 125
        SimpleCircle circle3 = new SimpleCircle(125);
        System.out.println("The area of the circle of radius " + circle3.radius + " is " + circle3.fetchArea());

        // Modify 2nd circle's radius to 100
        circle2.radius = 100; // or you can use circle2.setRadius(100)
        System.out.println("The area of the circle of radius " + circle2.radius + " is " + circle2.fetchArea());
    }
}

// Define the circle class with two constructors
class SimpleCircle {
    double radius;

    //Construct a circle with radius 1
    SimpleCircle() {
        radius = 1;
    }

    //Construct a circle with a specified radius
    SimpleCircle(double newRadius) {
        radius = newRadius;
    }

    //Return the area of this circle
    double fetchArea() {
    return radius * radius * Math.PI;
    }
    //Return the perimeter of this circle
    double fetchPermimeter() {
        return 2 * radius * Math.PI;
    }

    // Set a new radius for this circle
    void setRadius(double newRadius) {
        radius = newRadius;
    }
}

Output:
The area of the circle of radius 1.0 is 3.141592653589793 The area of the circle of radius 25.0 is 1963.4954084936207 The area of the circle of radius 125.0 is 49087.385212340516 The area of the circle of radius 100.0 is 31415.926535897932

You’ll notice that this Java program uses two classes; the main class TestSimpleCircle and SimpleCircle. The only purpose of the  TestSimpleCircle class is to test the second class SimpleCircle. Note that the a class is called a client when it uses another class. What does client exactly mean?

Let’s try to map the situation to a physical world scenario.

 

You go to a pastry shop and order a pastry. You get the pastry from the store pay for it and leave. You naturally call yourself a client of the store. So what did we understand from this?

 

The term client refers to any entity that requests a service from another entity. The client does not bother about how the entity providing the service actually provides the service – the client is happy as long as the service is available and fulfills its use case.

 

Hence, when a method M1 within a class calls another method M2 then M1 is a client of M2. Similarly when a class C1 requests service of C2 then C1 is a client of C2. [Source]

So when you run the Java program, the runtime system invokes the main method in the main class TestSimpleCircle.

Know that you can put 2 classes in one file, but only one class can be a public class. The reason why is simply because that’s how Java is designed:

Reason 1: A each public class must be kept in a separate file. This restriction makes it easy for a compiler for the Java programming language or an implementation of the Java virtual machine to find a named class within a package [Source]

 

Reason 2: It forces all Java code to be organized in a certain way, which in the long run helps improve code readability. The Java designers chose a strict approach that enforces their idea of good design practices, and this is part of that theme. Contrast that with the anything-goes attitude in Perl. [Source]

Continuing on the subject of public classes, know that the public class must be named the same as the file. So for the example above, the file name would be TestSimpleCircle.java, because the public class is called TestSimpleCircle. When the program is compiled, each class is compiled into a .class file. For example, when you compile the TestSimpleCircle.java program, you will obtain 2 class files: the TestSimpleCircle.class and SimpleCircle.class.

So the main class TestSimpleCircle contains the main method (line 4) that makes 3 circle objects. Note that the new operator is used whenever an object is made from a constructor. In this case new SimpleCircle() makes a object called circle1 with a radius of 1 (line 6), new SimpleCircle(25) makes an object called circle2 with a radius of 25 (line 10), and new SimpleCircle(125) makes an object called circle3 with a radius of 125 (line 14).

So by using the same method, we have obtained 3 similar objects (circle1, circle2, circle3) that differ only by the data assigned to them. The data field of the 3 circle objects can be accessed by using the object’s reference. Such as circle1.radius, circle2.radius, and circle3.radius would retrieve the object’s respective radius values. With that data, we are able to evaluate their areas by using the fetchArea() method (lines 38-39).  Again, the reference of the objects (circle1, circle2, circle3) can be used to invoke the fetchArea() method (lines 38-39) to find the area. Doing this looks like: circle1.fetchArea(), circle2.fetchArea(), circle3.fetchArea().

Lastly you can see in the above Java program that the radius of circle2 is altered to 100 in line 18, and circle2‘s new radius and area are displayed in the line 19.

*Note that the 3 circle objects are independent; meaning that they don’t affect each other. Also, the reference of the 3 circle objects are circle1, circle2, circle3.

Extra Notes:

 

Class and class type and class object v2

Notice that from the class SimpleCircle all the way at the bottom; you acquire the SimpleCircle type use 3 times (highlighted) to the left of the statements, and on the right part of the statement are the SimpleCircle Constructors that make 3 SimpleCircle Objects with data fields of 1, 25, and 125

class type and class object side by side

A constructor is composed of two parts. To the left of the statement is the type SimpleCircle and the name of the new object circle3. To the right of the statement is the constructor that makes the circle 3 object, using the new operator with SimpleCircle()and assigning the newly made object the datafield of 125.

Example 2

Know that there are many ways to write the same Java program. For instance; from Example 1 you can combine the two classes, TestSimpleCircle and SimpleCircle,  into one class. That is what I will be showing you in this example.

// Right below is the main class
public class SimpleCircle {
    // Right below the main method starts
    public static void main(String[] args) {
        // Make a circle object that has radius 1
        SimpleCircle circle1 = new SimpleCircle();
        System.out.println("The area of the circle with radius of " + circle1.radius + " is " + circle1.fetchArea());

        // Make a circle with radius 25
        SimpleCircle circle2 = new SimpleCircle(25);
        System.out.println("The area of the circle with radius of " + circle2.radius + " is " + circle2.fetchArea());

        // Make a circle with radius 125
        SimpleCircle circle3 = new SimpleCircle(125);
        System.out.println("The area of the circle with radius of " + circle3.radius + " is " + circle3.fetchArea());

        // Modify the radius of circle2 to 100
        circle2.radius =100;
        System.out.println("The area of teh circle with radius of " + circle2.radius + " is " + circle2.fetchArea());

    }	// main method ends here

    double radius; // make a radius variable, it is set to double type

    // Make a cirlce that has a radius of 1 by default
    SimpleCircle() {
        radius = 1;
    }

    // Make a circle that is given a specific radius
    SimpleCircle(double newRadius) {
        radius = newRadius;
    }

    // Make a method that uses an expression which returns the circle's area
    double fetchArea() {
        return radius * radius * Math.PI;
    }

    // Make a method that uses an expression which returns the circle's perimeter
    double getPerimeter() {
        return 2 * radius * Math.PI;
    }

    // Set a new radius for a circle object
    void setRadius(double newRadius) {
        radius = newRadius;
    }
}

Because the single main class (line 2) has a main method, we can make the Java interpreter execute the program. You’ll notice that the same method method is used in this example 2 as in example 1. This goes to show that just the addition of a main method to a class is all you need to test that class.

Example 3 + UML

In this next example I will be referring to an Laptop. Each Laptop is an object with many different states (power off or on, current time, current volume, etc.) and many different behaviors or actions (change Laptop time, change volume level, turn power on or off). You can use a class to model a Laptop’s functions. Here is a UML diagram that shows the Laptop class:

 

Laptop time: int The current time (12:00am to 12:00pm) for this Laptop. volumeLevel: int The current voluem level (0 to 10) of this Laptop. on: boolean Indicats whether the Laptop is powered on or off. +Laptop() Constructs a default Laptop object. +turnOn(): void Turns on this Laptop. +turnOff(): void Turns off this Laptop. +setTime(newTime: int): void Sets a new time for this Laptop. +setVolume(newVolumeLevel: int): void Sets a new volume for this Laptop. +increaseTime(): void Increases the time by 1 hour +decreaseTime(): void Decreases the time by 1 hour +volumeUp(): void Increases the volume by 1 +volumeDown(): void Decreases the volume by 1 The + sign indicates a public modifier

And here is the Java program modeled after the UML diagram above:

public class Laptop {

    //Below are the data fields
    int time = 1; // Default time is 1
    int volumeLevel = 1; //Default volume level is 1
    boolean on = false; // Laptop is off

    //Below is a constructor
    public Laptop() {
    }

    //turn on Laptop
    public void turnOn() {
        on = true;
    }

    //turn off Laptop
    public void turnOff() {
        on = false;
    }

    //set a new time for the Laptop
    public void setTime(int newTime) {
        if (on && newTime >= 0 && newTime <= 24)
            time = newTime;
    }

    //set a new volume for the Laptop
    public void setVolume(int newVolumeLevel) {
        if (on && newVolumeLevel >= 0 && newVolumeLevel <= 10)
            volumeLevel = newVolumeLevel;
    }

    //Increase the time by one hour
    public void increaseTime() {
        if (on && time < 24)
            time++;
    }

    //Decrease the time by one hour
    public void decreaseTime() {
        if (on && time > 0)
            time--;
    }

    //Increase the volume
    public void increaseVolume() {
        if (on && volumeLevel > 0)
            volumeLevel++;
    }

    //Decrease the volume
    public void decreaseVolume() {
        if (on && volumeLevel < 10)
            volumeLevel--;
    }
}

In the Laptop class, the methods and constructors are defined as public so they can be accessed from other classes. Note that the time and volume level do not change if the Laptop is not on to begin with. Before any change occurs, the values of the time and volume are checked so that they are in the correct range.

Example 3 | Part 2 | Making use of the public modifier

Now here’s another example that shows the Laptop class making two objects. (note that the public modifier used in front of the main class allows this program to fetch the methods used in the Laptop class from the program above, Laptop.java).

//main class below
public class TestLaptop {
	//main method below
	public static void main(String[] args) {
		//make a Laptop object
		Laptop laptop1 = new Laptop();
		laptop1.turnOn();				// Turn on object
		laptop1.setTime(6);				// Set new time
		laptop1.setVolume(7);			// Set new Volume
		
		//make a Laptop object
		Laptop laptop2 = new Laptop();
		laptop2.turnOn();				// Turn on Laptop object
		laptop2.increaseTime();			// Increase time by 1 hour
		laptop2.increaseTime();			// Increase time by 1 hour
		laptop2.volumeUp();				// Increase volume by 1 
		
		//Display the objects states
		System.out.println("laptop1's time is " + laptop1.time + " and volume level is " + laptop1.volumeLevel);
		System.out.println("laptop2's time is " + laptop2.time + " and volume level is " + laptop2.volumeLevel);
		
	}
}

Output:

"C:\Program Files (x86)\Java\jdk1.8.0_91\bin\java" -Didea.launcher.port=7532 "-Didea.launcher.bin.path=C:\Program Files (x86)\JetBrains\IntelliJ IDEA 2016.1.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\charsets.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\deploy.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\access-bridge-32.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\cldrdata.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\dnsns.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\jaccess.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\jfxrt.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\localedata.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\nashorn.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\sunec.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\sunjce_provider.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\sunmscapi.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\sunpkcs11.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\ext\zipfs.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\javaws.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\jce.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\jfr.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\jfxswt.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\jsse.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\management-agent.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\plugin.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\resources.jar;C:\Program Files (x86)\Java\jdk1.8.0_91\jre\lib\rt.jar;C:\Users\rock\IdeaProjects\HomeWork\out\production\HomeWork;C:\Program Files (x86)\JetBrains\IntelliJ IDEA 2016.1.3\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain TestLaptop laptop1's time is 6 and volume level is 7 laptop2's time is 3 and volume level is 2 Process finished with exit code 0

This program makes two objects on lines 6 & 12, invoking the methods on the objects to perform actions for setting and increasing the time and the volume levels. The program shows the state or status of the objects on lines 19-20. As you can see, the methods are invoked using such syntaxes like laptop1.turnOn()on line 7 and laptop1.time on line 19.


What's Your Opinion?