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:
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;
- Syntax:
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;orimport package.*; - Example:
import java.util.Scanner;
- Syntax:
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 { ... }
- Syntax:
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;
- Example (inside
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.
- Syntax:
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:
| Type | Size (Bytes) | Range / Use | Default Value |
|---|---|---|---|
| Numeric (Integral) | |||
byte | 1 | Stores small whole numbers (-128 to 127) | 0 |
short | 2 | Stores whole numbers (-32,768 to 32,767) | 0 |
int | 4 | The most commonly used whole number type (approx. +/- 2 billion) | 0 |
long | 8 | Stores very large whole numbers | 0L |
| Numeric (Floating-Point) | |||
float | 4 | Stores single-precision fractional numbers (suffixed with f or F) | 0.0f |
double | 8 | Stores double-precision fractional numbers (most commonly used) | 0.0d |
| Character | |||
char | 2 | Stores a single Unicode character (e.g., ‘A’, ‘1’, ‘@’) | \u0000 |
| Boolean | |||
boolean | 1 bit (internally) | Stores only two possible values: true or false | false |
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,
Stringis technically a non-primitive class used to store sequences of characters.
Comparison: Primitive vs. Reference Types
| Feature | Primitive Types | Non-Primitive (Reference) Types |
|---|---|---|
| Size | Fixed (e.g., int is always 4 bytes). | Varies depending on the object. |
| Storage | Stores the actual data value. | Stores the memory address (reference) of the object. |
| Default | Always 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):
byte→short→int→long→float→double
Example of Widening Conversion
int myInt = 100;
double myDouble = myInt; // Implicitly cast from int (4 bytes) to double (8 bytes)
// myDouble now holds 100.02. 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
ClassCastExceptionwill be thrown.
