Class Structure in Java
A class definition consists of several key components:
- Access modifiers:
public,protected,private, or package-private (no keyword), controlling visibility. - Class identifier: Must match the source file name exactly (e.g.,
MyClass.javamust declareclass MyClass). - Fields: Instance or static variables; may be primitives (
int,boolean) or references (String, custom objects). - Methods: Including constructors (name matches class, no return type) and regular methods — both instance-bound and
static. - Static members: Declared with
static; loaded with the class, shared across all instances, and accessible without instantiation.
Floating-Point Type Conversion
Java supports two floating-point types: float (32-bit) and double (64-bit). Widening conversions are implicit: float → double. Narrowing (double → float) requires explicit casting and risks precision loss due to reduced bit capacity and rounding.
String as a Reference Type
String is a final class in java.lang. It is not a primitive but an immutable object:
String greeting = "Hello, World!";
Internally, it wraps a char[] and provides rich manipulation APIs.
Enum Behavior and Identity Semantics
Given an enum Size { SMALL, LARGE }:
- Comparisons via
==and.equals()yield identical results because each enum constant is a singleton instance. s.getClass().isPrimitive()returnsfalse— enums are reference types, not primitives.Size.valueOf("SMALL")returns the canonicalSMALLinstance; repeated calls yield the same object reference.Size.values()returns a clone of the internal array containing all declared constants, enabling safe iteration.
Binary Representations: Two’s Complement
Java uses two’s complement for signed integer storage:
-
+5 (8-bit):
- Sign-magnitude (original):
00000101 - One’s complement:
00000101 - Two’s compliment:
00000101
- Sign-magnitude (original):
-
−5 (8-bit):
- Sign-magnitude:
10000101 - One’s complement:
11111010 - Two’s complement:
11111011
- Sign-magnitude:
All byte, short, int, and long values are stored this way. Bitwise operations (<<, >>, >>>, &, |, ^) operate directly on these bit patterns.
Primitive Type Ranges
| Type | Bits | Signed Range |
|---|---|---|
byte |
8 | −128 to 127 |
short |
16 | −32,768 to 32,767 |
int |
32 | −2,147,483,648 to 2,147,483,647 |
long |
64 | −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
float |
32 | ~±3.40282347E+38 (IEEE 754 single-precision) |
double |
64 | ~±1.79769313486231570E+308 (IEEE 754 double-precision) |
boolean |
— | true / false (JVM-specific size) |
Widening conversions (e.g., int → long, int → double) preserve value. Converting integers to floating-point types may lose precision for large values (>2⁵³ for double) due to mantissa limits.
Floating-Point Precision Limitations
Decimal fractions like 0.05, 0.01, or 0.42 lack exact binary representations. This leads to accumulated rounding errors:
System.out.println(0.05 + 0.01); // Outputs: 0.060000000000000005
For financial or scientific applications requiring exact decimal arithmetic, BigDecimal is preferred.
Using BigDecimal Safely
BigDecimal resides in java.math and supports arbitrary-precision decimal arithmetic:
import java.math.BigDecimal;
BigDecimal a = new BigDecimal("0.05");
BigDecimal b = new BigDecimal("0.01");
BigDecimal sum = a.add(b); // "0.06"
BigDecimal diff = a.subtract(b); // "0.04"
BigDecimal prod = a.multiply(b); // "0.0005"
BigDecimal quot = a.divide(b, 2, RoundingMode.HALF_UP); // "5.00"
⚠️ Avoid new BigDecimal(double) — it inherits the double’s imprecision. Always use the String constructor for deterministic initialization.
String Concatenation Precedence
The + operator behaves differently based on operand types:
int X = 100, Y = 200;
System.out.println("X+Y=" + X + Y); // "X+Y=100200" (left-associative string concat)
System.out.println(X + Y + "=X+Y"); // "300=X+Y" (addition first, then concat)