skip to content

What does Object.toString() return by default, and why is that often unhelpful for logging?

level: juniorimportance: should knowfreq 58%

answer

  1. Default = ClassName@hexHashCode
  2. The hex part is the hashCode, NOT a memory address
  3. Auto-called by println and string +
  4. No formal contract, just 'non-null & useful'
  5. Records generate a good toString automatically

basics

~20 s

By default toString() returns the class name, an '@', and the hashCode in hex, like Point@1b6d3586. It is auto-called in println and string concatenation, but shows no field values, so logs look cryptic unless you override it.

solid answer

~40 s

Object.toString() returns getClass().getName() + "@" + Integer.toHexString(hashCode()) — for example com.acme.Point@1b6d3586. The part after @ is the hash in hexadecimal, which is NOT a memory address and is not human meaningful. toString() is auto-invoked whenever an object is used in string concatenation or passed to print/println, and by many logging frameworks. The default reveals only the type, not the object's state, so debugging output is cryptic. That's why you override toString() to include the fields that matter (e.g. Point[x=1, y=2]). Records auto-generate a useful toString from their components. There's no formal contract on toString other than that it returns a non-null string; Effective Java recommends overriding it for any class whose instances you'll log or display.

go deeper

for a junior

Knows the default looks like ClassName@somehex and that you should override toString for readable output.

for a middle

Knows the exact format (getClass().getName()+"@"+hex hashCode) and that the suffix is a hash, not an address.

for a senior

Explains the lack of a formal contract, auto-invocation points, and records auto-generating toString; advises documenting parseable formats carefully.

for a principal

Weighs toString as a debugging/observability concern: cost of including large state, avoiding sensitive data in logs, and committing (or not) to a stable parseable format as an API.

## What `toString()` is for `toString()` is Object's method that produces a **textual representation** of an object. Java calls it automatically in two everyday situations: 1. **String concatenation**: `"value=" + obj` invokes `obj.toString()`. 2. **Printing**: `System.out.println(obj)` and `String.valueOf(obj)` call it (with a null-safe guard). Many logging libraries (`log4j`, `slf4j` with `{}` placeholders) also call it. ## The default format Object's default implementation is essentially: ```java public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } ``` So an un-overridden object prints like `com.acme.Point@1b6d3586`: - **`com.acme.Point`** — the fully-qualified class name. - **`@`** — a literal separator. - **`1b6d3586`** — the object's `hashCode()` rendered in **hexadecimal**. A very common misconception is that this is the memory address; it is **not** — it is just the hash code (often an identity hash) in hex. It is stable for the object's lifetime but otherwise opaque. ## Why it's unhelpful The default shows the **type** but none of the **state**. If you log a list of orders you get `[com.acme.Order@2f3a, com.acme.Order@7b1c]` — you can't tell one order from another. That defeats the purpose of logging. ## Fixing it Override `toString()` to include the meaningful fields: ```java @Override public String toString() { return "Point[x=" + x + ", y=" + y + "]"; } ``` Now logs read `Point[x=1, y=2]`. **Records** do this for free: `record Point(int x, int y) {}` auto-generates `Point[x=1, y=2]`. ## The (non-)contract Unlike `equals`/`hashCode`, `toString()` has **no formal correctness contract** beyond returning a non-null string. The Javadoc only *recommends* a concise, informative, readable result. Effective Java's guidance: override it for any class whose instances will be printed, logged, or shown to humans; consider documenting the format if other code might parse it (though parseable formats create a maintenance commitment).

  • Does toString() have a formal contract like equals and hashCode?
    No. The only hard requirement is returning a non-null string. The Javadoc merely recommends a concise, informative, human-readable representation; correctness contracts apply to equals/hashCode, not toString.
  • How do records change toString behavior?
    A record auto-generates toString() from its components, e.g. Point[x=1, y=2], so you rarely need to write it yourself for records.

saying these in an interview costs you the question

  • Saying the hex suffix is the object's memory address
  • Claiming toString() has a strict contract like equals/hashCode
  • Believing the default shows field values
  • Forgetting println(obj) calls toString() automatically

context