Variables, Primitives, Literals
The 8 primitives, wrapper classes, var inference, final constants, boxing pitfalls
The 8 Primitive Types
Java distinguishes primitive types from reference types. A primitive stores its value directly, has no methods, and has a fixed byte width; a reference type is an object and stores an address.
Type Bytes Default Range
-------- ----- -------- --------------------------
byte 1 0 -128 ~ 127
short 2 0 -32768 ~ 32767
int 4 0 ~ ±2.1 billion
long 8 0L ~ ±9.2×10^18
float 4 0.0f single-precision float
double 8 0.0d double-precision float
char 2 '\u0000' one UTF-16 unit (0 ~ 65535)
boolean 1* false true / false (*JVM-dependent)Declaration and Assignment
// Vars.java
public class Vars {
public static void main(String[] args) {
int age = 30;
double price = 19.9;
char letter = 'A';
boolean ok = true;
String name = "Alice"; // reference type
// declare multiple variables at once
int x = 1, y = 2, z = 3;
System.out.println(age + " " + price + " " + letter + " " + ok);
System.out.println(name + " " + x + " " + y + " " + z);
}
}Literals and Underscore Separators
A numeric literal can carry a type suffix (L / f / d); integers support binary 0b, octal 0, and hex 0x prefixes. Java 7+ allows underscores to improve readability (without affecting the value).
// Literals.java
public class Literals {
public static void main(String[] args) {
long big = 10_000_000_000L; // L suffix required (won't fit the default int)
float pi = 3.14f; // float requires the f suffix
double d = 1.0; // double by default; the d suffix is optional
int hex = 0xFF; // 255
int oct = 010; // 8
int bin = 0b1010; // 10
int million = 1_000_000;
System.out.println(big);
System.out.println(pi);
System.out.println(d);
System.out.println(hex + " " + oct + " " + bin + " " + million);
}
}Wrapper Classes and Autoboxing
Each of the 8 primitives has a corresponding wrapper class (Integer, Long, Double, Boolean…). Reference-type collections (such as List<Integer>) must use the wrapper class; the compiler converts between primitive and wrapper automatically — called "autoboxing / unboxing".
// Boxing.java
import java.util.ArrayList;
import java.util.List;
public class Boxing {
public static void main(String[] args) {
Integer boxed = 42; // autoboxing: int -> Integer
int unboxed = boxed; // auto-unboxing: Integer -> int
List<Integer> nums = new ArrayList<>();
nums.add(1); // autoboxing
nums.add(2);
int sum = 0;
for (Integer n : nums) {
sum += n; // auto-unboxing
}
System.out.println(sum); // 3
}
}// BoxingTrap.java
public class BoxingTrap {
public static void main(String[] args) {
Integer a = 100, b = 100;
Integer c = 200, d = 200;
System.out.println(a == b); // true (within cache range)
System.out.println(c == d); // false (outside cache)
System.out.println(c.equals(d)); // true (the correct way)
}
}var Local Variable Inference (Java 10+)
var works only for local variables; the compiler infers the type from the right-hand side. It is not dynamic typing — the type is still fixed at compile time.
// Var.java
import java.util.ArrayList;
public class Var {
public static void main(String[] args) {
var count = 0; // int
var name = "Alice"; // String
var list = new ArrayList<Integer>(); // ArrayList<Integer>
list.add(1);
list.add(2);
System.out.println(count + " " + name + " " + list);
}
// var cannot be used for fields, method parameters, or return values
// private var bad; // compile error
// void f(var x) {} // compile error
}final Constants
Once a variable is final it can be assigned only once. By convention constant names are all-uppercase with underscores.
// Constants.java
public class Constants {
static final double PI = 3.141592653589793;
static final String APP_NAME = "VelToolKit";
public static void main(String[] args) {
final int max = 100;
// max = 200; // compile error: cannot assign a value to a final variable
System.out.println(PI + " " + APP_NAME + " " + max);
}
}Type Conversion
Small → large range converts automatically (widening); the reverse requires an explicit (cast) (narrowing) and may lose precision.
// Cast.java
public class Cast {
public static void main(String[] args) {
int i = 100;
long l = i; // automatic widening
double d = i; // int -> double automatically
double pi = 3.14;
int truncated = (int) pi; // explicit cast, drops the fraction: 3
long big = 10_000_000_000L;
int overflow = (int) big; // overflow: 1410065408
System.out.println(l + " " + d + " " + truncated + " " + overflow);
}
}== vs equals Pitfall
== compares values for primitives; for reference types it compares "whether they are the same object". To compare whether the contents of strings/wrappers are equal, always use .equals().
// EqualsTrap.java
public class EqualsTrap {
public static void main(String[] args) {
String a = "hello";
String b = "hello"; // string literal pool, same object
String c = new String("hello"); // explicit new, a new object
System.out.println(a == b); // true (same pooled object)
System.out.println(a == c); // false (different objects)
System.out.println(a.equals(c)); // true (same content, correct)
}
}