โ˜• Unit 2 โ€ข Core Java Fundamentals

Variables, Data Types & Operators

The mathematical and lexical bedrock of Java: Variables and constants, enterprise naming conventions, primitive memory layout (byte, short, int, long, float, double, char, boolean), reference types, widening and narrowing type casting, numeric promotion, autoboxing with wrapper classes, and the complete taxonomy of operators from arithmetic to bitwise bit-manipulation and precedence hierarchies.

Curriculum: Enterprise Java Software Engineering
Unit: 02 of 15
Prerequisite: Unit 01 (JVM & Architecture)
Target: JDK 21 LTS
01

Variables and Constants in Java

๐Ÿ“ฆ What is a Variable? Memory Allocation Mechanics

In Java, a variable is a reserved memory location with a symbolic name that holds a value during program execution. Java is a statically-typed language: every variable must be declared with an explicit data type before it can be used. The data type determines the exact amount of memory allocated, the range of valid values, and the set of legal operations.

Variables in Java undergo a three-stage lifecycle:

  • Declaration: Informs the compiler of the variable's name and type: int count;
  • Initialization: Assigns an initial value before first read: count = 100; (or combined: int count = 100;)
  • Reassignment: Modifies the value during runtime: count = 105;
๐Ÿ”’ Constants in Java: The final Keyword

A constant is a variable whose value cannot be altered once initialized. In Java, constants are declared using the final keyword. Attempting to reassign a final variable causes a compile-time error.

When defining class-level constants accessible across an entire application, the idiom public static final is standard:

  • public: Accessible from any package.
  • static: Belongs to the class itself, stored once in the Method Area rather than duplicated per object instance.
  • final: Immutable; value cannot be mutated.
๐Ÿท๏ธ Standard Enterprise Java Naming Conventions
  • Local Variables & Instance Fields: lowerCamelCase โ€” e.g., transactionAmount, userEmailAddress.
  • Constants (final static): UPPER_SNAKE_CASE โ€” e.g., MAX_RETRIES, DEFAULT_TIMEOUT_MS, PI_CONSTANT.
  • Boolean Variables: Should read like assertions or questions โ€” e.g., isActive, hasPermission, canExecute.
02

The 8 Primitive Data Types in Java

๐Ÿงฉ Machine-Level Primitive Architecture

Java provides 8 built-in primitive data types. Primitives are not objects; they store raw binary values directly on the Thread Call Stack for maximum cache efficiency and execution speed. Java defines the precise bit-size and two's complement sign format for each type across all host operating systems:

Type Category Bit Size Byte Size Range / Value Representation Default Value
byte Integer 8 bits 1 byte -128 to +127 (-27 to 27-1) 0
short Integer 16 bits 2 bytes -32,768 to +32,767 (-215 to 215-1) 0
int Integer 32 bits 4 bytes -2,147,483,648 to +2,147,483,647 (-231 to 231-1) 0
long Integer 64 bits 8 bytes -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807 (-263 to 263-1) 0L
float Floating Point 32 bits 4 bytes ~1.4E-45 to ~3.4028235E+38 (IEEE 754 single-precision, 7 decimal digits) 0.0f
double Floating Point 64 bits 8 bytes ~4.9E-324 to ~1.7976931348623157E+308 (IEEE 754 double-precision, 15 decimal digits) 0.0d
char Textual Character 16 bits 2 bytes 0 to 65,535 (Unsigned 16-bit Unicode `\u0000` to `\uffff`) '\u0000'
boolean Logical Truth JVM-dependent ~1 byte true or false (Cannot be cast to/from integer) false
โš ๏ธ Literal Suffix Rules & Gotchas
  • Integral Literals: Default to int. To assign a value exceeding 2.14 billion to a long, you must append L or l (e.g., long population = 8000000000L;). Always use uppercase L to prevent visual confusion with digit 1.
  • Floating Literals: Default to double. Writing float price = 9.99; causes a compiler error because narrowing double-to-float requires explicit float designation: float price = 9.99f;.
  • Digit Separators (Java 7+): Underscores can be placed between digits to improve human readability without affecting numeric value: int creditCard = 1234_5678_9012_3456;.
