Ocp The Basics

6 minute read

OCP - The basics

Declaration vs Definition

Declaration just means that something exists. Where as Definition describes exactly what the something is. For example: you declare a class or a method, then you define what the class and/or method does.

class aClass // Declaring the class.

{ // The start of defining what the class does.

    private int aVariable; // All the information required to define a variable is included within the declaration. However, Java does make the distinction between variable **declaration** and **initialization**.

    private int anotherVariable = 100; // This variable is both **declared** and **initialized**
    
    public void aMethod() // Declaring a method.

    { // The start of defining what this method does.

    } // The end of the method definition.

} // The end of the class definition.

Interfaces

Interfaces did used to only contain method declarations. But since Java 8, interfaces could also contain method definitions in the form of default methods.

Classes

A class is the definition of what it’s object instances will be able to do. It is the “blue print” or the “cookie-cutter”. These objects are stored in memory (the heap) and a reference to their localation must be declared in a variable, so we can keep track of where the object is, to be able to call methods on it.

References

A object is created when it is initialized. The declaration initialiazes a reference variable which points to the location in memory where the object resides. This variable is known as a pointer because it’s value is the address of the location in memory of the object.

Many references can exist that point to the same location in memory where an object resides. For example:

[...]
private String variable1 = "value";
private String variable2;

public constructor() {
    this.variable2 = variable1; // This is 
}
[...]

A reference variable can not be assigned to a memory location directly. It can only ever be assigned a reference to the location in memory where the object resides.

Primitives

Primitive types are different to object types in that the value is the actual value and not a reference to an object stored in the heap. Although, whether a primitives value is stored in the heap or on the stack depends on whether the primitive is declared as a member or class variable, or a local variable or method parameter. More on this later.

[...]
private int primitive1 = 1;
[...]

Null objects

Objects can be declared without referencing an object in memory. In this case they are assigned the value null. Objects can also be de-referenced, or have their value changed from a reference to a location in memory to null, or not referencing any location in memory.

Primitives, on the other hand, can never be null, and can either be intialized explicitly with a value or not. In this case they are initialized with a default value for the type specified in the decalaration. For example, the default value for integer is 0. A primitive type declaration cannot be assigned the value null.

Static vs instance

In Java static is a keyword used when declaring fields or methods that belong to the class. These fields and methods cannot be called on instances of the class and can only be called on the class itself. For example:

class AClass() {
    private static String classVariable = "value";
}

[...]

var variable1 = AClass.classVariable;

Static fields and methods can be called within member (or instance) methods. For example:

class AClass() {
    private static String classVariable = "value";

    public String giveMeTheClassVariable() {
        return classVariable;
    }
}

If a method or variable is not declared as static then it is an instance or variable member. The values of instance fields may be different.

Stack vs Heap

All programs require Random Access Memory (RAM) in order to store data during runtime. This memory is allocated to a program by the operating system provided the system has enough to allocate. Once allocated, the program is responsible for managing the memory that was allocated to it. It may ask the system for more memory, or it may release memory (that it does not need) back to the operating system.

The difference between the stack memory and the heap memory essentially boils down to short term vs long term storage. But more specifically, the stack is used to store the order of method invokations and local reference variables within a single thread during runtime, and the heap is managed by the Java Virtual Machine (JVM) to store ALL objects that are referenced from variables in the stacks.

The stack is named because of the way it stores it’s data in “Last In First Out (LIFO)” order. This means that memory is released from the top of the stack as the most locally accessed methods and variables become out-of-scope and are no longer being accessed.

The heap, on the other hand, is managed by the JVM which uses a Garbage Collector (GC) to dynamically manage memory allocation. It does not store objects in the order they are declared, like the stack. Whenever an object is created on any stack, it is stored in the heap, but the reference variables are stored on the stack allocated to the thread within which it was instantiated.

A Java program does not ever explicitly release memory from the stack, but it is automatically released from the top of the stack when method invokation is complete. In the heap, the GC will identify “garbage” objects as those objects which no longer have any references on any stacks pointing to them.

  • Stacks are created for specific threads and the data stored in them is only accessible from the threads they are created for.

  • The heap is shared amongst threads, and is used to store ALL objects. This means that an object that was created in one thread could be accessed from another thread.

  • Primitive values could be stored on the stack or in the heap. This depends on where it is declared.

  • The stack space is limited and fixed. A StackOverflowException will be thrown if the stack space is exceeded. By default the stack space is 64KB, but this can be changed. The heap space is only limited by the available system memory that can be allocated to the JVM.

Compile time vs run time

In Java, all code must be compiled into class files by a compiler. The compiler converts the Java code into intermediary code that the JVM can execute.

The Java compiler is smart enough to identify syntactical errors during compilation and will generate relevant errors if it identifies any syntax errors. It will also try to identify logical errors, but can not be relied on soley for this. For example, it will correctly identify when a developer tries to assign a value greater than the bounds of the type used (e.g: byte b = 200) but it will not throw an error for int i = 10/0.

The JVM, on the other hand, will identify these logical mistakes and will throw a relevant Exception during run time.

Successful compilation is not a guarantee of successful execution.

The compiler can know the value of some types. These are known as compile-time constants. For example: final int x = 20. The value of x will never change so it is compile time constant. The same goes for literal values such as 1, 2, true, false and characters like 'a'.

Identifiers

Java has the following rules when naming classes, variables and methods:

  1. The first character of an identifier must be a uppercase or lowercase letter, a _, or a $
  2. An identifier can be an unlimited length of letters and digits
  3. An identifier cannot have the same spelling as a keyword or a literal

Reserved keywords and literals

         
abstract continue for new switch
assert default goto package synchronized
boolean do if private this
break double implements protected throw
byte else import public throws
case enum instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp volatile
const float native super while
_        

var

var is a special kind of keyword. It is not a keyword in and of itself, but is replaced by the compiler with a derived type based on the value that is being assigned.