When you write an anonymous class with `new SomeType() { ... }`, how does the meaning differ depending on whether SomeType is a class or an interface, and what are the limits?
answer
- One token after `new` -> extends (class) or implements (interface)
- Class supertype: () forwards to its constructor
- Interface supertype: () must be empty
- Exactly one supertype, never both/many
- No constructor -> use instance initializer block
basics
~20 sIf SomeType is a class, the anonymous class extends it (a subclass) and the () calls that class's constructor. If SomeType is an interface, the anonymous class implements it and the () must be empty because interfaces have no constructor. Either way you get exactly one supertype.
solid answer
~50 sThe single token after `new` decides everything. `new SomeClass(args) { ... }` declares an anonymous *subclass* of SomeClass; the `args` are passed to SomeClass's constructor, and the body can override its methods. `new SomeInterface() { ... }` declares an anonymous class that *implements* that interface; the parentheses must be empty because an interface has no constructor, and the body must implement its abstract methods. You can never list two types — an anonymous class has exactly one direct supertype (class or interface). The generated class implicitly extends Object when the supertype is an interface. You also cannot give the anonymous class its own named constructor (no name to declare one for); to run initialization, use an instance initializer block `{ ... }` inside the body. If you need to extend a class AND implement an interface, or implement several interfaces, you must use a named class instead.
go deeper
Knows new Type() {} either subclasses a class or implements an interface and that you get one object.
Explains the empty-parentheses rule for interfaces vs constructor-arg forwarding for classes, and the exactly-one-supertype limit.
Uses initializer blocks for setup, knows the double-brace pitfall, diamond support since Java 9, and when to pick a named class instead.
Reasons about API ergonomics (constructor injection vs functional callbacks), discourages double-brace init for memory/leak reasons, and steers toward lambdas or named types for clarity.
## The one-token decision The anonymous-class syntax is `new T(args_opt) { body }`. The compiler looks at `T`: - **`T` is a class** → the anonymous class is a **subclass** of `T` (it `extends T`). The arguments in `(args)` are forwarded to one of `T`'s constructors, which must exist and be accessible. Inside the body you can override `T`'s methods and add new ones. - **`T` is an interface** → the anonymous class **implements** `T` and implicitly extends `Object`. Because interfaces have no constructors, the parentheses **must be empty**: `new T() { ... }`. The body must provide implementations of `T`'s abstract methods (or the class won't compile, unless it itself is abstract — which an anonymous class cannot be, since it is instantiated). ```java // extends a class: calls Thread(String) constructor, overrides run() Thread t = new Thread("worker") { @Override public void run() { System.out.println(getName()); } }; // implements an interface: empty (), implements compare() Comparator<String> byLen = new Comparator<>() { @Override public int compare(String a, String b) { return a.length() - b.length(); } }; ``` ## The hard limit: exactly one supertype An anonymous class has **exactly one direct supertype** named in the `new` clause. You cannot write `new A(), B() { ... }`; there is no syntax for two types. So an anonymous class can: - extend one class, **or** - implement one interface, but **not** extend a class and implement an interface at the same time, and **not** implement two interfaces. When you need that, declare a **named** class (local or member): `class Both extends A implements B { ... }`. ## No named constructor — use an initializer block An anonymous class has no name, so you cannot write a constructor for it. To do setup work at construction time, put an **instance initializer block** in the body — a bare `{ ... }` block, which runs as part of object construction after the superclass constructor: ```java Map<String,Integer> m = new HashMap<>() {{ // double-brace: outer = anon subclass, inner = init block put("a", 1); put("b", 2); }}; ``` This is the so-called *double-brace initialization* trick; it works but creates a hidden subclass (and an enclosing-instance reference), so many style guides discourage it. ## Generics and the diamond Since Java 9 you can use the diamond `<>` with anonymous classes (`new Comparator<>() { ... }`) when the type argument is inferable, which earlier versions disallowed. ## Relationship to lambdas A lambda also implements a single (functional) interface, but it is **not** an anonymous class: it has no separate `this`, generates no `Outer$1.class` file, and can only target a functional interface — never extend a class. Use an anonymous class when you must extend a class, override more than one method, or maintain instance state/multiple methods.
- How do you run initialization code in an anonymous class given it can't have a constructor?Use an instance initializer block — a bare `{ ... }` block in the class body — which runs during construction after the superclass constructor. This is the basis of the double-brace initialization idiom.
- Why can't `new Runnable(arg) { ... }` compile?`Runnable` is an interface and interfaces have no constructors, so the parentheses must be empty. Passing arguments is only valid when the supertype is a class with a matching constructor.
saying these in an interview costs you the question
- Claiming `new Interface(args) { }` can pass constructor args (interfaces have no constructor)
- Saying an anonymous class can extend a class and implement an interface together
- Writing a named constructor inside an anonymous class body
- Confusing a lambda with an anonymous class (different `this`, no class file the same way)