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:
int count;count = 100; (or combined: int count = 100;)count = 105;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.transactionAmount, userEmailAddress.final static): UPPER_SNAKE_CASE โ e.g., MAX_RETRIES, DEFAULT_TIMEOUT_MS, PI_CONSTANT.isActive, hasPermission, canExecute.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 |
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.double. Writing float price = 9.99; causes a compiler error because narrowing double-to-float requires explicit float designation: float price = 9.99f;.int creditCard = 1234_5678_9012_3456;.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:
null.int age = 24; (Direct value: 24)String name = @0x4F1A (Memory pointer)
@0x4F1A [ "DevAscent" ]Type conversion occurs when a value of one data type is transferred to another. Java defines two distinct casting modalities:
byte โ short โ int โ long โ float โ double (also char โ int).
(targetType) because data truncation, precision loss, or sign-bit overflow can occur:
double โ float โ long โ int โ short โ byte.
byte (8-bit)short / char (16-bit)int (32-bit)long (64-bit)float (32-bit)double (64-bit)
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);
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 โ Byteshort โ Shortint โ Integerlong โ Longfloat โ Floatdouble โ Doublechar โ Characterboolean โ BooleanIntroduced in Java 5, the compiler automatically converts between primitive types and their corresponding wrapper object wrappers without explicit method calls:
Integer x = 42; (Compiler emits: Integer.valueOf(42)).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.
Java provides a comprehensive suite of operators classified into distinct functional categories:
+ (Addition), - (Subtraction), * (Multiplication), / (Division), % (Modulus / Remainder). Integer division truncates decimals toward zero (7 / 2 = 3).=, and compound operators +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=. Compound operators perform an implicit type cast automatically!true or false): == (Equal to), != (Not equal to), >, <, >=, <=.&& (Conditional-AND with short-circuiting), || (Conditional-OR with short-circuiting), ! (Logical NOT).+ (Unary plus), - (Unary minus / negation), ++ (Increment), -- (Decrement), ! (Logical complement), ~ (Bitwise bit-inversion). Prefix (++x) increments before evaluation; Postfix (x++) evaluates before incrementing.& (Bitwise AND), | (Bitwise OR), ^ (Bitwise XOR), ~ (Bitwise NOT), << (Left shift), >> (Signed right shift, preserves sign bit), >>> (Unsigned right shift, shifts zeroes into MSB).condition ? exprIfTrue : exprIfFalse;. Acts as an inline expression alternative to if-else.In logical expressions, Java evaluates from left to right using short-circuit logic:
conditionA && conditionB: If conditionA is false, conditionB is never evaluated because the entire expression can never be true.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!
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 |
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.
/**
* 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);
}
}
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.
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.
byte a = 10; byte b = 20; byte c = a + b; fail to compile?+, -, *, /) 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.
== and .equals() when comparing Wrapper Objects?== 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.
&& (Conditional-AND) and & (Bitwise / Logical-AND).&& 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.
>> (Signed Right Shift) and >>> (Unsigned Right Shift)?>> 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.
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.
int x = 5; int y = x++ + ++x;? Explain step-by-step.x++ (postfix): The current value of x (5) is used in the expression, then x is incremented to 6.++x (prefix): x is immediately incremented from 6 to 7, and its new value (7) is used in the expression.5 + 7 = 12.y = 12, and final x = 7.