Java 11 Developer Certification - Objects and Classes - basics

November 30, 2020

What we are covering in this lesson

  1. Declaring and Instantiating Java Objects
  2. Garbage Collection
  3. Types of Garbage Collectors

Declaring and Instantiating Java Objects

A Java reference variable is used to address and manipulate an Object. As we all know, an object is an instantiation of a class, and a class is a custom-defined data type that contains attributes and methods available to its instances using the dot operator to access some of those members from these instances.

Declaring such a variable is same as declaring primitive data type variables, String objects and arrays, without the special constructs that those variables have.

Certain Rules apply like

  • Multiple variables can be declared in a single statement but they should be of same type like int a=0, b=1, c=2; or int a,b,c;
  • An Object is either known by the compiler or the current context, or needs an import statement, or a Fully Qualified Class Name, an FQCN, to satisfy the compiler.
Object o;   //FQCN not required since Object is java.lang class which is imported by default
java.util.ArrayList list;   //FQCN used

To instantiate an object, we use the new keyword, as we have already seen before. When we use the new keyword, it calls the special initialization method called constructor. For our own class, we can create our own constructor, or Java creates a default one for us. Alternative way of instantiating a new Object is by using the clone method.

We can initialize an object like Object obj = new Object(). This will call the java.lang.Object class constructor. The referenced address to this object in memory is passed to the variable obj.

There are multiple ways we can declare and initialize an object, as mentioned below.

//Multi-line declaration and initialization
Object obj;
obj = new Object();

Object obj1 = new Object();
Object obj1 = new Object(), obj2 = new Object();

//obj2 declared, obj1 declared and assigned to obj2 which is assigned to new Object reference
Object obj2, obj1 = obj2 = new Object();

//Valid since String is subtype of Object
Object obj1 = new Object(), s = new String("TestString");

Some invalid examples of declaration and instantiations are shown below.

Object a = b, b = new Object(); // Object b is not declared here
Object a = b = new Object();    // Object b is not declared here
String s = new String("test"), a = new Object(); // Object is not subtype of String
Object a = new Object(), String s = new String("TestString"); //Different types

Important thing to remember here is that we cannot define and instantiate classes of different types in the same statement, declaring different types for each, even if the different type is a subtype of the first type, like in the last invalid example.

Garbage Collection

One of the biggest advantanges of Java runtime environment (JRE) is that it frees the developers from the complexity of memory management by providing a garbage collector. The garbage collector scans for de-allocated references, and reclaims that memory. Garbage collection is a process that could have a big impact on your application’s performance, especially if your application processes large amounts of data. At some point you may need to examine and tune garbage collection options.

When we instantiate an object in Java the Java virtual machine (JVM) allocates memory from the heap to store the data required for the object. The address of this memory location is assigned to the declared variable. This memory stays allocated as long as a variable maintains a reference to it. We cannot de-allocate memory manually in Java, but we can de-reference an object by setting it to null or assigning a different reference to the variable, allowing the object which lost its reference to be available for garbage collection.

Objects declared locally and instantiated in method blocks, will automatically be de-referenced, when the method returns execution back to the calling thread unless the object is itself, the return value of the method. Objects never assigned to a variable, are immediately available for garbage collection.

Lets look at a simple code to understand when the JVM invokes its garbage collection mechanism

package maxCode.online.GC;

class TestClass {
    private String a = "a";
    private String b = "b";
 
    TestClass(String a, String b) {
        this.a = a;
        this.b = b;
    }
 
    public String toString() {
        return a + "-" + b;
    }
}