03

Non-Primitive (Reference) Data Types & Memory Layout

๐Ÿ›๏ธ Stack vs. Heap: Primitive vs. Reference Types

Non-primitive data types (also known as Reference Types) include Classes, Interfaces, Arrays, Strings, and Enums. Unlike primitives which directly contain their raw data bits, a reference variable stores a memory address (pointer reference) pointing to an object allocated dynamically on the JVM Garbage-Collected Heap:

  • Primitives: Stored directly where declared (local primitives live on the Call Stack; instance primitives live inside their parent object on the Heap). Default to numeric zeroes.
  • Reference Variables: The reference pointer (4 or 8 bytes) lives on the Stack, while the actual object body and its fields reside on the Heap. The default value for any uninitialized reference variable is null.
Visual Architecture: Stack vs. Heap Memory Allocation
Thread Call Stack
int age = 24; (Direct value: 24)
String name = @0x4F1A (Memory pointer)
โ”€โ”€โ”€โ”€โ”€โ”€ Pointer Reference โ”€โ”€โ”€โ”€โ”€โ”€โž”
JVM Garbage-Collected Heap
@0x4F1A [ "DevAscent" ]
Object metadata, char array, hash code
04

Type Conversion, Casting & Numeric Promotion

๐Ÿ”„ Widening vs. Narrowing Type Casting

Type conversion occurs when a value of one data type is transferred to another. Java defines two distinct casting modalities:

  1. Widening Casting (Implicit / Automatic): Occurs automatically when converting a smaller datatype into a larger datatype. Because the target type has a larger bit-capacity, no information is lost:
    byte โž” short โž” int โž” long โž” float โž” double (also char โž” int).
  2. Narrowing Casting (Explicit / Manual): Occurs when converting a larger datatype into a smaller datatype. Requires an explicit cast operator (targetType) because data truncation, precision loss, or sign-bit overflow can occur:
    double โž” float โž” long โž” int โž” short โž” byte.
Visual Architecture: Java Numeric Conversion Ladder
byte (8-bit)
โž”
short / char (16-bit)
โž”
int (32-bit)
โž”
long (64-bit)
โž”
float (32-bit)
โž”
double (64-bit)
โ—„โ”€โ”€ Widening (Automatic, Safe, No Data Loss) โ”€โ”€โ–บ
โ—„โ”€โ”€ Narrowing (Explicit `(type)`, Potential Truncation & Overflow) โ”€โ”€โ–บ
โš ๏ธ The Binary Numeric Promotion Rule in Arithmetic Expressions

In Java, any arithmetic operation (+, -, *, /) involving integer types smaller than int (i.e., byte, short, char) is automatically promoted to int before evaluation!

Therefore, the following code does NOT compile:
byte b1 = 10; byte b2 = 20; byte b3 = b1 + b2; // ERROR: Type mismatch: cannot convert from int to byte
It must be cast explicitly: byte b3 = (byte)(b1 + b2);

05

Wrapper Classes, Autoboxing & Unboxing

๐ŸŽ Bridging Primitives to Object-Oriented Frameworks

Java primitives provide raw computational speed, but enterprise Java frameworks (such as the java.util.Collections framework: List<T>, Map<K,V>, Generics, and Reflection) can only manipulate Objects. Java bridges this gap with Wrapper Classes located in java.lang:

  • byte โž” Byte
  • short โž” Short
  • int โž” Integer
  • long โž” Long
  • float โž” Float
  • double โž” Double
  • char โž” Character
  • boolean โž” Boolean
โšก Autoboxing and Unboxing (Compiler Automation)

Introduced in Java 5, the compiler automatically converts between primitive types and their corresponding wrapper object wrappers without explicit method calls:

  • Autoboxing: Automatic conversion of a primitive to its wrapper: Integer x = 42; (Compiler emits: Integer.valueOf(42)).
  • Unboxing: Automatic conversion of a wrapper object to its primitive: int y = x; (Compiler emits: x.intValue()).

High-Yield Viva Fact: The Integer Cache: To save memory, Integer.valueOf() caches objects for values between -128 and +127. Therefore, comparing two autoboxed integers in that range with == evaluates to true, but outside that range it evaluates to false! Always use .equals() for object value comparisons.

