Java Fundamentals: Structure, Data Types, and Casting

The basic structure of a Java program is based on the concept of classes. Every executable Java program must contain at least one class definition.

Essential Structure of a Java Program

A typical Java application follows this hierarchical structure:

  1. Package Statement (Optional)

    The very first statement in a Java source file (if present) is the package statement. It organizes classes into logical groups, preventing naming conflicts.

    • Syntax: package package_name;
    • Example: package com.mycompany.app;
  2. Import Statements (Optional)

    These statements are used to include classes from other packages. They allow you to use classes without specifying their full package name every time.

    • Syntax: import package.ClassName; or import package.*;
    • Example: import java.util.Scanner;
  3. Class Definition (Mandatory)

    This is the core of any Java program. All code must reside inside a class. The class serves as the blueprint for objects.

    • Syntax: [access_modifier] class ClassName { ... }
    • Example: public class HelloWorld { ... }
  4. Fields/Instance Variables (Optional)

    These are variables defined within the class but outside any method. They represent the state or properties of the object created from the class.

    • Example (inside HelloWorld): private int number;
  5. Methods (Optional, but main is mandatory for execution)

    Methods contain the executable code and define the behavior of the class.

    The main Method

    For a Java application to run, it must have a special method called main. The Java Virtual Machine (JVM) starts program execution here.

    • Syntax: public static void main(String[] args) { ... }
    • Explanation of Keywords:
      • public: The method is accessible from outside the class.
      • static: The method belongs to the class, not to a specific object. The JVM can call it without creating an object.
      • void: The method does not return a value.
      • main: The standard name for the entry point.
      • String[] args: An array of strings to accept command-line arguments.

Example Program Structure

// 1. Package Statement (Optional)
package com.example.greetings;

// 2. Import Statement (Optional)
import java.io.PrintStream;

// 3. Class Definition (Mandatory)
public class SimpleProgram {

    // 4. Field/Instance Variable (Optional)
    String message = "Hello, Java!";

    // 5. Main Method (Mandatory for application execution)
    public static void main(String[] args) {
        // Code inside the main method (The program's execution begins here)
        System.out.println("Program started.");
        SimpleProgram sp = new SimpleProgram();
        System.out.println(sp.message);
        // Other methods can be called here
        sp.displayMessage();
    }

    // 5. Another Method (Optional)
    public void displayMessage() {
        System.out.println("This is a separate method.");
    }
}

Classes and Objects: The OOP Foundation

Classes and Objects are the fundamental and essential concepts that form the basis of Object-Oriented Programming (OOP) in Java.

Understanding Classes

A Class serves as a blueprint or template, defining the structure and capabilities for a set of similar entities. It is a logical construct that specifies the state (data stored in fields or instance variables) and the behavior (actions implemented in methods) that its objects will possess. Because a class is merely a definition, it occupies no memory space when declared.

Understanding Objects

Conversely, an Object is a concrete, real-world instance of a class. It is a physical entity created in memory using the new keyword, consuming resources and having a unique identity, state, and behavior. Every object derives its properties and methods from its class, but each object maintains its own independent set of values for the instance variables. This clear separation allows programmers to model complex real-world entities efficiently. This paradigm promotes code reusability, modularity, and maintainability by encapsulating related data and functions together.

Example: The Car Class and Objects

Consider a Car class that acts as the blueprint:

public class Car {
    // Fields (State/Attributes)
    String color;
    int speed;

    // Method (Behavior)
    public void accelerate() {
        speed = speed + 10;
        System.out.println("Current speed: " + speed + " mph.");
    }
}
public static void main(String[] args) {
    // Object 1: A specific instance of the Car class
    Car honda = new Car(); 
    honda.color = "Red"; // Setting state
    honda.speed = 0;

    // Object 2: A separate instance of the Car class
    Car bmw = new Car();
    bmw.color = "Black"; // Setting state
    bmw.speed = 0;

    System.out.println("Honda is " + honda.color + "."); // Honda's state
    bmw.accelerate(); // BMW's behavior modifies only its own speed
}

