Early in my Java journey, I saw two lines of code that looked almost the same:
Dog d = new Dog("Bruno");
d.bark();
new Dog("Bruno").bark();
Both make a dog and tell it to bark. So why does the second one have a special name, "anonymous object", and why do some people avoid it?
The short answer is that the two lines create the same kind of thing but treat it very differently afterwards. In this post, we'll look at what each one means, what the JVM does in both cases, and how to choose between them. We'll also clear up a mix-up that trips up almost every beginner: anonymous objects are not the same as anonymous classes.
Unless I show a full class, the snippets go inside a main method.
A quick reminder: objects and references
When you write new Dog("Bruno"), Java creates an object on the heap. The object doesn't have a name. To talk to it later, you need a reference, which is like its address.
A reference variable is a variable that holds that address:
Dog d = new Dog("Bruno");
STACK HEAP
+--------+ +------------------+
| d -|--------> | Dog: name=Bruno |
+--------+ +------------------+
Here is a small Dog class we'll use for the whole post:
class Dog {
String name;
Dog(String name) {
this.name = name;
System.out.println("Dog created: " + name);
}
void bark() {
System.out.println(name + " says Woof!");
}
}
Reference object: an object with a name tag
A quick note on the words. "Reference object" isn't an official Java term. People use it for an object that's held by a reference variable. (Don't confuse it with the java.lang.ref package, which is a different, advanced topic.) You'll also just hear "named object".
Dog d = new Dog("Bruno");
d.bark();
d.bark();
Output:
Dog created: Bruno
Bruno says Woof!
Bruno says Woof!
Because we kept the reference d, we can:
- call as many methods as we like on the same object,
- read or change its fields later,
- pass it to other methods,
- store it in a list or compare it with another object.
The object lives as long as it can still be reached through some reference.
Anonymous object: an object with no name tag
An anonymous object is an object you create with new but don't store in any variable.
new Dog("Tiger").bark();
new Dog("Tiger").bark();
Output:
Dog created: Tiger
Tiger says Woof!
Dog created: Tiger
Tiger says Woof!
Look at the output closely. "Dog created" appears twice. Each new made a brand new object. We never talked to the same Tiger twice. After each line, our code had no way to reach that object again.
Reference object: d ----------> [ Dog: Bruno ] we can come back to it
Anonymous object: (no name) --> [ Dog: Tiger ] used once, then unreachable
State is lost between calls
This is the clearest way to see the difference. Here's a counter:
class Counter {
int count;
int incrementAndGet() {
count++;
return count;
}
}
With a reference, the state builds up:
Counter c = new Counter();
System.out.println(c.incrementAndGet());
System.out.println(c.incrementAndGet());
Output:
1
2
With anonymous objects, each call starts from scratch:
System.out.println(new Counter().incrementAndGet());
System.out.println(new Counter().incrementAndGet());
Output:
1
1
Same code, different result, because the second version used two different Counter objects.
What happens behind the scenes
Here's the part I wish someone had told me earlier: the JVM treats both kinds of objects exactly the same. An anonymous object is still allocated on the heap, and its constructor still runs. The only difference is what your code does with the reference afterwards.
You can see this in the bytecode (try javap -c on your class). For Dog d = new Dog("Bruno"); d.bark();, it looks roughly like this:
new Dog
dup
ldc "Bruno"
invokespecial Dog.<init>
astore_1 // store the reference in variable d
aload_1 // load it back
invokevirtual Dog.bark
For the anonymous version, new Dog("Bruno").bark();, it's roughly:
new Dog
dup
ldc "Bruno"
invokespecial Dog.<init>
invokevirtual Dog.bark // use the reference right away
(The exact lines vary a bit between Java versions.) Notice there's no astore. The reference is created, used immediately and then dropped. Nothing keeps it.
So an anonymous object isn't "lighter" or "faster". It's just an object whose reference you chose not to keep.
What about garbage collection?
Java frees objects that nobody can reach anymore. That's the garbage collector's job.
- An anonymous object that's used on one line is unreachable right after that statement ends, so it becomes eligible for cleanup. (Eligible doesn't mean deleted instantly. The garbage collector decides when to run.)
- A reference object stays alive as long as some reference points to it.
- You can also make a named object lose its name by re-pointing the variable:
Dog d = new Dog("A");
d = new Dog("B"); // nobody points to "A" now
Output:
Dog created: A
Dog created: B
After the second line, the Dog named "A" is in the same situation as an anonymous object: alive on the heap, but unreachable.
One important twist: "anonymous" only means no variable name in your code. If you hand the object to someone who keeps it, it lives on:
class Student {
String name;
Student(String name) { this.name = name; }
}
List<Student> students = new ArrayList<>();
students.add(new Student("Asha")); // anonymous object
students.add(new Student("Ravi")); // anonymous object
System.out.println(students.size());
System.out.println(students.get(0).name);
Output:
2
Asha
Here we created two anonymous objects, but the list keeps a reference to each, so they're safe and reachable. This is probably the most common use of anonymous objects in real code.
Where anonymous objects are useful
They fit when you need an object once and only once:
-
Passing to a method or collection:
students.add(new Student("Asha")); -
Returning from a method:
return new Result(status, message); - A one-shot chain of calls:
String reversed = new StringBuilder("Java").reverse().toString();
System.out.println(reversed);
Output:
avaJ
- Starting a thread:
new Thread(() -> System.out.println("Hello from a thread")).start();
In each case, giving the object a name would add a line and a variable that you'd never use again.
Don't mix up: anonymous object vs anonymous class
This confusion is very common, so let's clear it up.
- An anonymous object has a class with a name (like
Dog) but no variable holding it. - An anonymous class is a class with no name, defined and used on the spot, usually to implement an interface.
Runnable r = new Runnable() {
public void run() {
System.out.println("Running");
}
};
r.run();
Output:
Running
The object here has a reference (r), so it isn't an anonymous object. But the class that it's built from has no name, so it's an anonymous class. These are two different ideas that just share the word "anonymous".
You can combine them in one line, new Runnable() { ... }.run();, and then it's both. But keep the two ideas separate in your head:
- Is there a variable holding the object? If no, it's an anonymous object.
- Is the class itself unnamed? If yes, it's an anonymous class.
Which one should I use?
- Need to use the object more than once? Use a reference variable. An anonymous object gives you a different object each time.
- Need to remember its state, read a field later or pass it to several places? Use a reference variable.
- Using it for exactly one call or one argument? An anonymous object is clean and short.
- Debugging? A named variable is easier. You can inspect it, and the name tells readers what the object is for.
-
Creating an object just to call one method that doesn't use its fields? That's a hint the method probably should be
static. Then you wouldn't need an object at all.
As a rule of thumb: if you find yourself wanting to name it, give it a name. If naming it feels like noise, go anonymous.
Common mistakes
-
Expecting state to carry over. Calling
new Counter().incrementAndGet()twice gives you two separate counters. If you want the count to build up, keep one reference. -
Calling methods on "the same" anonymous object. There's no such thing. Two
newexpressions always mean two objects. - Mixing up anonymous object and anonymous class. One is about a missing variable, the other is about a missing class name.
- Thinking anonymous objects use less memory. They're ordinary heap objects. They just become unreachable sooner, if nobody else holds them.
-
Creating anonymous objects inside a loop for no reason. Something like
new Random().nextInt(10)on every round creates a new object each time. Create theRandomonce outside the loop and reuse it. - Assuming an anonymous object is deleted immediately. It becomes eligible for garbage collection, and the JVM cleans up when it decides to. And if a list or another object keeps a reference, it stays alive.
Quick recap
- An object lives on the heap, and a reference variable holds its address.
- A reference object (named object) is stored in a variable, so you can use it again and again.
- An anonymous object is created with
newbut not stored, so you can use it only at that spot. - The JVM treats both the same way: allocate on the heap, run the constructor. The only difference is whether you keep the reference.
- An anonymous object becomes eligible for garbage collection once nothing can reach it, but passing it to a list or method may keep it alive.
- Anonymous object means no variable. Anonymous class means no class name. They're different things.
Try it yourself
Here's a small practice idea: write the Counter class from this post and try three versions. First, call incrementAndGet() three times on one reference and note the output. Second, call it three times using new Counter() each time and compare. Third, add a Counter to a list as an anonymous object, then get it back and call incrementAndGet() on it. This will show you exactly when state survives and when it doesn't.
For a bonus experiment, run javap -c on your class, and compare the bytecode of the named and anonymous versions. Spotting the missing astore yourself is a great moment.
If this helped, or if you spotted something I should fix, tell me in the comments. I'm still learning too.
Top comments (0)