06

Complete Taxonomy of Java Operators

โš™๏ธ Operator Classifications

Java provides a comprehensive suite of operators classified into distinct functional categories:

  1. Arithmetic Operators: + (Addition), - (Subtraction), * (Multiplication), / (Division), % (Modulus / Remainder). Integer division truncates decimals toward zero (7 / 2 = 3).
  2. Assignment Operators: Simple assignment =, and compound operators +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=. Compound operators perform an implicit type cast automatically!
  3. Relational (Comparison) Operators: Evaluates to a boolean (true or false): == (Equal to), != (Not equal to), >, <, >=, <=.
  4. Logical Operators: Evaluates boolean operands: && (Conditional-AND with short-circuiting), || (Conditional-OR with short-circuiting), ! (Logical NOT).
  5. Unary Operators: Operates on a single operand: + (Unary plus), - (Unary minus / negation), ++ (Increment), -- (Decrement), ! (Logical complement), ~ (Bitwise bit-inversion). Prefix (++x) increments before evaluation; Postfix (x++) evaluates before incrementing.
  6. Bitwise & Bit-Shift Operators: Manipulates individual binary bits: & (Bitwise AND), | (Bitwise OR), ^ (Bitwise XOR), ~ (Bitwise NOT), << (Left shift), >> (Signed right shift, preserves sign bit), >>> (Unsigned right shift, shifts zeroes into MSB).
  7. Ternary Operator (Conditional): The only three-operand operator in Java: condition ? exprIfTrue : exprIfFalse;. Acts as an inline expression alternative to if-else.
๐Ÿ’ก Short-Circuit Evaluation Mechanics

In logical expressions, Java evaluates from left to right using short-circuit logic:

  • For conditionA && conditionB: If conditionA is false, conditionB is never evaluated because the entire expression can never be true.
  • For conditionA || conditionB: If conditionA is true, conditionB is never evaluated because the entire expression is already guaranteed to be true.

This property is critical for preventing NullPointerException: if (user != null && user.isActive()) safely terminates before calling isActive() if user is null!

07

Operator Precedence & Associativity Table

๐Ÿ“ Evaluation Order: Rules of Precedence

When an expression contains multiple operators, operator precedence determines which operations execute first. When two operators share the same precedence level, associativity determines whether they evaluate Left-to-Right (L-to-R) or Right-to-Left (R-to-L). Parentheses ( ) override all precedence rules.

Precedence Level Operator Type Operator Symbols Associativity
15 (Highest) Postfix / Access expr++, expr--, . (Member access), [ ] (Array access), ( ) (Call) Left to Right
14 Unary ++expr, --expr, +expr, -expr, ~, ! Right to Left
13 Cast & Object Creation (type), new Right to Left
12 Multiplicative *, /, % Left to Right
11 Additive +, - Left to Right
10 Shift <<, >>, >>> Left to Right
9 Relational <, <=, >, >=, instanceof Left to Right
8 Equality ==, != Left to Right
7 Bitwise AND & Left to Right
6 Bitwise XOR ^ Left to Right
5 Bitwise OR | Left to Right
4 Logical AND && Left to Right
3 Logical OR || Left to Right
2 Ternary Conditional ? : Right to Left
1 (Lowest) Assignment =, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, >>>= Right to Left
08

Unit 2 Practical Capstone: Financial Engine & Bitmask Permission System

๐Ÿš€ Practical Engineering Project

This comprehensive application demonstrates all concepts covered in Unit 2: exact primitive allocations, widening & explicit narrowing casts, binary promotion safeguards, wrapper utility parsing, bitwise authorization flags, and ternary conditional pricing.

DataTypesAndOperatorsDemo.java โ€” Capstone Implementation
/**
 * DevAscent Academy โ€” Unit 2 Capstone Project
 * Demonstrates Primitives, Type Casting, Bitwise Flags, and Precedence Rules.
 */
public class DataTypesAndOperatorsDemo {

