Java is an object-oriented advanced programming language. Its outstanding place is that it is concise. A programmer is to do is create a class class and define interface (Define Interface), so. Of course, this simple and beautiful is cost, such as losing the extensive data type of Enum, is a small loss. Prior to Java 1.5, programmers have to solve this problem through some ways to work. For example, universal enumeration alternatives and type safety alternatives (Type Safe Enum). Before you officially discuss the enumeration type of Java 1.5, let us first review these two enumeration alternatives. One. Integer enumeration alternatives, for example, we have to define an enumeration type in the four seasons of spring and summer, if an integer is used to simulate, it looks probably:
Public Class Season
{
Public static final int SPRING = 0;
Public static final int summer = 1;
Public static final int fall = 2;
Public static final int winter = 3;
}
For the above programs, everyone may not be unfamiliar, because you may have used this integer type enumeration multiple times in your program. Although this is a very common alternative, this does not mean it is a good alternative. This simple approach has a lot of serious problems. Question 1: Type Security Problem First, use an integer we cannot guarantee type security issues. For example, we design a function, our intent is to bring the caller into a value among the spring and summer autumn and winter, however, using "integer enumeration" we can't guarantee that users are not incoming other unexpected values. As follows:
......
Public void seasontest (int season)
{
// Season should be season.spring, season.summer, season.fall, season.winter
/ / But we can't guarantee this
......
}
Public void foo ()
{
Seasontest (season.summer); // Ideally used method
Seasontest (5); // Error call
}
......
Program seasontest (season.summer) is our expectation method, while Seasontest (5) is an obvious error, but when compiled, the compiler will consider this is a legal function call to pass. This is obviously the purpose of not conforming to Java type safety. Question 2: The expression of the string uses most cases of enumeration, we need to get enumeration type characters, such as Spring, Summer, Fall, Winter, or even Chinese spring, summer, autumn, winter . But this integer type of enumeration and characters do not contact, we have to use some other auxiliary functions to achieve such effects, which is not convenient enough, that is, foreigners are not a "gener solution".
......
Public String GetSeasonstring (int season)
{
IF (Season == Season.spring)
Return "Spring;
Else IF (Season == Season.summrt)
Return "SUMMER;
......
}
two. ENUM alternatives for type safety alternatives are a method of being called type security. Although the specific implementation of different people may be different, their core ideas are consistent. Let us first look at a simple example. Public Class Season
{
Private season (String S)
{
m_name = s;
}
Public String Tostring ()
{
Return M_Name;
}
PRIVATE FINAL STRING M_NAME;
Public Static Final Season Spring = New Season ("Spring");
Public Static Final Season Summer = New Season ("SUMMER");
Public Static Final Season Fall = New Season ("Fall");
Public Static Final Season Winter = New Season ("Winter");
}
Its features are: 1. Define a class, express enumeration values 2 with instances of this class. The public constructor is not provided to eliminate the customer's instance 3 of this class. The instance of all classes is Final, which is not allowed to have any modifications 4. The examples of all classes are public static, so customers can use it directly 5. All enumeration values are unique, so the == operator can be used in the program without having to use the equals () method of the fee to ensure that type security is guaranteed. If there is such a call program
Public Class ClientProgam
{
.
Public String MyFunction (Season Season)
{
......
}
}
Then we can rest assured that the parameters incorporated by myFunction method must be a Season type, absolutely impossible to be other types. The specific value can only be a one we give in the spring and summer of spring and summer (the only exception is incoming a null. That is a problem with other nature, all Java programs are common, not what we discuss today). Isn't this the most fundamental original intention to use enumeration! Its disadvantage is: 1. Not intuitive, not simple enough 2. Some cases are not as convenient, such as switch statement 3. Memory overhead is larger than integer, although this is not a problem for most Java programs, but for Java mobile devices may be a potential problem relating to completely implement the above source program is the most basic framework. In reality, we will add something to it, making it more perfect, more convenient. The most common is to add an integer variable to indicate the order of the enumeration value or the size level, and the English is called Ordinal. This way we can compare between each enumeration value. In addition, we may need to get all values of this enumeration to conduct traversal or loops. Sometimes we may also wish to give a string (such as summer) to get the corresponding enumeration class. If you add these common requirements to our specific implementation, then the program we have is expanded to:
Public Class Season IMPLEments Comparable
{
Private season (String S)
{
m_ordinal = m_nextordinal ;
m_name = s;
}
Public String Tostring ()
{
Return M_Name;
}
Public string name () {
Return M_Name;
}
Public int compareto (Object obj)
{
Return m_ordinal - (Season) .m_ordinal;
}
Public static final season [] VALUES ()
{
Return M_Seasons;
}
Public Static Season Valueof (String S)
{
For (int i = 0; i IF (m_seasons [i] .name (). Equals (s)) Return M_Seasons [i]; Throw New IllegalargumentException (s); } PRIVATE FINAL STRING M_NAME; Private static int m_nextordinal = 0; PRIVATE FINAL INT M_ORDINAL; Public static final season Spring; Public static final season Summer; Public Static Final Season Fall; Public static final season. Private statin m_seasons []; Static { Spring = New Season ("Spring"); Summer = New Season ("Summer"); Fall = New Season ("Fall"); Winter = New Season ("Winter"); m_seasons = (new season [] { Spring, Summer, Fall, Winter }); } } Although this example given above solves the basic requirements of the enumeration type, it is obviously not simple enough. If we want to write a lot of such enumeration classes, it will be a small task. And repeated write a similar program is very boring and easy to make mistakes. In order to liberate the programmer from these cumbersome work, some tool software has been developed to complete these duplicate work. For example, the popular Jenum, please refer to "Use Enumeration in Java" (http://tech.ccidnet.com/pub/Article/c1078_a95621_p1.html) These tool software is actually some "program generators". You define your enumeration in accordance with its grammar rules (syntax relatively simple and intuitive), then run these tool software, which transforms your definition into a complete Java class, just like the program we wrote above. Seeing this, the reader may think: "Why can't you put this tool software in the Java compiler? Don't we make a simple and convenient definition enumeration? And the specific Java class program is compiled by the compiler To generate, we don't have to manually complete such a lengthy procedure, don't you need to use a third-party tool to generate such a program? "If you have such an idea, then you will be congratulations. Because you and Java design developers think of a piece. Ok, let's take a look at the function of new enumerations in Java 1.5. Java 1.5 enumeration type in the new Java 1.5, if the first quarter of the spring, summer, autumn and winter mentioned above, then the statement is very simple, as shown below Public Enum Season { Spring, Summer, Fall, Winter } How is it, it's simple enough. Before we fully discuss, let's take a look at this small example, let's take a look at the basic requirements of an enumeration type in Java 1.5. 1. Use Keywords ENUM 2. Type name, such as Season 3. A string of allowable values, such as the Spring and Summer Four Seasons defined above 4. Enumeration can be individually defined in a file or embedded in other Java classes. In addition to this basic requirement, users have some other options 1. Enumerations can implement one or more interfaces 2. You can define a new variable 3. A new method 4 can be defined. You can define the specific use and characteristics of these options that are different depending on the specific enumeration value. We will gradually mentioned in the following examples. So what is the inner connection of such a small program and the "type security enumeration alternative" scheme mentioned earlier? From the surface, it seems to have a large phase, but if we go deep into step, it will find that the essence of the two is almost exactly the same. How is it, is it somewhat surprised? After compiling the above enumeration, we got Season.class. After we compile this season.class, we will find the true face of Java 1.5 enumeration, and its anti-compiled source program is: public final class season extends enum { Public static final season [] VALUES () { Return (Season []) $ VALUES.CLONE (); } Public Static Season Valueof (String S) { Season aseason [] = $ values; INT i = aSeason.Length; For (int J = 0; j
{ Season season = aseason [j]; IF (season.name (). Equals (s)) Return season; } Throw New IllegalargumentException (s); } Private season (String S, INT I) { Super (S, I); } Public static final season Spring; Public static final season Summer; Public Static Final Season Fall; Public static final season. Private stat Final Season $ VALUES []; Static { Spring = New Season ("Spring", 0); Summer = New Season ("Summer", 1); Fall = New Season ("Fall", 2); Winter = New Season ("Winter", 3); $ VALUES = (New Season [] { Spring, Summer, Fall, Winter }); } } Compare this example and "Type Safety Enumeration" given earlier, you will find that they are almost the same. A more significant difference is that all enumerations of Java 1.5 are both derivatives of the Enum type. But if you look at the source program of the Enum class, you will find that it is just the base class for some basic services, in essence, Java 1.5 enumeration and what we say "Type Safety Enumeration" is Consistent. / * * @ (#) ENUM.JAVA 1.12 04/06/08 * * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. * Sun Proprietary / Confidential. Use is Subject To License Terms. * / Package java.lang; Import java.io.serializable; / ** * This is The Common Base Class of All Java Language Enumeration Types. * * @Author Josh Bloch * @Author neal Gafter * @version 1.12, 06/08/04 * @since 1.5 * / Public Abstract Class Enum Implements Comparable PRIVATE FINAL STRING NAME; Public final string name () { Return Name; } PRIVATE FINAL INT Ordinal Public final int ordinal () { Return Ordinal } protected enum (string name, int order) { THIS.NAME = Name; THIS.RINAL = Ordinal; } Public string toString () { Return Name; } Public final boolean equals (object other) {{ Return this == ot; } Public final int.comode () { Return System.Identityhashcode (this); } Protected final Object Clone () throws clonnotsupportedException { Throw new clonenotsupportedException (); } Public Final Int Compareto (e o) { ENUM Other = (Enum) O; ENUM SELF = THIS; IF (self.getclass ()! = other.getclass () && // Optimization Self.getDeclaringclass ()! = other.getDeclaringClass ()) Throw new classcastexception (); Return Self.ordinal - Other.ordinal; } Public Final Class Class Clazz = getClass (); Class Zuper = Clazz.getsuperClass (); Return (zuper == enum.class)? CLAZZ: ZUPER; } Public Static String name) { T Result = Enumtype.enumConstantDirectory (). Get (name); IF (Result! = NULL) Return Result; IF (Name == Null) Throw new nullpointerException ("name is null"); throw new iLlegaArgumentException "NO ENUM Const" EnumType "." Name); } } Constructor with parameters Now let us look at a more complicated example to further explain the essence of Java 1.5 enumeration. The following program is the enumeration model provided by Sun, which is the ability to illustrate the enumeration in the nine planets in the solar system - that is, we can create a new constructor, rather than just the default of ENUM. that one. We can also define new methods, constants, and so on. Public Enum Planet { Mercury (3.303e 23, 2.4397e6), Venus (4.869e 24, 6.0518e6), Earth (5.976e 24, 6.37814e6), MARS (6.421E 23, 3.3972E6), Jupiter (1.9e 27, 7.1492e7), Saturn (5.688E 26, 6.0268E7), Uranus (8.686e 25, 2.5559e7), Neptune (1.024e 26, 2.4746e7), PLUTO (1.27e 22, 1.137e6); Private final double mass; // in kilograms Private Final Double Radius; // in Meters Planet (Double Mass, Double Radius) { THIS.MASS = MASS; THIS.RADIUS = RADIUS; } PRIVATE DOUBLE () {Return Mass;} Private Double Radius () {Return Radius;} // universal gravitational constant (M3 KG-1 S-2) Public Static Final Double G = 6.67300E-11; Double SurfaceGravity () { Return G * Mass / (Radius * Radius); } Double SurfaceWeight (double Othermass) { Return Othermass * SurfaceGravity (); } } Compile this program and then recompile, we get this program, which is the source program actually used by Java virtual machines. Public Final Class Planet Extends ENUM { Public Static Final Planet [] VALUES () { Return (Planet []) $ VALUES.CLONE (); } Public Static Planet Valueof (String S) { Planet Aplanet [] = $ values; INT i = APLANET.LENGTH; For (int J = 0; j
{ Planet Planet = Aplanet [J]; IF (planet.name (). Equals (s)) Return Planet; } Throw New IllegalargumentException (s); } Private Planet (String S, INT I, DOUBLE D, DOUBLE D1) { Super (S, I); Mass = d; RADIUS = D1; } Private Double Mass () { Return mass; } Private Double Radius () { Return Radius; } Double SurfaceGravity () { RETURN (6.6729999999999999E-011D * mass) / (RADIUS * RADIUS); } Double SurfaceWeight (Double D) { Return D * SurfaceGravity (); } Public Static Final Planet Mercury; Public Static Final Planet Venus; Public Static Final Planet Earth; Public Static Final Planet Mars; Public Static Final Planet Jupiter; Public Static Final Planet Saturn; Public Static Final Planet Uranus; Public Static Final Planet Neptune; Public Static Final Planet Pluto; PRIVATE FINAL DOUBLE MAS; PRIVATE FINAL DOUBLE RADIUS; PUBLIC STATIC FINAL DOUBLE G = 6.6729999999999999999999999E-011D; Private static final planet $ values []; Static { Mercury = new planet ("Mercury", 0, 3.3030000000000001E 023D, 2439700D); Venus = New Planet ("VENUS", 1, 4.8690000000000001E 024D, 6051800D); Earth = New Planet ("Earth", 2, 5.9760000000000004E 024D, 6378140D); Mars = New Planet ("MARS", 3, 6.420999999999999E 023D, 3397200D); Jupiter = New Planet ("Jupiter", 4, 1.900000000000000001E 027D, 71492000D); Saturn = New Planet ("Saturn", 5, 5.6879999999999999999999999999999999999999999999999999999999999999999999999999999998E 026D, 60268000D); Uranus = New Planet ("Uranus", 6, 8.686e 025d, 25559000d); Neptune = New Planet ("Neptune", 7, 1.0239999999999999999999999999999999999999999999999999999999999999999999999999999999E 026D, 24746000D); Pluto = New Planet ("Pluto", 8, 1.2700000000000001E 022D, 1137000D); $ VALUES = (New Planet [] { Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto }); } } From the anti-compiled program, there is no mysterious thing in this Java 1.5. It is just a slight change of constructor, adds several variables and functions. The "Type Security Enumeration" mentioned earlier can complete the same work. The method attached to the specific variable is also a relatively representative example. That is, in four enumeration values listed, each value has its corresponding class definition segment (that is, the so-called Value-Specific Class Bodies). In this way, the addition and subtraction of four enumeration values have the same version of the EVAL function implementation method. Use Java 1.5 Enum service, its source program is: Public Enum Operation { Plus {Double Eval (Double X, Double Y) {Return X Y;}}, Minus {Double Eval (Double X, Double Y) {Return X - Y;}}, Times {Double Eval (double x, double y) {return x * y;}}, Divide {Double Eval (double x, double y) {return x / y;}}; Abstract Double Eval (Double X, Double Y); } This program looks more complicated. If we reflect the Operation.class file generated by the Java compiler, we will find that its principle is not complicated. Public Abstract Class Operation Extends ENUM { Public static final operation [] VALUES () { Return (Operation []) $ VALUES.CLONE (); } Public Static Operation Valueof (String S) { Operation aOperation [] = $ values; I = aoperation.length; For (int J = 0; j
{ Operation Operation = aoperty [J]; IF (Operation.Name (). Equals (s)) Return Operation; } Throw New IllegalargumentException (s); } Private Operation (String S, INT I) { Super (S, I); } Abstract Double Eval (Double D, Double D1); PUBLIC STATIC Final Operation Plus; Public static final operation minus; Public static final operation Times; Public static final operation divide; Private static final operation $ values []; Static { Plus = New Operation ("plus", 0) { Double Eval (Double D, Double D1) { RETURN D D1; } } Minus = New Operation ("minus", 1) { Double Eval (Double D, Double D1) { RETURN D - D1; } } Times = New Operation ("Times", 2) {Double Eval (Double D, Double D1) { Return D * D1; } } Divide = New Operation ("Divide", 3) { Double Eval (Double D, Double D1) { RETURN D / D1; } } $ VALUES = (New Operation "{ Plus, Minus, Times, Divide }); } } So how do we solve such a problem before Java 1.5? If you use object-oriented principles to solve this problem, the source program is: Public Abstract Class Operation { PRIVATE FINAL STRING M_NAME; Operation (String Name) {m_name = name; Public Static Final Operation Plus = New Operation ("Plus") { Protected Double Eval (double x, double y) { Return X Y; } } Public static final operation minus = new operation ("minus") { Protected Double Eval (double x, double y) { Return X - Y; } } Public static final operation timees = new operation ("timees") { Protected Double Eval (double x, double y) { Return x * y; } } Public static firm Operation devide = new operation ("devide") { Protected Double Eval (double x, double y) { Return X / Y; } } Abstract Double Eval (Double X, Double Y); Public string toString () {return m_name;} Private static int m_nextORIDNAL = 0; PRIVATE FINAL INT M_ORDINAL = m_nextoridnal ; Private static firm operation [] value = { Plus, Minus, Times, Devide } } The essence of this method is consistent with ENUM in Java 1.5. That is to define an abstract function (Abstract function) and then each Enum value provides a specific implementation method. Before Java 1.5, some people may use a simple way to complete similar tasks. such as: Public Class Operation { PRIVATE FINAL STRING M_NAME; Operation (String Name) {m_name = name; Public Static Final Operation Plus = New Operation ("Plus"); Public static final operation minus = new operation ("minus"); Public static final operation timees = new operation ("time"); public static final operation devide = new operation ("devide"); Public Double Eval (Double X, Double Y) { IF (this == OPERATION.PLUS) { Return X Y; } Else IF (this == Operation.minus) { Return X - Y; } Else IF (this == Operation.Times) { Return x * y; } Else if (this == Operation.devide) { Return X / Y; } Return -1; } Public string toString () {return m_name;} Private static int m_nextORIDNAL = 0; PRIVATE FINAL INT M_ORDINAL = m_nextoridnal ; Private static firm operation [] value = { Plus, Minus, Times, Devide } } The difference between this implementation and the method mentioned above is that it eliminates the abstract class and abstract function, using conditional judgment statements to give the addition and subtraction and divide four enumeration values in different methods. From the effect, it is entirely possible, but this is not advocated by object-oriented programming. So this kind of thought is not introduced into Java 1.5. Convenient Switch features before Java 1.5, Switch statements can only be used in combination with int, short, char, and byte. Now, in Java 1.5 enumeration, you can easily use the Switch statement. such as: Public class enumtest { Public Enum grade {a, b, c, d, e, f, incomplete} PRIVATE M_GRADE; Public enumtest (grade grade) { THIS.M_GRADE = GRADE; Testing (); } Private void testing () { Switch (this.m_grade) { Case A: System.out.println (grade.a.tostring ()); Break; Case B: System.out.println (grade.b.tostring ()); Break; Case C: System.out.println (grade.c.tostring ()); Break; Case D: System.out.println (grade.d.tostring ()); Break; Case E: System.out.println (grade.e.tostring ()); Break; Case F: System.out.println (grade.f.tostring ()); Break; Case INCOMPLETE: System.out.println (grade.Incomplete.toString ()) Break; } } Public static void main (String [] args) { New enumtest (grade.a); } } (Note: A, B, C, D, E, F, INCOMPLETE are the universal learning grades in the American school) Looking above this example, everyone must not help but ask: "Is Java 1.5 Switch features enhanced? "In fact, things are not like this, we just see a description. After the compiler is compiled, everything goes back. Switch still jumps on an integer. Below is the anti-compiled programpad: ... // Private void testing () { Static class _cls1 { Static Final Int $ SWITCHMAP $ ENUMTEST1 $ GRADE []; Static { $ SWITCHMAP $ ENUMTEST1 $ grade = new int = new int = inGT [grade]; Try { $ SWITCHMAP $ ENUMTEST1 $ GRADE [grade.a.ordinal ()] = 1; } Catch (nosuchfielderror nosuchfielderror) {} Try { $ SWITCHMAP $ ENUMTEST1 $ GRADE [grade.b.ordinal ()] = 2; } Catch (nosuchfielderror nosuchfielderror1) {} Try { $ SWITCHMAP $ ENUMTEST1 $ GRADE [grade.c.ordinal ()] = 3; } Catch (nosuchfielderror nosuchfielderror2) {} Try { $ SWITCHMAP $ ENUMTEST1 $ GRADE [grade.d.ordinal ()] = 4; } Catch (nosuchfielderror nosuchfielderror3) {} Try { $ STCHMAP $ ENUMTEST1 $ grade [grade.e.ordinal ()] = 5; } Catch (nosuchfielderror nosuchfielderror4) {} Try { $ SWITCHMAP $ ENUMTEST1 $ GRADE [grade.f.ordinal ()] = 6; } Catch (nosuchfielderror nosuchfielderror5) {} Try { $ SWITCHMAP $ ENUMTEST1 $ grade [grade.Incomplete.ordinal ()] = 7; } Catch (NosuchfieldError Nosuchfielderror6) {} } } Switch (_cls1..witchmap.enumtest1.grade [m_grade.ordinal ()]) { Case 1: // '/ 001' System.out.println (grade.a.tostring ()); Break; Case 2: // '/ 002' System.out.println (grade.b.tostring ()); Break; Case 3: // '/ 003' System.out.println (grade.c.tostring ()); Break; Case 4: // '/ 004' System.out.println (grade.d.tostring ()); Break; Case 5: // '/ 005' System.out.println (grade.e.tostring ()); Break; Case 6: // '/ 006' System.out.println (grade.f.tostring ()); Break; Case 7: // '/007'system.out.println (grade.Incomplete.toString ()); Break; } } The essence of enumeration in Java 1.5 came from above, and it was here, readers will certainly ask, why Java 1.5 enumeration and Java 1.5 "type security enumeration" are so similar (thrown GENERICS in Java 1.5 does not say)? In fact, this is very good to understand. Everyone maybe noticed such a detail, the first author of the Enum source program in Java 1.5 is Josh Bloch. The Java Master published the "Effective Java Programming Language Guide" in 2001, the Java Classic Programming Manual, in the fifth chapter of the "Effective Java Programming Language Guide", has fully clearly expounded the core ideology and implementation of the type of security enumeration. Enumeration in Java 1.5 is not a new idea, but an implementation and improvement of the original thoughts. Its progress is that these ideas are reflected in the Java compiler, and the programmer sees a simple, intuitive enumeration service, which will originally need to be manually completed or through the task completed by the third party tool. Put in the compiler. Of course, the enumeration implementation in Java 1.5 is not "perfect". It is not an enumeration implemented in the Java virtual machine hierarchy, but is implemented in the compiler hierarchy, essentially a "Java Program Automatic Generator". The benefits of this implementation are self-evident. Because it does not have any new requirements for Java virtual machines, this greatly reduces the pressure of Java virtual machines, and Java 1.5 virtual machines do not have to make big changes, and it can be improved and perfected on the basis. At the same time, this approach also makes the program have a better forward compatibility. This guiding ideology is completely consistent with Java Generics, increasing the function in the Java compiler, rather than big fierce Java virtual machines. So we can regard the new enumeration in Java 1.5 as a "syntax sugar". Of course, it is not in the virtual machine hierarchy to expose some problems in some cases, sometimes there will be some None class, and we have some functions. The situation is the same as Java Generics I mentioned later (please see http://tech.ccidnet.com/pub/Article/c1078_a170543_p1.html). Let us discuss several significant problems. Special Enum classes can be seen from the previous example, all enumeration types are implicitly derived from base class java.lang.enum. From the surface, this Enum class and other Java classes have no difference. If you look at the Enum source program given in front, then this problem is very obvious. Since it is an ordinary Java class, can we use it like other classes? If we say, we expand this Enum class to generate a subclass: Public Class Myenum Extends Enum { Protected Enum (String Name, int Ordinal); Protected Object Clone (); } Syntax, this definition is completely legal. But if you try to compile this program, Java's compiler will give you an error message. That is to say, the Enum class can be extended inside, and you do not allow you to explicitly expand directly. So this enum is similar to a class of "special", and the compiler has "special policy" on it. In theory, this is a non-recommended practice. It is clear that it is a non-final class, but you can't go to Extends it, this is contrary to the most basic principles. This is a slap in the realization of Java 1.5 enumeration, and it is unfortunate that people feel some regret. Unable to extend the Enum type When we want us to define the enumeration, it is like other classes we define. This requirement is very reasonable regardless of the logical perspective or from the object-oriented programming principle. For example, the Operation enumeration we defined earlier, where we defined four basic operations of the addition and subtraction. If one day we want to expand this enumeration, join the ability to take the logarithm and the multiplication, we may naturally think of this method: public Enum OperationExt Extends Operation { LOG {Double Eval (Double X, Double Y) {Return Math.log (Y) / Math.log (x);}} Power {Double Eval (Double X, Double Y) {Return Math.Power (X, Y);}}, } Unfortunately, when you try to compile such a program, the compiler gives an error message and compiles will not pass. That is, we lost the ability to extend an enumeration type. And before Java 1.5, we can manually do this. For example, we define the constructor of the Operation base class as protected, then we can easily extend the Operation class, and its source program is: Abstract Class OperationExt Extends OPETATIONEXT { PRIVATE FINAL STRING M_NAME; Operation (String Name) {m_name = name; Public Static Final Log = New Operation ("log") { Protected Double Eval (double x, double y) { Return Math.log (Y) / Math.log (x); } } Public Static Final Power = New Operation ("Power") { Protected Double Eval (double x, double y) { Return Math.log (X, Y); } } Protected Double Eval (Double X, Double Y); Public string toString () {return m_name;} Private static int m_nextORIDNAL = 0; PRIVATE FINAL INT M_ORDINAL = m_nextoridnal ; Private static firm operation [] value = { LOG, POWER; } }