Java is a typed language, which essentially means that every variable declared has a certain type associated with it. This type determines the value it can store. For example, an integer type can store non-fractional numbers. Also called a data type, this can grossly be divided into two categories: primitive and reference. Primitive types are the most common and form the basis of type declaration and reference types are those which are not primitive types. More on these reference types later in this programming tutorial; but first, a slight detour.
Looking to learn Java in a class or online course environment? Check out our list of the Top Online Courses to Learn Java to help get you started.
What are Static and Dynamic Types in Java?
A language is considered statically typed if the type of a variable declared is known prior to the compilation of code. For some languages, this typically means that the programmer needs to specify the type of the variable in code before using it (eg – Java, C, C++). Others offer a form of type inference that is able to deduce the type of a variable (eg – Kotlin, Scala, Haskell). The advantage of explicit type declaration is that trivial bugs are quickly caught in the early stages.
Dynamic typing, on the other hand, means programmers do not need to declare any type of variable and can just start using them. The type is decided dynamically according to the value it stores. This is a quicker way to code because a variable can store different types of values – for example, numbers and strings – without having to bother with their type declaration (eg – Perl, Ruby, Python, PHP, JavaScript). The type is decided on the go. Most scripting languages have this feature, primarily because there is no compiler to do static type-checking in any case. However, it makes finding a bug a bit difficult, especially if it is a big program, despite the fact that this type of script typically has smaller code, so bugs have fewer places to hide.
There are languages (such as Rascal) that adopt both approaches (static and dynamic). Interestingly, Java 10 has introduced the var keywords. A variable declared as var automatically detects its type according to the value it stores. However, note that, once assigned a value, the compiler designates its type during compilation. Later they are not reusable with another type down the line of code. Here is an example of how to use the var keyword in Java:
var iVar = 12; var dVar = 4,678; var cVar=”A”; var sVar = “Java”; var bVar = true;
What is the Difference Between a Primitive Type and Reference Type in Java?
In Java, since all non-primitive types are reference types, the classes which specify objects as an instance of the class are also deemed as reference types. To compare, here are the typical characteristics of primitive types vis-a-vis reference types:
- It can store values of its declared type.
- When another value is assigned, its initial value is replaced.
- There is a specific limit to its memory occupancy for all primitive types.
- They are initialized by default (numbers with 0 values, boolean with false values)
- They can be explicitly initialized during their declaration (int tot=10;)
- Local primitive type variables declared are never initialized, hence any attempt to use them prior initialization is not allowed in Java.
Some characteristics of reference types are as follows:
- All other variables except primitives are reference types.
- A reference type stores references or locations of objects in a computer’s memory. Such variables refer to the object in the program.
- An object or concrete instance of a class is created using a new keyword which follows a constructor call. A constructor is a special member function of a class used to create an object by initializing all the variables declared in the class with their respective default values or with values received as constructor arguments.
- A class instance is created by invoking the class constructor and there can be more than one.
- Although an interface reference cannot be instantiated, an instance of a class that extends the interface can be assigned to the references of the interface type.
Reading: Best Tools for Remote Developers
Addresses of Variables and Reference Types in Java
Unlike C/C++ where we can get a close look at the memory addresses of a variable and references through pointers, Java is completely silent here. There is no element in the Java language that enables one to get the address of a variable. This is the reason there is no such thing as address-of or a similar operator in the language construct; the language, from the ground up, is designed to work without it. This completely closes the door for pointers in Java.
However, if we are so keen to get close to the memory – or, rather, close to the memory abstraction in Java – use reference types. Reference types are not actually memory addresses but are closely convertible to memory addresses. In any case, they have a similar vibe to pointers and they can be treated like just any other variable.
InterfaceReference in Java
In Java, an interface cannot be instantiated. Therefore, it cannot be referenced directly. However, an object of class type, which extends the interface, can be used to assign a reference of that interface type. In the following example, a professor is derived not only from the person class, but also from the two interfaces: teacher and researcher.
Therefore, according to the statement, the following hierarchy is valid:
As such, the following Java code example will compile just fine:
public class Main{ public static void main(String[] args){ Professor professor = new Professor(“112233”, “Donald Ervin Knuth”, Date.valueOf(LocalDate.of(1938,1,10)), 9.8f); Person person = new Professor(“223344”, “Dennis Ritchie”, Date.valueOf(LocalDate.of(1941,9,9)),9.7f); Teacher teacher = new Professor(“223344”, “Andrew S Tanenbaum”, Date.valueOf(LocalDate.of(1944,3,16)),9.6f); Researcher researcher = new Professor(“223344”, “Ken Thompson”, Date.valueOf(LocalDate.of(1943,2,4)),9.5f); } }
Here, the four objects of type Professor are assigned to different reference types that also include two interface reference types. Hypothetically, the stack and heap content of the reference types would look something like this:
The following reference is also equally possible:
Professor professor = new Professor(“112233”, “Donald Ervin Knuth”, Date.valueOf(LocalDate.of(1938,1,10)), 9.8f); person person = professor; Teacher teacher = professor; Researcher researcher = professor;
In such a case, the stack and heap memory would look something like this where one object has multiple references:
But, note that the references must be super types of an assigned object. This means that the following assignment is not valid (and will not compile):
person = professor; // valid professor = person; //invalid
The reason for this is that references are used to call the public methods declared within the class. Therefore, the object that the reference is pointing to must be able to access those methods. Here, the reference professor cannot access a person’s property. As a result, the Java compiler complains about the assignment. Some smart code editors and IDEs are also able to scent the invalidity and flag a message and warn programmers prior to compilation.
One can, however, use explicit conversion to convince the compiler that everything is just fine:
professor = (professor) person; //valid
Final Thoughts on Java Reference Types
Reference type instances are initialized by default to value null. The null is a reserved keyword in Java which means that the reference type points to nothing in the memory. One aspect of not having pointers in Java is that reference types can almost be treated just like any other variable in most cases. Pointers have a strange look which many programmers dislike for exactly that reason (some however like it anyway). Lay programmer’s hand off the memory and still have a reference to point to objects in memory – you get Java reference types.
read more Java programming and software development tutorials.