skip to content

What does the default Object.toString() return, and why is it usually not useful?

level: juniorimportance: must knowfreq 70%

answer

  1. ClassName@hexHashCode
  2. hex part = hashCode, NOT memory address
  3. shows type, hides data
  4. override for readable logs
  5. records generate one automatically

basics

~20 s

By default toString() returns the class name, an '@', and the object's hash code in hexadecimal, like Point@1b6d3586. It identifies the type but shows none of the object's data, so it is rarely helpful for reading or logging.

solid answer

~30 s

Every class inherits toString() from java.lang.Object. The inherited version returns getClass().getName() + '@' + Integer.toHexString(hashCode()) — for example com.app.Point@1b6d3586. That string tells you the runtime class and a hex hash, but nothing about the object's actual state (its x and y, say), so it is useless for debugging, logging, or user-facing output. That is why the standard advice is to override toString() in almost every value-bearing class to return a concise, human-readable description of the instance's important fields. The hex part is the hash code, not a memory address, and it is not stable across JVM runs.

go deeper

for a junior

Knows the default returns ClassName@somehex and that you should override it to make logs readable.

for a middle

Can state the exact formula getClass().getName() + '@' + Integer.toHexString(hashCode()) and explain the hex is a hash code, not an address.

for a senior

Discusses implicit invocation sites (concatenation, println, logging) and notes records/Lombok/IDE generation as practical alternatives to hand-writing it.

for a principal

Frames toString() as a debuggability/observability concern, weighs auto-generation vs hand-tuning across a codebase, and cautions about leaking sensitive fields in logged toString output.

## What toString() is `toString()` is a method defined on **`java.lang.Object`**, the root class that every Java class extends. Because every class inherits it, you can call `toString()` on any object reference. Its job is to produce a **`String` representation** of the object — text that describes the object. ## The default implementation If a class does **not** override `toString()`, it uses the one inherited from `Object`. That implementation is, in effect: ```java public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } ``` Term by term: - **`getClass().getName()`** — the fully-qualified runtime class name, e.g. `com.app.Point`. - **`@`** — a literal separator character. - **`Integer.toHexString(hashCode())`** — the object's **hash code** (an `int` returned by `hashCode()`) formatted in **hexadecimal** (base-16, digits 0–9 and a–f). So a typical result looks like `com.app.Point@1b6d3586`. ## Common misconception: it is NOT a memory address The hex part *looks* like a pointer, but it is the **hash code**, not the object's address in memory. For the default `Object.hashCode()` the JVM derives a value (often once, then cached in the object header); it is **not guaranteed stable across different JVM runs**, and two different objects can occasionally share it. Never parse or rely on it. ## Why the default is not useful The default string identifies the **type** and gives an opaque hash, but reveals **none of the object's data**. If you log a `Point(3, 4)` you see `com.app.Point@1b6d3586` instead of something like `Point[x=3, y=4]`. That makes logs, debugger views, and error messages unreadable. Hence the near-universal recommendation: **override `toString()`** in any class that carries meaningful state, returning a short, readable summary of the key fields. ## Where it shows up automatically `toString()` is invoked implicitly in several places, so even if you never call it directly you still see its output: string concatenation (`"p=" + p`), `System.out.println(p)`, `String.valueOf(p)`, logging frameworks, and IDE debugger displays. (`null` is handled specially in those paths and prints `"null"` rather than throwing.) ## Records get one for free Since Java 16, a **record** auto-generates a `toString()` of the form `Point[x=3, y=4]` from its components, so you usually do not write one for records.

  • Is the hex number after the @ a memory address?
    No. It is the object's hashCode() rendered in hexadecimal. The default hashCode is JVM-assigned, not the object's address, and is not stable across runs.
  • Do you need to write toString() for a record?
    No. Records auto-generate a toString() like ClassName[component=value, ...] from their components; you only write one if you want a different format.

saying these in an interview costs you the question

  • Claiming the hex suffix is the object's memory address
  • Saying the default toString() prints the field values
  • Thinking the default hash/string is stable across JVM runs
  • Believing toString() must be called explicitly to ever run

context