Java Classes Tutorial

by Dimitris Tasios
316 views

In this article, we will learn about one of the most fundamental concepts of Java: Java Classes. This article will only cover Java Classes, not the Objects created from classes.

1. Introduction

Java is an Object-Oriented Programming language, which means that everything in Java is made to reflect real-life objects and entities. For instance, a class named Car would represent a car and a List would represent a list of elements in the actual world.

2. Java Classes

Java Classes represent entities with some characteristics (fields) which are vital to the class. They can also perform actions (methods), providing functionalities to the class. Lastly, we can use those classes to create (constructors) as many Objects as we need.

Perhaps, it’s would be a better idea to see all that in an example. Let’s assume we wanted to make a Robot. Our Robot would have a name, a primary color for its body and a preferred language to speak. Also, the Robot would be able to introduce themselves, greet us, and perform a simple math operation.

2.1 Defining Our Robot Class

Firstly, let’s create the Robot class. In Java, there can be only one public class, whose name must be the name as the name of the file. We can have as many non-public classes as we want. Additionally, by convention, class names start with a capital letter. As a result, this file would be named Robot.java. So far, we have the following code:

// Declared in Robot.java
public class Robot {

}

As you can see, we create Java Classes with the class keyword. The access modifier of the class would impact its usability by other classes; a stricter access modifier would mean that the class could be used by fewer classes. In our case, a public class can be used by any other class that exists in Java.

2.2 Creating a Robot Object

Java Classes need to be constructed in order to be used. By constructing a class, we create a new object from the class which can be used in our programs. The construction process can include the initialization of a few characteristics (fields) of the class.

Right now, despite the Robot class being essentially empty, we can still create a Robot object, thanks to the default constructor that all classes have. This constructor takes no arguments and would initialize all fields with their default values. If we included any constructor, we would not have that constructor but we could define it manually as such (inside the Robot class):

// Declared in Robot.java
public class Robot {

    // default constructor if we do not define any other constructors; otherwise we would have to create it on our own
    public Robot() {

    }

    // a custom-made constructor
    public Robot(String name, String color, String language) {
        
    }
}

We are going to use the second constructor in the next section.

2.3 Giving Identity to Our Robot Class Through Class Fields

Moving on, we can begin adding the characteristics we mentioned for our Robot. Any Robot has the following three characteristics:

  • A name that describes the name of the Robot and differentiates it from other robots.
  • A color representing its main body color.
  • Lastly, a language for when it performs actions.

Let’s add those to the code, as such:

// Declared in Robot.java
public class Robot {

    enum RobotLanguages {
        ENGLISH, SPANISH, GREEK
    }

    enum RobotColors {
        BLACK, WHITE, RED, BLUE, GREEN, YELLOW, PURPLE, PINK, ORANGE, BROWN, GRAY
    }

    // fields; the characteristics of a robot
    String name;
    RobotColors color;
    RobotLanguages language;

    // default constructor if we do not define any other constructors; otherwise we would have to create it on our own
    public Robot() {

    }

    // a custom-made constructor
    public Robot(String name, RobotColors color, RobotLanguages language) {
        this.name = name;
        this.color = color;
        this.language = language;
    }
}

Let’s see what we have added:

  • Line 4: We added an enum for all supported languages of a Robot. By using enums, we make sure that we cannot pass an invalid language that the Robot cannot understand. For instance, if the language was a String, we could pass any random String as the robot’s language, which is not valid.
  • Line 8: By following the same logic for the robot’s language, we define the robot’s color as an enum as well.
  • Line 13-15: We define the main characteristics of a Robot as fields. Every Robot will have these fields from now on.
  • Line 23-27: By using this constructor, we can create a Robot object with specific characteristics, by initialising all fields of the Robot class. The keyword this is used to refer to a variable that belongs to the class, rather than a method. For example, this.name referes to the field name of the Robot class, while the name after the “=” refers to the name that is passed as an argument to the constructor. We could avoid using the this keyword, if the argument had a different name that the field, like so:
    public Robot(String n, String color, RobotLanguage language) {
        name = n;
        this.color = color;
        this.language = language;
    }

