Java 1.5 Tiger A Developers Notebook [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Java 1.5 Tiger A Developers Notebook [Electronic resources] - نسخه متنی

David Flanagan, Brett McLaughlin

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید








3.9 Value-Specific Class Bodies


In covering the more advanced

features of enums, I can't leave out the
ability to define value-specific class bodies. That sounds sort of fancy, but
all it means is that each enumerated value within a type can define
value-specific methods. This is a rather obscure bit of functionality, but
sort of cool to talk about around the water cooler.


3.9.1 How do I do that?


Example 3-9 is an example of a class that determines how the perform( ) method is executed based on the enumerated value. It's a perfect example
of value-specific class bodies.


Example 3-9. Value-specific class bodies in an enum


// These are the opcodes that our stack machine can execute.
enum Opcode {
// Push the single operand onto the stack
PUSH(1) {
public void perform(StackMachine machine, int[] operands) {
machine.push(operands[0]);
}
}, // Remember to separate enum values with commas
// Add the top two values on the stack and put the result
ADD(0) {
public void perform(StackMachine machine, int[] operands) {
machine.push(machine.pop( ) + machine.pop( ));
}
},
/* Other opcode values have been omitted for brevity */
// Branch if Equal to Zero
BEZ(1) {
public void perform(StackMachine machine, int[] operands) {
if (machine.pop( ) == 0) machine.setPC(operands[0]);
}
}; // Remember the required semicolon after last enum value
// This is the constructor for the type.
Opcode(int numOperands) { this.numOperands = numOperands; }
int numOperands; // how many integer operands does it expect?
// Each opcode constant must implement this abstract method in a
// value-specific class body to perform the operation it represents.
public abstract void perform(StackMachine machine, int[] operands);
}

NOTE

This example is
lifted straight
out of Java in a
Nutshell, Fifth
Edition (O'Reilly).

Skipping past the individual types (which you should already understand),
the method that each value should implement is defined:
perform( ), which takes two arguments. Finally, each value is followed
by an opening curly brace, one or more value-specific methods, and then
a closing curly brace. This works in conjunction with any constructor that
must be supplied a value, as this enum has. The end result, frankly, is
one of the oddest looking Java constructs you'll ever see.


3.9.2 What just happened?


In the lab on Creating an Enum, I mentioned that enumerated type values
are created and marked as final (in addition to being public and
static), ensuring that they aren't changed by some malicious or
unknowing programmer. In the case of a value-specific class body,
though, this isn't possible. Instead, an anonymous subclass of the type is
created, and the value becomes a singleton instance of that subclass.
This still ensures that multiple instances of the same value aren't floating
around, but it does change what's going on at the compiler level a
bit. Despite this, you still can't extend an enum (see Extending an Enum
for more details).

NOTE

I suppose you
could really
clutter things up
with generics and
varargs, but you
get the idea...
value-specific class
bodies are often
a pain to debug
for even mid-level
programmers,
because of their
unusual syntax.


3.9.3 What about...


...just using a more generic method that determines what to do based on
a switch statement? Well, that's a better idea, to be honest. Here's the
(much cleaner) way to write OpCode:


// These are the the opcodes that our stack machine can execute.
abstract static enum Opcode {
PUSH(1),
ADD(0),
BEZ(1); // Remember the required semicolon after last enum value
int numOperands;
Opcode(int numOperands) { this.numOperands = numOperands; }
public void perform(StackMachine machine, int[] operands) {
switch(this) {
case PUSH: machine.push(operands[0]); break;
case ADD: machine.push(machine.pop( ) + machine.pop( )); break;
case BEZ: if (machine.pop( ) == 0) machine.setPC(operands[0]); break;
default: throw new AssertionError( );
}
}
}

This is so painfully simpler than the first version of OpCode that I hesitated
to even include this labbut for completeness, here it is. If at all
possible, though, consider using switch in your method bodies to direct
program flow, rather than value-specific class bodies.


/ 131