public class GarbageCollectionExample {
	public static void main(String[] args) {
        // Declare and instantiate some objects
        // aref is a reference to the 'a-z object'
        TestClass aref = new TestClass("a", "z");
 
        // bref is a reference to the 'first-last object'
        TestClass bref = new TestClass("first", "last");
 
        // cref is a reference to the 'start-end object'
        TestClass cref = new TestClass("start", "end");
 
        // References not assigned to any objects
        TestClass dref = null;
        TestClass eref = null;
 
        // any references to 'a-z object' no longer exist after statement
        aref = bref;
        System.out.println("aref has a reference to object : " + aref);
 
        //  aref, bref and dref variables reference the 'first-last object'
        dref = bref;
        System.out.println("dref has a reference to object : " + dref);
 
        // Assignments not in declarations occur right to left
        // eref, bref, cref variables all reference the 'start-end object'
        eref = bref = cref;
        System.out.println("eref has a reference to object : " + eref);
 
        // all references to 'start-end object' are set to null
        // making it eligible for garbage collection
        aref = dref = null;
        System.out.println("---------End-------------");
        System.out.println("aref has a reference to object : " + aref);
        System.out.println("bref has a reference to object : " + bref);
        System.out.println("dref has a reference to object : " + cref);
        System.out.println("dref has a reference to object : " + dref);
        System.out.println("eref has a reference to object : " + eref);
 
    }
}

Output

aref has a reference to object : first-last
dref has a reference to object : first-last
eref has a reference to object : start-end
---------End-------------
aref has a reference to object : null
bref has a reference to object : start-end
dref has a reference to object : start-end
dref has a reference to object : null
eref has a reference to object : start-end

The objects returning null at the end would have been eligible for garbage collection, when the program exited.

We can run java.exe with one of the following options to log some of the garbage collection output.

  • -Xlog:gc
  • -Xlog:gc* is more verbose than -Xlog:gc and will print any message that has the gc tag and any other tag.
  • -verbose:gc as an alias for -Xlog:gc.

Till Java 8, we can use the below GC commands and the output will be redirected to a file which will look like below.

VM Arguments: -XX:+PrintGCDetails 
              -XX:+PrintGCDateStamps 
              -Xloggc:C:\maxCode\GC.txt
Output:
Java HotSpot(TM) 64-Bit Server VM (25.73-b02) for windows-amd64 JRE (1.8.0_73-b02), built on Jan 29 2016 17:38:49 by "java_re" with MS VC++ 10.0 (VS2010)
Memory: 4k page, physical 8244304k(1617496k free), swap 16632912k(7886596k free)
CommandLine flags: -XX:InitialHeapSize=131908864 -XX:MaxHeapSize=2110541824 -XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC 
Heap
 PSYoungGen      total 37888K, used 2622K [0x00000000d6100000, 0x00000000d8b00000, 0x0000000100000000)
  eden space 32768K, 8% used [0x00000000d6100000,0x00000000d638f810,0x00000000d8100000)
  from space 5120K, 0% used [0x00000000d8600000,0x00000000d8600000,0x00000000d8b00000)
  to   space 5120K, 0% used [0x00000000d8100000,0x00000000d8100000,0x00000000d8600000)
 ParOldGen       total 86016K, used 0K [0x0000000082200000, 0x0000000087600000, 0x00000000d6100000)
  object space 86016K, 0% used [0x0000000082200000,0x0000000082200000,0x0000000087600000)
 Metaspace       used 2574K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 279K, capacity 386K, committed 512K, reserved 1048576K

Types of Garbage Collectors

There are different types of Garbage Collectors that can be used based on the code requirement, and those are tabulated below.

Garbage Collector Name VM Option to use Description Notes
Serial Collector -XX:+UseSerialGC The Serial Collector uses a single thread to perform all the Garbage Collection work Best suited for Single Processor machines
Parallel Collector -XX:+UseParallelOldGC The Parallel Collector has multiple threads that are used to speed up Garbage Collection Used for applications having medium or large sized datasets that run on multiprocessor or multi-threaded hardware
Garbage-First Collector (G1) -XX:+UseG1GC The G1 collector is a server style collector for multiprocessor machines with a large amount of memory. It meets GC pause-time goals with high probability, while achieving high throughput Default in Java 11
Z Garbage Collector -XX:+UseZGC ZGC is a scalable, low latency GC, performing all expensive work concurrently, without stopping the execution of application threads. Intended to be used for appication which require low latency (less than 10ms pause) and/or use a very large heap Introduced in Java 11
Concurrent Mark Sweep Collector(CMS) -XX:+UseConcMarkSweepGC The CMS was for apps which preferred shorter Garbage Collection pauses, and could afford to share processor resources with the GC Deprecated as of Java 9