Java ProgrammingLearn About Class Access Levels & Garbage Collection in Java

Learn About Class Access Levels & Garbage Collection in Java

Java

In the previous article we discussed class access levels, and how they can be used to hide and show class fields to the code that is calling them. A useful implementation of this feature is to create private fields for your values, and use public methods to manipulate those fields according to your rules. For example, a student may have an integer age field. But you don’t want uses of your class to accidentally set a student’s age to a negative value, or a considerably large number, or even zero. For this purpose you use a method (called setter) that will handle this work, and ensure that correct values have been supplied:

[Student.java]

public class Student {
    private int _age;
    public String setAge(int a){
        if (a > 0 && a <= 50){
            this._age = a;
        }
        else {
            return "Invalid value for age";
        }
        return null;
    }
    
}

[MainClass.java]

public class MainClass {

    public static void main(String[] args) {
       Student s = new Student();
       String result = s.setAge(0);
        System.out.println(result);
    }
}

Now if you run the above code, you will see “Invalid value for age” printed at the output screen. This way we avoid having incorrect values for our class fields by protecting them through setter properties.

Now what if you want your class to output a value, but you want this value to be in a specific form. For example, a student may have a first name and a last name. Each of those has its own string field. But you don’t want the first name and last name fields to be called separately, instead, you want the full name of the student to be printed, perhaps to avoid confusion. To achieve this, you create a getter method that will be used to do this work, while keeping the first and last name fields private. Consider the following:

[Student.java]

public class Student {
    private String _firstname;
    private String _lastname;
    
    public void setFrstName(String s){
        if (s != ""){
            this._firstname = s;
        }
    }
    
    public void setLastName(String s){
        if (s != ""){
            this._lastname = s;
        }
    }
    
    public String getName(){
        return this._firstname + " " + this._lastname;
    }
}

[MainClass.java]

public class MainClass {

    public static void main(String[] args) {
       Student s = new Student();
       s.setFrstName("Jack");
       s.setLastName("Black");
        System.out.println(s.getName());
    }
}

In this example, we have created two setters for the first and last name of the student, respectively. Then we created a getter for the full name. Notice that you cannot have access to the first and last name fields in the main() method. You can only print the student name by calling the getName() method, which will concatenate the first and last name fields of the object, separated by a space.

Class initialization

Recall from a previous post when we talked about object initialization, and how variables have default values (integers bear zeroes and strings are just empty strings). Classes also have their own initializers. You can initialize a class by placing any block of code preceded by the keyword static. This will make method/property available to the class immediately without having to instantiate an object to be able to use it. Consider the following:

[StaticClass.java]

public class StaticClass {
    public static int counter = 1;
}

[MainClass.java]

public static void main(String[] args) {
        StaticClass.counter += 1;
        StaticClass objStatic1 = new StaticClass();
        System.out.println(objStatic1.counter);
    }

The output of this code will be 2. Let’s discuss it step by step. You created a class called StaticClass, and added an integer field called counter, and set its value to 1. But you defined this field to be static. That makes the field available immediately to the class, so you can increment this field by 1 just by referencing its class. Now any instance of the StaticClass will have access to “counter” with it’s new value: 2.

Static methods and blocks are most commonly used when you want to share code among different instances of the same class. One practical example is in a design pattern (a way of writing code), where you must ensure that only one instance of the class is available throughout the code. A way to do this is to add a static field in the class that will get incremented as soon as the class is instantiated. Now you can check for the value of this field before creating a new class instance to ensure that only one instance of the class is active.

Java Programming Course for Beginner From Scratch

Garbage collection

Creating more and more objects using the new keyword will eventually eat up all the heap memory you have available. Because of this, Java provides the Garbage Collector. This is code that runs periodically to check for unreferenced objects, and removes them from the heap.

An unreferenced object is an object that is not available anywhere in the code. For example:

new StaticClass();

This statement is perfectly legal Java code. However, the new instance of StaticClass was not assigned to any variable. This object will be cleaned by the garbage collector.

Objects also loose their reference when, for example, they are created in a method and this method returns or when they get assigned to null. For example:

StaticClass obj = new StaticClass();
obj = null;

The first line creates a referenced object of the StaticClass called obj, while the second line removes this reference by assigning the variable to null.

Introducing inheritance

Inheritance is an integral part of object oriented programming. Think about cars. A car is a generic term, why? Because numerous types of it exist: sports cars, trucks, SUV’s, and others. All those car types have roughly the same characteristics as a car; all of them have tires, doors, brakes, gas pedals, steering wheels…etc. however, each type provides a slightly different implementation of some aspects, or perhaps a totally new feature. For example, a sports car my have only two seats instead of the typical four seats in a traditional car. A truck may have up to eighteen tires and so on. If this model was implemented in Java, we’d say a truck class, a sportsCar class, and an suv class are all inheriting from the base class car.

Inheriting from classes, sometimes called extending, means acquiring all the properties and methods of a specific class, and adding upon them or even overriding them. Take a look at the following example, which illustrates inheritance:

[Car.java]

public class Car {
    public int tires;
    public String color;
    public int seats;
    
    public Car(){
        this.tires = 4;
        this.color = "red";
        this.seats = 4;
    }
}

[SportsCar.java]

public class SportsCar extends Car {
    
}

[MainClass.java]

public static void main(String[] args) {
        SportsCar objCar = new SportsCar();
        System.out.println(objCar.color);
        System.out.println(objCar.seats);
        System.out.println(objCar.tires);
    }

if you run this code you will see the following output:

red
4
4

Let’s see what’s going on here. First we created out base class Car. It has a number of fields that a typical car would have. Then we created another class, SportsCar. This time, we used the extends keyword followed by Car. This informs Java that we are inheriting from Car. This makes all the non-private fields in the Car class available to the SportsCar class. To prove this, we instantiated objCar from SportsCar. As you can see it has access to all the fields that were defined in it’s parent class: Car.

Conclusion

In this article, we examined class initialization by adding code preceded with the static keyword. We learned that such code becomes available immediately to the class and do not need an instance object to use it. Hence, it can be shared among different instances as it is defined at the class level. Then you were introduced to the concept of Garbage Collection in Java, and how this helps free memory periodically. Finally, we started discussing one of the most important aspects of object oriented programming: inheritance. You saw how inheritance can be mapped to real world examples, like a car model. You also created your first parent and child classes to prove that a subclass (child class) has access to all non-private fields declared in its parent.

We’ve just scratched the surface here; inheritance is a lot more than just reusing code of one class by its children. In the next article, you will see more ways to use the fields and methods of the parent class. You will also delve more into object oriented aspects of Java. See you then.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Exclusive content

- Advertisement -

Latest article

21,501FansLike
4,106FollowersFollow
106,000SubscribersSubscribe

More article

- Advertisement -