    // Class-level constants
    public static final double STATE_TAX_RATE = 0.0825; // 8.25%
    public static final int FLAG_READ    = 1 << 0; // 0001 (1)
    public static final int FLAG_WRITE   = 1 << 1; // 0010 (2)
    public static final int FLAG_EXECUTE = 1 << 2; // 0100 (4)
    public static final int FLAG_ADMIN   = 1 << 3; // 1000 (8)

    public static void main(String[] args) {
        System.out.println("==================================================");
        System.out.println(" DEVASCENT ACADEMY: CORE DATA TYPES & OPERATORS ");
        System.out.println("==================================================");

        // 1. Primitive Declarations & Suffixes
        byte userTier = 3;
        short stockQuantity = 1_500;
        int customerId = 489_201;
        long globalInventoryCount = 8_450_000_000L; // 'L' suffix mandatory
        float unitWeightKg = 2.45f;                 // 'f' suffix mandatory
        double unitBasePrice = 199.99;
        char currencySymbol = '$';
        boolean isDiscountEligible = userTier >= 2;

        // 2. Widening & Narrowing Casting
        double subtotal = stockQuantity * unitBasePrice; // short widened to double
        double taxAmount = subtotal * STATE_TAX_RATE;
        double rawGrandTotal = subtotal + taxAmount;

        // Explicit narrowing casting: double truncated to whole integer cents
        long totalInCents = (long) (rawGrandTotal * 100);

        System.out.printf("Subtotal          : %c%.2f%n", currencySymbol, subtotal);
        System.out.printf("Tax (%s)       : %c%.2f%n", "8.25%", currencySymbol, taxAmount);
        System.out.printf("Raw Grand Total   : %c%.4f%n", currencySymbol, rawGrandTotal);
        System.out.println("Total in Cents    : " + totalInCents + "ยข (Narrowed to long)");
        System.out.println("--------------------------------------------------");

        // 3. Ternary Operator & Precedence
        double discountPercent = isDiscountEligible ? 0.15 : 0.0;
        double finalBilledAmount = rawGrandTotal * (1.0 - discountPercent);
        System.out.printf("Discount Applied  : %.0f%%%n", discountPercent * 100);
        System.out.printf("Final Net Payable : %c%.2f%n", currencySymbol, finalBilledAmount);
        System.out.println("--------------------------------------------------");

        // 4. Bitwise Operators: Security Permission Mask
        // Grant READ and WRITE access to user
        int userPermissions = FLAG_READ | FLAG_WRITE; // 0001 | 0010 = 0011 (3)
        System.out.println("Bitwise Security System:");
        System.out.println("  Current Mask    : " + Integer.toBinaryString(userPermissions) + " (Decimal: " + userPermissions + ")");
        System.out.println("  Has READ access : " + ((userPermissions & FLAG_READ) != 0));
        System.out.println("  Has WRITE access: " + ((userPermissions & FLAG_WRITE) != 0));
        System.out.println("  Has ADMIN access: " + ((userPermissions & FLAG_ADMIN) != 0));

        // Grant ADMIN permission dynamically using compound assignment
        userPermissions |= FLAG_ADMIN; // 0011 | 1000 = 1011 (11)
        System.out.println("  After ADMIN Prom: " + ((userPermissions & FLAG_ADMIN) != 0) + " (Mask: " + userPermissions + ")");
        System.out.println("--------------------------------------------------");

        // 5. Wrapper Classes: Autoboxing & Utility Parsing
        String inputScoreString = "98";
        int parsedScore = Integer.parseInt(inputScoreString); // Parsing String to primitive
        Integer boxedScore = parsedScore;                     // Autoboxing
        System.out.println("Wrapper Class Utilities:");
        System.out.println("  Parsed Primitive: " + parsedScore);
        System.out.println("  Autoboxed Object: " + boxedScore.getClass().getSimpleName());
        System.out.println("  Max Integer Val : " + Integer.MAX_VALUE);
    }
}
Execution Output (javac & java)
$ javac DataTypesAndOperatorsDemo.java $ java DataTypesAndOperatorsDemo ================================================== DEVASCENT ACADEMY: CORE DATA TYPES & OPERATORS ================================================== Subtotal : $299985.00 Tax (8.25%) : $24748.76 Raw Grand Total : $324733.7625 Total in Cents : 32473376ยข (Narrowed to long) -------------------------------------------------- Discount Applied : 15% Final Net Payable : $276023.70 -------------------------------------------------- Bitwise Security System: Current Mask : 11 (Decimal: 3) Has READ access : true Has WRITE access: true Has ADMIN access: false After ADMIN Prom: true (Mask: 11) -------------------------------------------------- Wrapper Class Utilities: Parsed Primitive: 98 Autoboxed Object: Integer Max Integer Val : 2147483647
09

