In the previous article, Java Data and Data Types, common data types are introduced. Programmers use these types to define variables to track states of a program (for example, car speed). In this article, we study Java data types in more detail and explain two broad categories in Java’s type system, primitive and references types, and how they are represented in memory.

This is a very fundamental topic in Java and paramount in learning Java.

Primitive Types

Most of the types mentioned in the previous article types are primitive types, which are the most basic data types in java. Primitive types are: byte, short, int, long, float, double, char, and boolean.

Primitive types also have the properties that they are fixed sized, such that all variable of the same type use the same amount of memory, and “indivisible”, such that they are not composed of other types.

Conceptually, computer memory is a set of storage cells, each with an address. For example, the figure below shows a block of memory with address from 100 to 104

When a variable of a primitive type is declared, int myInt = 10; for example, this variable represents a memory location. In the figure below, myInt represent memory location 102 and we can use myInt to store to and read from this memory location. In addition, when the program is compiled, all occurrences of myInt is replaced with memory address 102. For example, when we write the statement myInt = 10;, it literally means, set the content of memory location 102 to integer 10.

Reference Types

Reference types are any class types and arrays. These include the String class, and any class you write. The reason that these are called reference types is because, in contrast to primitive types, a variable (memory location) of this type holds a memory address to the data, instead of the data itself. We give an example below.

Let’s say we have this statement in our program: String s = "Hello";

What this statement does is assign a memory location to s, but the location does not store the string "Hello", but the address of it, as shown in the figure below. In the figure, s represents memory address 101. However, at this location, the location of the string "Hello" is stored which is at location 150.

Also note that objects (the actual data) may take more than 1 memory locations. In fact, some data may take many memory locations (use lots of memory) as in a long array. One justification for storing references instead of the actual data is that since the compiler does not know how large the actual data will be when the program is executed, JVM has to find a memory location large enough for the data during runtime.

In the following code snippet, we are not copying the content of a to b, but only copying the address.

String a = "Hello";
String b = a;

Object Instantiation

Instantiation mean to create an object from a class. For example, the following code performs two instantiations: one of String and one of Person.

String s = "Hello";
Person p = new person();

Each of above actually take two steps. The first step is declaration, where a variable of the desired type is declared. The second step is the actual instantiation, where the object is created, as shown below.

Person p;         //declaration; p = null
p = new person(); //instantiation
p = null;         //reset the variable to null

After the first step (and before the second step) is performed, the variable p holds the value of null, which is a special value that can be assigned to variables of references types and means the variable does not point to any object. If we call any method or field of this variable at this point, we will get the error NullPointerException.

The second step does the following:

  1. Ask Java to find a block of memory large enough for the Person object
  2. Create the object
  3. Return the address of the object
  4. Put the address in varaible p

After the second step, methods of the object can be safely called.

Object of Other Objects

Often we have objects that are composed of other objects. For example, in the following code, we have a Person class, which contains another object of type String. The following figure shows how an object of Person class is presented in memory, when a variable, p, is declared.

class Person {
    int id;
    String name;

    public Person(int id, String name) {
        this.id = id;
        this.name = name;
    }
    //...
}

Person p = new Person(1, "John");

Note that arrays are also reference types. The following figure shows how an array of objects are stored.

String[] names = {"Abe", "Bob", "Cid"};