2.4 Providing Functionality to Our Robot Through Class Methods

Lastly, it’s time to give some life to our robots, by setting up a few methods inside the Robot class:

  • Firstly, an introduce() method, which announces the robot’s name and color in the robot’s language.
  • An setLanguage(RobotLanguages newLanguage) method that updates the robot’s spoken language to newLanguage.
  • Lastly, a calculate(double operand1, double operand2, RobotOperations operation) that performs the arithmetic operation between the two operands and announces the result. We are going to create another enum named RobotOperation for this.

Let’s add all these into our class, one by one.

2.4.1 The introduce() Method

Starting with the first method we want to add, we have to take into account the 3 different languages the Robot can speak. So, every time a Robot talks, we have to cover the same phrase in all languages. So, we will create two private methods that will help introduce translate the color and language fields. The reason they are private is that those two methods are only useful inside the Robot class, since they are helper functions, so we hide them from other classes. This is another OOP concept called Abstraction.

The introduce() method is the following:

    public void introduce() {
        switch (this.language) {
            case GREEK:
                System.out.println("Γειά σας! Με λένε "+ name +" και έχω " + this.translateColor() + " χρώμα.\nΜιλάω " + this.translateLanguage() + ".");
                break;
            case ENGLISH:
                System.out.println("Hello there! My name is "+ name +" and my color is " + this.translateColor() + ".\nI speak " + this.translateLanguage() + ".");
                break;
            case SPANISH:
                System.out.println("Hola! Me llamo "+ name +" y soy " + this.translateColor() + ".\nHablo " + this.translateLanguage() + ".");
                break;
        }
    }

According to the robot’s language, the introduction is made in a different language. The helper functions are translateColor() and translateLanguage(). Both of the methods return a String of either color or language in the correct language. Starting with translateColor():

    private String translateColor() {
        String translatedColor = this.color.toString();

        switch (this.color) {
            case RED:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "κόκκινο";
                        break;
                    case ENGLISH:
                        translatedColor = "red";
                        break;
                    case SPANISH:
                        translatedColor = "rojo";
                        break;
                }
                break;
            case BLUE:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "μπλε";
                        break;
                    case ENGLISH:
                        translatedColor = "blue";
                        break;
                    case SPANISH:
                        translatedColor = "azul";
                        break;
                }
                break;
            case GRAY:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "γκρι";
                        break;
                    case ENGLISH:
                        translatedColor = "gray";
                        break;
                    case SPANISH:
                        translatedColor = "gris";
                        break;
                }
                break;
            case PINK:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "ροζ";
                        break;
                    case ENGLISH:
                        translatedColor = "pink";
                        break;
                    case SPANISH:
                        translatedColor = "rosado";
                        break;
                }
                break;
            case BLACK:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "μαύρο";
                        break;
                    case ENGLISH:
                        translatedColor = "black";
                        break;
                    case SPANISH:
                        translatedColor = "negro";
                        break;
                }
                break;
            case BROWN:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "καφέ";
                        break;
                    case ENGLISH:
                        translatedColor = "brown";
                        break;
                    case SPANISH:
                        translatedColor = "marrón";
                        break;
                }
                break;
            case GREEN:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "πράσινο";
                        break;
                    case ENGLISH:
                        translatedColor = "green";
                        break;
                    case SPANISH:
                        translatedColor = "verde";
                        break;
                }
                break;
            case WHITE:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "άσπρο";
                        break;
                    case ENGLISH:
                        translatedColor = "white";
                        break;
                    case SPANISH:
                        translatedColor = "blanco";
                        break;
                }
                break;
            case ORANGE:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "πορτοκαλί";
                        break;
                    case ENGLISH:
                        translatedColor = "orange";
                        break;
                    case SPANISH:
                        translatedColor = "naranja";
                        break;
                }
                break;
            case PURPLE:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "μωβ";
                        break;
                    case ENGLISH:
                        translatedColor = "purple";
                        break;
                    case SPANISH:
                        translatedColor = "morado";
                        break;
                }
                break;
            case YELLOW:
                switch (this.language) {
                    case GREEK:
                        translatedColor = "κίτρινο";
                        break;
                    case ENGLISH:
                        translatedColor = "yellow";
                        break;
                    case SPANISH:
                        translatedColor = "amarillo";
                        break;
                }
                break;
        }
        return translatedColor;
    }

