For example:
// innerclasses/Parcel7.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// Returning an instance of an anonymous inner class
public class Parcel7 {
public Contents contents() { // no-arg constructor
return new Contents() { // Insert class definition
private int i = 11;
@Override
public int value() {
return i;
}
}; // Semicolon required, upcasting
}
public static void main(String[] args) {
Parcel7 p = new Parcel7();
Contents c = p.contents();
}
}
when use
$ javac innerclasses/Parcel7.java
the compile error is :
innerclasses/Parcel7.java:2: error: cannot find symbol
public Contents contents() {
^
symbol: class Contents
location: class Parcel7
innerclasses/Parcel7.java:3: error: cannot find symbol
return new Contents() { // Insert class definition
^
symbol: class Contents
location: class Parcel7
innerclasses/Parcel7.java:15: error: cannot find symbol
Contents c = p.contents();
^
symbol: class Contents
location: class Parcel7
3 errors
this solution is to cd Parcel7.java current directory for compile this java source code.
The result generated three classes: Contents.class, Parcel7.class, Parcel7$1.class(anonymous inner class).
Inner class with an argument:
// innerclasses/Parcel8.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// Calling the base-class constructor
public class Parcel8 {
public Wrapping wrapping(int x) {
// Base constructor call:
return new Wrapping(x) { // [1]
@Override
public int value() {
return super.value() * 47;
}
}; // [2], compiled class has similar style to Parcel7 anonymoius inner class
}
public static void main(String[] args) {
Parcel8 p = new Parcel8();
Wrapping w = p.wrapping(10);
}
}
- [1] We pass the appropriate argument to the base-class constructor.
- [2] The semicolon at the end of an anonymous inner class doesn’t mark the end of the class body. Instead, it marks the end of the expression that happens to contain the anonymous class. Thus, it’s identical to the way the semicolon is used everywhere else.
Another inner class with an argument:
// innerclasses/Parcel9.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
public class Parcel9 {
// Argument must be final or "effectively final"
// to use within the anonymous inner class:
public Destination destination(final String dest) { // method parameter is final
return new Destination() {
private String label = dest;
@Override
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel9 p = new Parcel9();
Destination d = p.destination("Tasmania");
}
}
As long as We're assigning a field, the approach in this example is fine. But what if we must perform some constructor-like activity? We can’t have a named constructor in an anonymous class (since there’s no name). With instance initialization, we can, in effect, create a constructor for an anonymous inner class, like this:
// innerclasses/AnonymousConstructor.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// Creating a constructor for an anonymous inner class
abstract class Base {
Base(int i) {
System.out.println("Base constructor, i = " + i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i) {
return new Base(i) {
{
System.out.println("Inside instance initializer");
}
@Override
public void f() {
System.out.println("In anonymous f()");
}
};
}
public static void main(String[] args) {
Base base = getBase(47);
base.f();
}
}
/* Output:
Base constructor, i = 47
Inside instance initializer
In anonymous f()
*/
Here, the variable i did not have to be final. While i is passed to the base constructor of the anonymous class, it is never directly used inside the anonymous class.
Here's the "parcel" theme with instance initialization:
// innerclasses/Parcel10.java
// (c)2017 MindView LLC: see Copyright.txt
// We make no guarantees that this code is fit for any purpose.
// Visit http://OnJava8.com for more book information.
// Using "instance initialization" to perform
// construction on an anonymous inner class
public class Parcel10 {
public Destination destination(final String dest, final float price) { // note arguments are final
return new Destination() {
private int cost;
// Instance initialization for each object:
{
cost = Math.round(price);
if (cost > 100) {
System.out.println("Over budget!");
}
}
private String label = dest;
@Override
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel10 p = new Parcel10();
Destination d = p.destination("Tasmania", 101.395F);
}
}
/* Output:
Over budget!
*/
Inside the instance initializer we see code that couldn’t be executed as part of a field initializer (that is, the if statement). So in effect, an instance initializer is the constructor for an anonymous inner class. However, it’s limited; we can’t overload instance initializers, so we can have only one of these constructors. Anonymous inner classes are somewhat limited compared to regular inheritance, because they can either extend a class or implement an interface, but not both. And if we do implement an interface, we can only implement one.
references:
1. On Java 8 - Bruce Eckel
2. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/innerclasses/Parcel7.java
3. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/innerclasses/Parcel8.java
4. https://github.com/wangbingfeng/OnJava8-Examples/blob/master/innerclasses/Parcel9.java