Skip to content

Chapter 2 of 8

Core Language Features

Java's type system rests on eight primitive data types that map directly to hardware: byte (8-bit), short (16-bit), int (32-bit), long (64-bit), float (32-bit IEEE 754), double (64-bit IEEE 754), char (16-bit unsigned Unicode), and boolean. Primitives are stored on the stack when local, have no identity or methods, and are not objects. When object behavior is required, the compiler will automatically box a primitive into its wrapper type (autoboxing: Integer i = 42;) and unbox it again on use (int n = i;). The compiler inserts Integer.valueOf() and intValue() calls under the hood, with one important caveat: unboxing a null wrapper throws NullPointerException, and for performance the IntegerCache keeps small values (\([-128, 127]\)) as singletons. Beyond wrappers, the int[] vs Integer[] distinction matters for performance: int[] stores raw 32-bit values contiguously with no boxing overhead, while Integer[] stores object references suitable for generics and reflection at the cost of heap allocation per element.

The String class is one of the most distinctive parts of the language. String is deliberately immutable—every modification returns a new String—and this design choice provides security (strings used in class loading, networking, and file paths cannot be tampered with), thread safety without synchronization, hash code caching, and the String Pool, a special heap region where the JVM interns string literals to save memory. When you write String s = "hello";, the JVM checks the pool first and reuses existing instances; the explicit intern() method adds a string to the pool. For mutable text manipulation, Java provides StringBuilder (fast, not thread-safe, the default for single-threaded code) and StringBuffer (synchronized, thread-safe, slower). Strings should always be compared with .equals() for value equality rather than ==, which compares reference identity: \( \texttt{new String("hi") == new String("hi")} \) is false even though both hold the same characters. The classic equality contract requires that x.equals(y) ⇒ x.hashCode() == y.hashCode(); otherwise HashMap and HashSet silently lose entries.

A handful of keywords shape class-level structure. The static keyword binds a member to the class rather than to any instance: static variables are shared across all objects, static methods can be called without creating an instance (as with Math.sqrt(25)), and static initialization blocks run exactly once when the class is loaded into the JVM. The final keyword has three flavors: a final variable cannot be reassigned (a constant), a final method cannot be overridden by subclasses, and a final class cannot be extended. Access modifiers control visibility along a four-step spectrum: public (everywhere), protected (same package plus subclasses), default/package-private (same package only, no keyword needed), and private (the declaring class only). The this and super keywords are essential for navigating class internals: this refers to the current object instance and is used to disambiguate fields from parameters (this.name = name), to invoke another constructor in the same class as this(args), and to pass the current object as an argument; super refers to the parent class and lets a constructor call its parent's constructor as super(args), invoke an overridden parent method via super.methodName(), or access a parent field that the child has hidden.

Finally, packages group related classes and interfaces into namespaces—declared with a package statement at the top of the file—avoiding naming collisions, controlling package-private visibility, and providing modular structure for larger code bases. Java also distinguishes several flavors of nested classes: a nested static class does not capture an outer instance and behaves like a top-level type; an inner (non-static) class holds an implicit reference to its enclosing instance and can access all of its members; a local class is declared inside a method and can access effectively-final locals; and an anonymous class is a one-off local class without a name. Lambdas replace most uses of anonymous classes for functional interfaces.

All chapters
  1. 1Java Platform and Memory Model
  2. 2Core Language Features
  3. 3Object-Oriented Programming
  4. 4Generics and the Collections Framework
  5. 5Functional Programming and the Streams API
  6. 6Concurrency and the Java Memory Model
  7. 7Exception Handling, I/O, and Serialization
  8. 8Modern Java, Design Patterns, and Best Practices

Drill it

Reading is not remembering. These come from the Java Programming deck:

Q

What is the JVM?

The Java Virtual Machine (JVM) is an abstract computing machine that executes Java bytecode. It provides platform independence by translating bytecode into nati...

Q

What is the difference between JDK, JRE, and JVM?

JDK (Java Development Kit) includes tools for developing Java programs.JRE (Java Runtime Environment) provides libraries and JVM to run Java applications.JVM (J...

Q

What are the four pillars of OOP in Java?

Encapsulation – bundling data and methods, restricting direct accessInheritance – a class derives from another classPolymorphism – one interface, many implement...

Q

What is encapsulation in Java?

Encapsulation is the practice of keeping fields private and providing access through public getter and setter methods. This protects the internal state of an ob...