Variables & Basic Types
java1-1 showed every value living inside a class. This chapter shows the one deliberate exception — and the real trap it creates.
Primitive Types
Java has exactly eight primitives — byte, short, int, long, float, double, char, boolean — each with an exact, guaranteed size across every platform, per the JVM specification itself. This is genuinely Rust-like, not C-like: c1-2's own material established that C only guarantees a minimum size for int. Java's primitives agree with Rust here, not with C.
Reference Types
Everything else — objects, arrays, String — is a reference type, stored as a reference to heap-allocated data, not the raw value itself. Conceptually similar to C's own pointer/value distinction (c1-7), but Java references cannot be manipulated with pointer arithmetic at all — no c1-7-style arithmetic; dereferencing is always implicit.
Primitives vs. Objects — Why Both Exist
A real, practical reason: primitives are stored directly — on the stack, or inline within an object — avoiding the overhead a full object/reference would carry for something as simple as an int. A deliberate performance-vs-uniformity tradeoff; making everything a full object, as some "purer" OOP languages do, has real, measurable overhead.
Boxing & Unboxing
Integer is the object wrapper class for the primitive int. Autoboxing (a primitive silently becoming a wrapper object) and auto-unboxing (the reverse) happen automatically in many contexts since Java 5.
A Real Boxing Gotcha — Integer Caching
A genuinely surprising, real, documented JVM behavior: Java caches small boxed Integer values, -128 to 127. Trips up even experienced Java programmers, since small test values often happen to fall inside the cached range and hide the bug.
== vs. .equals()
The general rule this gotcha is an instance of: == compares references for objects (are these the same object in memory) but compares values for primitives (since there's no reference to compare at all). .equals() is the method for genuine value comparison between objects.
| Concept | C (c1-2) | Rust | Java |
|---|---|---|---|
| Integer type size | minimum only, platform-dependent | exact, guaranteed | exact, guaranteed |
| Value vs. reference default | everything is a value; pointers are explicit | explicit ownership/borrowing | primitives are values; everything else is a reference |
| Object equality operator | n/a — no objects | == is value equality (PartialEq) | == is reference identity for objects, not value equality |
== for reference identity checks (or genuine primitive comparisons) — .equals() is the everyday habit for comparing what two objects actually contain.
== on boxed Integer values outside -128..127 will not reliably behave the way small test values might suggest — a genuine, real source of confusing bugs that only manifest once real data exceeds the cached range.
Coding Challenges
Declare two Integer variables both set to 100, compare them with ==, then declare two more both set to 500 and compare those with ==. Print both results and explain the difference.
📄 View solutionRepeat Challenge 1's 500-value comparison, but use .equals() instead of ==. Report the result and explain why it now behaves correctly regardless of the cache range.
📄 View solutionExplain why Java's primitive types are described as "Rust-like" rather than "C-like" in terms of size guarantees, tying your answer directly back to c1-2's own material on C's int.
📄 View solutionChapter 2 Quick Reference
- Eight primitives — exact, guaranteed sizes, unlike C's own minimum-only guarantee
- Everything else is a reference type — no pointer arithmetic, unlike C's pointers
- Autoboxing/auto-unboxing convert transparently between a primitive and its wrapper class (e.g. int/Integer)
- Integer caching (-128..127) means small boxed values happen to share references — a real, documented gotcha
==is reference identity for objects;.equals()is genuine value comparison — use.equals()by default- Next chapter: operators, control flow, switch expressions, and pattern matching