简体   繁体   English

如何在Java中设计类型安全的堆栈,防止从空列表中弹出?

[英]How can I design a type-safe stack in Java preventing pops from an empty list?

This is an offshoot of these two questions: 1 , 2 . 这是这两个问题的一个分支: 12

I'd like to implement type-safe data structures in Java that prevent nonsensical operations. 我想在Java中实现类型安全的数据结构,以防止无意义的操作。 For example, if the compiler knows I have an instance of an empty stack, it shouldn't allow me to call pop on the empty stack. 例如,如果编译器知道我有一个空堆栈的实例,它不应该允许我在空堆栈上调用pop。

As an example, how would I implement such a (generic) stack in Java? 作为一个例子,我如何在Java中实现这样的(通用)堆栈?

See below Java implementation based on .net code from stakx's question . 请参阅下面基于stakx问题的 .net代码的Java实现。

If a client tries to pop too far, the compiler will issue an undefined method error. 如果客户端尝试弹出太多,编译器将发出未定义的方法错误。 For example, issuing calls like: 例如,发出以下呼叫:

new EmptyStack<Integer>().push(1).pop().getTop()

will result in an undefined method error on the call to getTop() . 将调用getTop()会导致未定义的方法错误。

class GenericStack {
   @Test public void test() {
      final IStack<Integer> stack = new EmptyStack<Integer>();
      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<T> { 
      INonEmptyStack<T, ? extends IStack<T>> push(T x);
   }

   interface IEmptyStack<T> extends IStack<T>
   {
       @Override INonEmptyStack<T, IEmptyStack<T>> push(T x);
   }

   interface INonEmptyStack<T, TStackBeneath extends IStack<T>> 
      extends IStack<T>
   {
       T getTop();
       TStackBeneath pop();
       @Override INonEmptyStack<T, INonEmptyStack<T, TStackBeneath>> 
          push(T x);
   }

   class EmptyStack<T> implements IEmptyStack<T> {
      @Override public INonEmptyStack<T, IEmptyStack<T>> push(T x) {
         return new NonEmptyStack<T, IEmptyStack<T>>(x, this);
      }
   }

   class NonEmptyStack<T, TStackBeneath extends IStack<T>> extends Object 
      implements INonEmptyStack<T, TStackBeneath> {
      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<T, INonEmptyStack<T, TStackBeneath>> 
         push(T x) {
         return 
            new NonEmptyStack<T, INonEmptyStack<T, TStackBeneath>>(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<Integer>(), 20);
      // This assertion will fail 1 out of .3^20 runs 
      assertTrue(stack instanceof INonEmptyStack<?,?>); 
      assertFalse(stack instanceof IEmptyStack<?>); 
   }

   public IStack<Integer> randomPopper(IStack<Integer> s, final int N) {
      IStack<Integer> stack;
      if(N<1)
         return s;
      stack = s.Push(1);
      for (int i = 1; i < N; i++) {
         INonEmptyStack<Integer,?> tStack = stack.Push(i+1);
         if(Math.random()<0.3) {
            stack = tStack.Pop();            
         } else {
            stack = tStack;
         }
      }
      return stack;
   }

   @Test public void testDrainStack() {
      IStack<Integer> stack = randomPopper(new EmptyStack<Integer>(), 20);
      IStack<?> maybeEmptyStack = drainStack(stack);
      assertTrue(maybeEmptyStack instanceof IEmptyStack);
      IEmptyStack<?> definitelyEmptyStack = (IEmptyStack<?>) maybeEmptyStack;
      assertTrue(definitelyEmptyStack instanceof IEmptyStack<?>); 
   }

   @Test public void testCastNonEmptyStackToEmptyStack() {
      IStack<Integer> stack = randomPopper(new EmptyStack<Integer>(), 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;
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Java中进行类型安全的Xpath查询? - How can I do type-safe Xpath queries in Java? 是否有一种类型安全的方法将空列表作为参数传递给java? - Is there a type-safe way to pass an empty list as an argument in java? 我们如何编写一个函数List multiPop(int k)来从堆栈中弹出k个元素,或者直到堆栈为空? - How can we write a function List multiPop(int k) that pops k elements from the stack or until the stack is empty? 如何验证特定类型并使我的列表“类型安全” - How to validate a specific type and make my list "type-safe" 如何使用转换器从其他类型的Iterable获取泛型类型安全的Iterble? (Java 7) - How to get a generic type-safe Iterble from Iterable of other type, with a convertor? (Java 7) 类型安全整数的设计模式? - Design patterns for type-safe integers? 从枚举(Java)实例化/返回时的类型安全接口 - Type-safe interface when instantiated/returned from enum (Java) 是否存在&#39;reduce&#39;的类型安全的Java实现? - Is there a type-safe Java implementation of 'reduce'? 以类型安全的方式在Java中表示JSON - Representing JSON in Java in a type-safe way Scala 和 Java 的类型安全生成器库 - Type-safe Builder Library for Scala and Java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM