At this point, we have a basic understanding of the typical uses of internal classes. For those involved in the internal class code, often expressed in the "simple" inner class, very simple, and very easy to understand. However, the design of internal classes is very comprehensive and inevitably encounters many of their other uses-if we create inner classes in a single method or even in an arbitrary scope. There are two reasons why we should do this:
(1) as shown earlier, we are prepared to implement some form of interface so that we can create and return a handle.
(2) To solve a complex problem, and would like to create a class that assists with its own program scheme. And not willing to make it public.
In the following example, the preceding code is modified to use:
(1) classes defined within a method
(2) A class defined within a scope of a method
(3) An anonymous class that implements an interface
(4) An anonymous class that expands a class that owns a Non-default builder
(5) An anonymous class for performing field initialization
(6) An anonymous class that is constructed from an instance initialization (anonymous inner class cannot have a builder)
All of this happens in the Innerscopes package. First, the generic interfaces from the aforementioned code are defined in their own files so that they can be used in all instances:
: Destination.java
package c07.innerscopes;
Interface Destination {
String readlabel ();
}///:~
Since we have assumed that contents may be an abstract class, we can take this more natural form, like an interface:
: Contents.java
package c07.innerscopes;
Interface Contents {
int value ();
}///:~
Although it is a generic class that contains specific implementation details, wrapping is also used as a generic "interface" for all its derived classes:
: Wrapping.java
package c07.innerscopes;
public class Wrapping {
private int i;
public wrapping (int x) {i = x;}
public int value () {return i;}
} ///:~
In the above code, we notice that wrapping has a builder that requires the use of arguments, which makes the situation even more interesting.
The first example shows how to create a complete class in the scope of a method, rather than in the scope of another class:
: Parcel4.java
//Nesting a class within a method
package c07.innerscopes;
public class Parcel4 {public
destination dest (String s) {
class Pdestination
implements destination { C16/>private String label;
Private Pdestination (String whereto) {
label = Whereto;
}
Public String Readlabel () {return label;}
}
return new Pdestination (s);
}
public static void Main (string[] args) {
Parcel4 p = new Parcel4 ();
Destination D = p.dest ("Tanzania");
}
///:~
The
Pdestination class is part of the dest () and not part of the PARCEL4 (note that you can use the class identifier pdestination for an internal class inside each class within the same directory, so that no named conflict occurs). Therefore, pdestination cannot be accessed from outside the Dest (). Notice that the trace in the return statement--except for a handle to the destination of the underlying class--has nothing beyond the bounds of the dest (). Of course, because the name of the class pdestination is not placed inside dest (), it is assumed that pdestination is not a valid object after Dest () is returned.
The following example shows how to embed an inner class in any scope:
: Parcel5.java
//Nesting a class within a scope
package c07.innerscopes;
public class Parcel5 {
private void internaltracking (Boolean b) {
if (b) {
class Trackingslip {
private St Ring ID;
Trackingslip (String s) {
id = s;
}
String Getslip () {return id;}
}
Trackingslip ts = new Trackingslip ("slip");
String s = ts.getslip ();
}
Can ' t use it here! Out of scope:
//! Trackingslip ts = new Trackingslip ("X");
}
public void Track () {internaltracking (true);}
public static void Main (string[] args) {
Parcel5 p = new Parcel5 ();
P.track ();
}
///:~
The Trackingslip class is nested within the scope of an if statement. This does not mean that the class is created conditionally-it will be compiled with everything else. However, it is not available beyond the scope in which it is defined. Besides these, it does not seem to be any different from a normal class.
The following example looks a little strange:
//: Parcel6.java//A method This returns an anonymous inner class package c07.innerscopes;
public class Parcel6 {public Contents cont () {return new Contents () {private int i = 11;
public int value () {return i;} };
Semicolon required in this case} public static void Main (string[] args) {Parcel6 p = new Parcel6 ();
Contents C = P.cont (); }
} ///:~
The
Cont () method merges the creation code of the return value and the class used to represent that return value. In addition, this class is anonymous-it has no name. And what seems even more confusing is that we're going to create a Contents object:
return new Contents ()
But after that, before we met the semicolon, we said, "Wait, let me play a trick in a class definition first":
return new Contents () {
private int i = one;
public int value () {return i;}
};
This strange syntax is meant to "create an object of an anonymous class derived from contents." The handle returned by the new expression automatically traces the shape into a contents handle. The syntax of the anonymous inner class is actually expressed as follows:
Class Mycontents extends Contents {
private int i = one;
public int value () {return i;}
}
Return to new Mycontents ();
in the anonymous inner class, the contents is created with a default builder. The following code shows what the underlying class needs to do with a builder that has an argument:
: Parcel7.java
//An anonymous inner class that calls the
//Base-class constructor Package-C07.innerscopes
;
public class Parcel7 {public
wrapping wrap (int x) {
//Base constructor call: Return
new Wrapping (x) {
PU Blic int value () {return
super.value () *;}
};//semicolon required
} public
static void Mai N (string[] args) {
Parcel7 p = new Parcel7 ();
Wrapping W = p.wrap (ten);
}
} ///:~
That is, we simply pass the appropriate arguments to the underlying class builder, which is represented here as passing X in new wrapping (x). Anonymous classes cannot have a builder, which is different from the usual practice when calling super ().
In the preceding two examples, the semicolon does not mark the end of the class body (unlike C + +). Instead, it marks the end of the expression used to contain the anonymous class. Therefore, it is entirely equivalent to using semicolons anywhere else.
What happens when you want to initialize an object of an anonymous inner class in some way? Since it is anonymous and has no name assigned to the builder, we cannot have a builder. However, we can initialize when we define our own fields:
: Parcel8.java
//An anonymous inner class that performs
//initialization. A briefer version
//of Parcel5.java.
Package c07.innerscopes;
public class Parcel8 {
//Argument must is final to use inside
//Anonymous inner class: public
destination de St (Final String dest) {return
new destination () {
private String label = dest;
Public String Readlabel () {return label;}}
;
}
public static void Main (string[] args) {
Parcel8 p = new Parcel8 ();
Destination D = p.dest ("Tanzania");
}
///:~
If you attempt to define an anonymous inner class and want to use an object that is defined outside the anonymous inner class, the compiler requires that the external object be the final property. That's why we set the dest () argument to final. If you forget to do this, you will get a compile-time error prompt.
As long as you just want to allocate a field, the above method is certainly feasible. But what if you need to take some kind of builder-like action? Initialized with an instance of Java 1.1, we can effectively create a builder for an anonymous inner class:
: Parcel9.java
//Using "instance initialization" to perform
//construction on an anonymous inner class
PAC Kage C07.innerscopes;
public class Parcel9 {public
destination
dest (final String dest, final float price) {return
new destination ( ) {
private int cost;
Instance initialization for each object:
{The cost
= Math.Round (price);
if (Cost > m)
System.out.println ("over budget!");
}
Private String label = dest;
Public String Readlabel () {return label;}}
;
}
public static void Main (string[] args) {
Parcel9 p = new Parcel9 ();
Destination D = p.dest ("Tanzania", 101.395F);
}
} ///:~
In the instance initialization module, we can see that the code cannot be executed as part of a class initialization module (that is, an if statement). So in fact, an instance initialization module is a builder of an anonymous inner class. Of course, its functionality is limited; we cannot overload the instance initialization module, so we can only own one of these builders.