Despite looking overwhelming due to its size, translateColor() is quite simple. Depending on the robot’s color and language, the method returns the appropriate word for that color in that language. Due to the fact that there are 3 languages and 11 colors, there are 33 cases, which explains the size of that method. And, because we are combining switch statements with enums, we can be sure that we do not forget any enum value.

Similarly, albeit smaller, translateLanguage() is defined as such:

    private String translateLanguage() {
        String translatedLanguage = this.language.toString();

        switch (this.language) {
            case GREEK:
                translatedLanguage = "Ελληνικά";
                break;
            case ENGLISH:
                translatedLanguage = "English";
                break;
            case SPANISH:
                translatedLanguage = "Español";
                break;
        }

        return translatedLanguage;
    }

2.4.2 The setLanguage(RobotLanguages newLanguage) Method

In order for this function to make sense, we have the language field private. By doing so, we cannot access that field directly. This is where setLanguage comes in; thanks to it, we can change the language.

    // fields; the characteristics of a robot
    String name;
    RobotColors color;
    private RobotLanguages language;

// ....

    public void setLanguage(RobotLanguages newLanguage) {
        if(this.language != newLanguage) {
            this.language = newLanguage;
        }
    }

Now, you might be wondering “why are doing that instead of simply declaring language as public“. The reason we use a set method is that this way, we can do additional checks or operations when setting the language field. For example, we could have the Robot announce the change of language with a System.out.println() or check whether the current language is the same as the newLanguage and not perform any actions, since it would be unnecessary.

Normally, all fields would have setter and getter functions, but for the sake of brevity, we will not include all those methods.

2.4.3 The calculate(double operand1, double operand2, RobotOperations operation) Method

This method calculates the result of the operation between the two double numbers and announces the result in the appropriate language. The operation is an enum named RobotOperations which is defined as such:

    enum RobotOperations {
        ADD, SUBTRACT, MULTIPLY, DIVIDE
    }

Just like all the enums in Robot, we are ensuring that only acceptable arithmetic operations are provided to the Robot.

The calculate(...) method is the following:

    public void calculate(double operand1, double operand2, RobotOperations operation) {
        double result = 0;

        switch (operation) {
            case ADD:
                result = operand1 + operand2;
                break;
            case SUBTRACT:
                result = operand1 - operand2;
                break;
            case MULTIPLY:
                result = operand1 * operand2;
                break;
            case DIVIDE:
                result = operand1 / operand2;
                break;
        }

        switch (this.language) {
            case GREEK:
                System.out.println("Το αποτέλεσμα είναι " + result);
                break;
            case ENGLISH:
                System.out.println("The result is " + result);
                break;
            case SPANISH:
                System.out.println("El resultado es " + result);
                break;
        }
    }

You might notice that there isn’t any check for division with zero. That’s because we won’t get an exception for that if we are dealing with float or double numbers, but either:

  • Infinity when dividing a positive number with zero.
  • -Infinity when dividing a negative number with zero.
  • Or, NaN when dividing zero with zero.

3. Conclusion

By now, you should have a solid understanding of Java Classes. You can find the source code on our GitHub page.

4. Sources

[1]: Classes, Oracle

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.

Related Posts