University Exam & Technical Interview Viva Preparation Guide

Q1. Why is the size of all primitive data types fixed in Java across all operating systems?
In C and C++, primitive types (like int and long) depend on the underlying hardware architecture (e.g., an int could be 16 bits on a legacy processor or 32/64 bits on modern systems). Java mandates exact, immutable bit sizes (e.g., int is always 32 bits, long is always 64 bits) across every architecture to fulfill the core "Write Once, Run Anywhere" (WORA) contract and ensure identical numerical computation worldwide.
Q2. What is the difference between Widening Casting and Narrowing Casting?
Widening Casting converts a smaller type into a larger type (e.g., int to double). It happens automatically (implicitly) without code intervention because no precision or magnitude is lost. Narrowing Casting converts a larger type into a smaller type (e.g., double to int). It requires an explicit cast operator ((int) myDouble) because high-order bits can be discarded, causing potential data truncation or negative integer overflow.
Q3. Why does byte a = 10; byte b = 20; byte c = a + b; fail to compile?
Java enforces a language rule called Binary Numeric Promotion: whenever arithmetic operators (+, -, *, /) operate on integral values smaller than int (specifically byte, short, char), the operands are automatically promoted to 32-bit int values before calculation. Consequently, the result of a + b is an int. Attempting to store an int into a byte variable without an explicit cast ((byte)(a + b)) causes a compile-time type mismatch.
Q4. What is the difference between == and .equals() when comparing Wrapper Objects?
The == operator compares memory references (addresses) to check whether both variables point to the exact same object on the Heap. The .equals() method compares the actual wrapped value. Because of the JVM Integer Cache (-128 to 127), Integer a = 100; Integer b = 100; a == b; evaluates to true, but Integer x = 200; Integer y = 200; x == y; evaluates to false! Always use .equals() for object equality.
Q5. Explain the difference between && (Conditional-AND) and & (Bitwise / Logical-AND).
The && operator performs short-circuit evaluation: if the left-hand operand is false, the right-hand operand is never evaluated, which prevents runtime exceptions (e.g., user != null && user.isAdmin()). The single & operator is non-short-circuiting: when applied to booleans, it unconditionally evaluates both operands regardless of the left-hand value; when applied to integers, it performs bitwise bit-manipulation.
Q6. What is the difference between >> (Signed Right Shift) and >>> (Unsigned Right Shift)?
The >> operator is the Signed Right Shift: it shifts bits to the right and fills the vacated leftmost positions with copies of the original sign bit (preserves negative signs: 1 for negative, 0 for positive). The >>> operator is the Unsigned Right Shift: it shifts bits to the right and unconditionally fills all vacated leftmost positions with 0, regardless of whether the original number was positive or negative.
Q7. What is Autoboxing and Unboxing, and what is its performance overhead?
Autoboxing is the automatic conversion that the Java compiler makes between a primitive type and its corresponding object wrapper class (e.g., int to Integer). Unboxing is the reverse process. While convenient, excessive autoboxing inside tight loops causes severe performance degradation because it repeatedly allocates short-lived objects on the Heap, leading to heap fragmentation and triggering unnecessary Garbage Collection pauses.
Q8. What is the value of int x = 5; int y = x++ + ++x;? Explain step-by-step.
The expression evaluates as follows:
  1. x++ (postfix): The current value of x (5) is used in the expression, then x is incremented to 6.
  2. ++x (prefix): x is immediately incremented from 6 to 7, and its new value (7) is used in the expression.
  3. The addition performs 5 + 7 = 12.
  4. Result: y = 12, and final x = 7.