Variables and Types

Learning goals

Declare variables with correct types, distinguish primitives from reference types, use literals and var appropriately, and read basic type conversion rules without surprise bugs at runtime.


Variables and declarations

A variable stores a value. Java requires an explicit type (or var with inferrable initializer):

int count = 0;
String name = "Ada";
double price = 19.99;
boolean active = true;

Naming: camelCase for variables and methods (itemCount), PascalCase for classes (OrderService).

Constants use final:

final int MAX_SIZE = 100;
final String APP_NAME = "Learning";

By convention, final fields are UPPER_SNAKE_CASE.


Primitive types

Java has eight primitives—stored directly, not on the heap as objects:

Type Size Example Notes
byte 8 bit (byte) 127 Rare
short 16 bit (short) 1000 Rare
int 32 bit 42 Default for integers
long 64 bit 42L Suffix L
float 32 bit 3.14f Suffix f
double 64 bit 3.14 Default for decimals
char 16 bit 'A' Single Unicode char
boolean true, false Not 0/1
long users = 2_000_000_000L;   // underscores for readability (JDK 7+)
char newline = '\n';

Reference types

Everything that is not a primitive is a reference type: objects, arrays, String, your own classes. A variable holds a reference (like a pointer) to an object on the heap:

String s = "hello";           // reference to String object
int[] nums = {1, 2, 3};       // reference to array object
LocalDate today = LocalDate.now();  // reference (java.time)

null means “no object”:

String optional = null;  // valid for references, illegal for primitives

Literals

int hex = 0xFF;
int binary = 0b1010;
double scientific = 1.2e3;  // 1200.0
String escaped = "Line1\nLine2";
String textBlock = """
    Multi-line
    string (JDK 15+)
    """;

Text blocks strip incidental indentation—useful for SQL and JSON snippets.


var (local type inference, JDK 10+)

var list = new ArrayList<String>();  // inferred as ArrayList<String>
var count = 10;                       // int

Rules:

  • Local variables only, with initializer.
  • Not for fields, method parameters, or null alone (var x = null fails).
  • Type is fixed at compile time—Java stays statically typed.

Casting and widening

Widening (safe, implicit):

int i = 100;
long L = i;      // int → long
double d = L;    // long → double

Narrowing (explicit cast, may lose data):

double pi = 3.99;
int truncated = (int) pi;  // 3
long big = 300;
byte b = (byte) big;  // overflow wraps (256 mod 256 → 44)

Boxing and unboxing

Primitives have wrapper classes: Integer, Long, Double, etc.

Integer boxed = 42;        // autoboxing
int unboxed = boxed;       // unboxing

Watch NullPointerException when unboxing null:

Integer n = null;
int x = n;  // NPE at runtime

Prefer primitives in hot loops; use wrappers in generics (List<Integer>).


Common mistakes

  1. Using float without f suffixfloat f = 3.14; is a compile error (3.14 is double).
  2. Comparing floats with == — use Math.abs(a - b) < epsilon or BigDecimal for money.
  3. var without readable initializervar data = getData(); hides type; sometimes explicit is clearer.
  4. Integer division5 / 2 is 2, not 2.5; cast one operand: 5 / 2.0.
  5. Confusing = (assign) with == (compare) — especially in conditions.

Practice checkpoint

  1. What is the type of var x = 10L;?

    • Answer: long
  2. What prints? System.out.println((int) 9.8);

    • Answer: 9
  3. Declare a final constant for PI as a double.

    • Answer: final double PI = 3.141592653589793;
  4. Why is Integer n = null; int y = n; dangerous?

    • Answer: Unboxing null throws NullPointerException.

Interview angles

  • “Primitive vs reference?” — Primitives hold value directly; references hold address to heap object. Defaults: primitives 0/false, references null.
  • “Pass-by-value in Java?” — Always pass-by-value; for references, the reference value is copied (object identity unchanged).
  • “Why no unsigned int?” — Historical; use long or bit masking when needed.

Next: /java/learn/language/operators-and-expressions/