请参阅下面基于
stakx’s question的.net代码的Java实现.
如果客户端尝试弹出太多,编译器将发出未定义的方法错误.例如,发出以下呼叫:
new EmptyStack< Integer>().push(1).pop().getTop()
将调用getTop()会导致未定义的方法错误.
class GenericStack {
@Test public void test() {
final IStack stack = new EmptyStack();
assertEquals(new Integer(1), stack.push(1).getTop());
assertEquals(new Integer(2), stack.push(1).push(2).getTop());
assertEquals(new Integer(1), stack.push(1).push(2).pop().getTop());
}
interface IStack {
INonEmptyStack> push(T x);
}
interface IEmptyStack extends IStack
{
@Override INonEmptyStack> push(T x);
}
interface INonEmptyStack>
extends IStack
{
T getTop();
TStackBeneath pop();
@Override INonEmptyStack>
push(T x);
}
class EmptyStack implements IEmptyStack {
@Override public INonEmptyStack> push(T x) {
return new NonEmptyStack>(x, this);
}
}
class NonEmptyStack> extends Object
implements INonEmptyStack {
private final TStackBeneath stackBeneathTop;
private final T top;
NonEmptyStack(T top, TStackBeneath stackBeneathTop) {
this.top = top;
this.stackBeneathTop = stackBeneathTop;
}
@Override public T getTop() {
return top;
}
@Override public TStackBeneath pop() {
return stackBeneathTop;
}
@Override public INonEmptyStack>
push(T x) {
return
new NonEmptyStack>(x, this);
}
}
// The following client code at the request of @TacticalCoder demonstrates
// some of the benefits (and limitations) of this implementation.
@Test public void testRandomPopper() {
IStack> stack = randomPopper(new EmptyStack(), 20);
// This assertion will fail 1 out of .3^20 runs
assertTrue(stack instanceof INonEmptyStack,?>);
assertFalse(stack instanceof IEmptyStack>);
}
public IStack randomPopper(IStack s, final int N) {
IStack stack;
if(N<1)
return s;
stack = s.Push(1);
for (int i = 1; i < N; i++) {
INonEmptyStack tStack = stack.Push(i+1);
if(Math.random()<0.3) {
stack = tStack.Pop();
} else {
stack = tStack;
}
}
return stack;
}
@Test public void testDrainStack() {
IStack stack = randomPopper(new EmptyStack(), 20);
IStack> maybeEmptyStack = drainStack(stack);
assertTrue(maybeEmptyStack instanceof IEmptyStack);
IEmptyStack> definitelyEmptyStack = (IEmptyStack>) maybeEmptyStack;
assertTrue(definitelyEmptyStack instanceof IEmptyStack>);
}
@Test public void testCastNonEmptyStackToEmptyStack() {
IStack stack = randomPopper(new EmptyStack(), 20);
IStack> maybeEmptyStack = stack;
assertFalse(maybeEmptyStack instanceof IEmptyStack);
// Below cast should issue warning! Doesn't and issues runtime error.
IEmptyStack> definitelyEmptyStack = (IEmptyStack>) maybeEmptyStack;
assertFalse(definitelyEmptyStack instanceof IEmptyStack>);
}
public IStack> drainStack(IStack> stack) {
for (;stack instanceof INonEmptyStack,?>;)
stack = ((INonEmptyStack,?>) stack).Pop();
return stack;
}
}