Data Types in Java

Data types in Java specify the size and type of values that can be stored in variables. Java is a statically-typed language, meaning all variables must be declared with a specific data type before they can be used.

Java data types are primarily divided into two categories: Primitive Data Types and Non-Primitive (Reference) Data Types.

1. Primitive Data Types

Primitive data types are the most basic data types available in Java. They are predefined by the language, named by a keyword, and do not use objects. Their size and range are fixed.

Java has eight primitive data types:

TypeSize (Bytes)Range / UseDefault Value
Numeric (Integral)
byte1Stores small whole numbers (-128 to 127)0
short2Stores whole numbers (-32,768 to 32,767)0
int4The most commonly used whole number type (approx. +/- 2 billion)0
long8Stores very large whole numbers0L
Numeric (Floating-Point)
float4Stores single-precision fractional numbers (suffixed with f or F)0.0f
double8Stores double-precision fractional numbers (most commonly used)0.0d
Character
char2Stores a single Unicode character (e.g., ‘A’, ‘1’, ‘@’)\u0000
Boolean
boolean1 bit (internally)Stores only two possible values: true or falsefalse

2. Non-Primitive (Reference) Data Types

Non-primitive data types, also called Reference Types, are created by the programmer and are not defined by Java (with the exception of String). They refer to objects and store the memory address where the object is located, rather than the actual value itself.

  • Classes: Variables of a class type (e.g., Car, Dog).
  • Interfaces: Types defined by an interface (e.g., Runnable).
  • Arrays: Ordered collections of elements.
  • String: Although highly integrated into Java, String is technically a non-primitive class used to store sequences of characters.

Comparison: Primitive vs. Reference Types

FeaturePrimitive TypesNon-Primitive (Reference) Types
SizeFixed (e.g., int is always 4 bytes).Varies depending on the object.
StorageStores the actual data value.Stores the memory address (reference) of the object.
DefaultAlways has a default value (e.g., 0, false).Default value is null.

Type Casting in Java

Type casting in Java is the mechanism for converting a value from one data type to another. It is classified into two main types based on whether the conversion is safe and automatic or potentially lossy and manual.

1. Widening Conversion (Implicit Casting)

Widening conversion is the process of converting a smaller-sized data type to a larger-sized data type. This conversion happens automatically (implicitly) by the Java compiler because there is no risk of losing data.

  • Flow: The conversion always goes from a type with less storage space and range to a type with more storage space and range.
  • Order (Smallest to Largest): byteshortintlongfloatdouble

Example of Widening Conversion

int myInt = 100;
double myDouble = myInt; // Implicitly cast from int (4 bytes) to double (8 bytes)
// myDouble now holds 100.0

2. Narrowing Conversion (Explicit Casting)

Narrowing conversion is the process of converting a larger-sized data type to a smaller-sized data type. This conversion is not automatic and requires the programmer to explicitly specify the target type using parentheses () before the value. This is necessary because there is a potential for data loss or precision loss.

  • Flow: The conversion goes from a type with more storage space to one with less.
  • Required Syntax: (target_type) value_to_be_cast

Examples of Narrowing Conversion

Example 1 (Precision Loss):

double myDouble = 9.75;
int myInt = (int) myDouble; // Explicitly cast from double to int, truncating .75
// myInt now holds 9 (data loss)

Example 2 (Overflow/Wraparound):

int largeInt = 300;
byte myByte = (byte) largeInt; // Explicitly cast from int (300) to byte (max 127)
// myByte now holds 44 (wraparound/overflow)

Reference Type Casting

Casting also applies to non-primitive (reference) types, involving conversions between classes and interfaces in an inheritance hierarchy:

  • Upcasting (Implicit): Casting a subclass reference to a superclass reference. This is always safe and automatic.
  • Downcasting (Explicit): Casting a superclass reference back to a subclass reference. This requires an explicit cast and is checked at runtime; if the object is not actually an instance of the target subclass, a ClassCastException will be thrown.