Method Parameters in Java
An interface declares a set of methods that implementing classes must provide, and a variable of the interface type can refer to any implementing object.
When a Method Needs Behavior, Not Just Data
Most method parameters carry data: a number, a string, or a reference to an object. Sometimes a method needs something different. It needs a piece of behavior from its caller, meaning the caller must decide what happens when the method asks for work to be done. Java lets you express that need with an interface. An interface names a set of methods that a caller must supply, and the method that receives the behavior never needs to know which concrete class supplies it. It only needs to know that the object promises the required methods.
This article follows one small scenario. A method has to draw a figure into two different graphics contexts. The figure itself is supplied by the caller. Before reading further, pause and ask yourself what the caller must hand over so that the method can do its job, and where that object would come from if you did not want to write a separate named class for it.
The Drawable Promise
An interface declares a set of methods that implementing classes must provide, and a variable of the interface type can refer to any implementing object.
Read the declaration as a promise. The interface Drawable says that anything claiming to be a Drawable has a draw method that accepts a Graphics object. The declaration contains no body for draw. The body belongs to whichever class implements the interface. Classes are allowed to implement interfaces, and that is the mechanism this whole article depends on.
- Drawable is the interface: it declares draw but gives no body
drawTwicereceives the figure through a parameter typed as Drawable- render builds the anonymous implementation at the call site
The method that consumes a Drawable takes two graphics contexts and one drawable figure, then asks the figure to draw itself into each context in turn. The listing above reconstructs that shape in its essential form. The method drawTwice never mentions a concrete class. It only calls draw on figure, and that call is legal because figure is declared as a Drawable.
Predict Before You Read the Code
Notice what a prediction about drawTwice depends on. You do not need to know the name of the class behind figure. You only need the fact that figure is a Drawable, so calling draw on it is legal. This is the point of the design: the caller decides what the figure does, and drawTwice decides how many times it happens and in which contexts.
What do you think happens?
When drawTwice runs, in what order does the figure draw into the two graphics contexts?
Reveal answer
Into g1 first, then g2
drawTwice contains two sequential calls: figure.draw(g1) appears first and figure.draw(g2) appears second. Java runs statements in order, so the figure draws into g1 and then into g2.
Reading the Anonymous Expression
An anonymous class is a class without a name that is declared and instantiated in one expression. It can implement an interface by supplying the required method body. Read the expression from left to right. The keyword new asks for an object. Drawable() names the interface the object will satisfy, and the empty parentheses work the same way they do in any instance creation. Because no class name appears, the braces that follow supply the entire class body.
Inside those braces, the method draw is written with the parameter g, and its body is the work the figure performs. The anonymous class exists only as this expression, so you use it exactly where the object is needed. You cannot refer to it by name later in the file, because it was never given one.
Following an Argument Into a Parameter
Anonymous classes are often used as actual parameters, meaning the values supplied at a call site rather than declared variables. In the scenario, the third argument to drawTwice is not a variable declared earlier. It is the anonymous Drawable, created directly inside the argument list. Each actual argument is bound to the parameter in the same position. The first two arguments are graphics contexts, so they land in g1 and g2. The third argument is the anonymous object, so it lands in figure.
Inside drawTwice, the name figure refers to the anonymous object, and the method never mentions the anonymous class by name. Each call figure.draw(...) runs the implementation supplied at the call site. The name g inside the anonymous draw method is a parameter of that method, separate from g1 and g2 in drawTwice. The two methods use different names for their own parameters. The value that connects them is the argument passed on each call. If you lose track of which graphics context is in use during a run, check the argument in the call that is currently executing, not the names you see elsewhere in the file.
Tracing one call to drawTwice
render calls drawTwice(a, b, new Drawable with draw body g.drawLine(0, 0, 10, 10)). Trace where each value goes and what runs.
- 1Bind the arguments
a is bound to g1, b is bound to g2, and the new Drawable object is bound to figure, because each argument takes the parameter in its position.
- 2First call
drawTwicerunsfigure.draw(g1). Because figure refers to the anonymous object, control enters the anonymous draw method, where the parameter g now refers to the same graphics context as g1, namely a. - 3Body runs
The anonymous body calls
g.drawLine(0, 0, 10, 10)on that context. When the body finishes, control returns todrawTwice. - 4Second call
drawTwicerunsfigure.draw(g2). The same anonymous body runs again, this time with g referring to b. - 5Return
After the second call finishes,
drawTwiceends and control returns to render.
The figure is drawn into a first and then into b, using the single anonymous implementation written at the call site.
Mistakes That Block Compilation
Most problems with anonymous interface implementations come from breaking the promise the interface makes. The compiler checks that promise, so many errors appear before the program runs. The mistakes below are the ones most likely to stop the code from compiling or from behaving as you intended.
Common mistake Leaving out the draw method
What it looks likenew Drawable() { } passed as the third argument, with no draw body inside the braces.
Why it failsThe interface declares draw and requires implementing classes to provide it. An anonymous class that omits the method does not satisfy the promise, so it cannot be used as a Drawable.
Do this insteadWrite a draw method with a body inside the braces, matching the interface signature.
Common mistake Writing the wrong method signature
What it looks likevoid draw(Graphics g, int n) inside the braces of a Drawable.Why it failsThe interface promises a draw method that accepts a single Graphics object. A method with a different parameter list is a different method, so draw is still missing as far as Drawable is concerned.
Do this insteadMatch the declared signature exactly: draw takes one Graphics parameter and returns void.
Common mistake Putting a semicolon after the closing brace of the class body
Why it failsThe anonymous expression is part of a larger statement, the call to
drawTwice. The statement ends with a semicolon after the call's closing parenthesis, not after the brace that closes the class body.Do this insteadEnd the whole call with one semicolon: drawTwice(a, b, new Drawable() { ... });Common mistake Looking for the anonymous object by name later in the file
Why it failsAn anonymous class has no name and exists only as the expression where it was created. A later reference to it has nothing to refer to.
Do this insteadUse the object through the parameter it was passed into, such as figure inside drawTwice.
Practice: Tracing Two Calls
Suppose render is changed so that drawTwice receives the same graphics context for both arguments, and the anonymous draw body is unchanged. Without running the program, describe which graphics context figure.draw uses on each call and how many times the body runs in total.
Hints
- Each argument is bound to the parameter in its own position, so check what the first and second arguments are.
drawTwicemakes exactly two calls on figure, one per statement.- Count the calls, not the distinct contexts.
Wrap-Up
- 1An interface declares methods that implementing classes must provide, and a variable of the interface type can refer to any implementing object.
- 2An anonymous class is declared and instantiated in one expression, using new, the interface name, and a braced body that supplies the required method.
- 3When an anonymous object is passed as an actual parameter, it is bound to the parameter in the same position, and each call on that parameter runs the anonymous implementation.
- 4Compilation errors such as a missing method or a wrong signature break the interface promise, while the statement must end with one semicolon after the whole call.
Key Takeaways
- An interface is a promise: a variable of the interface type can refer to any object whose class supplies the declared methods.
- An anonymous class is a nameless class declared and instantiated in one expression, with a braced body that supplies the interface method.
- Passing an anonymous object as an argument binds it to a parameter by position, and each call on that parameter runs the anonymous implementation.
- Missing methods and wrong signatures break the interface promise, and the statement ends with a semicolon after the entire call.