栈在数据结构当中称为一种线性表,它限制只能在表的一端进行插入或删除操作。这一端就叫做栈顶,反之另一端则称为栈底。
栈有个明显的特征是后进先出(Last in first out),这一特征无论在java或者数据结构中我们都遵循。
栈在java中我们称为Stack类,它是Vector类的子类,而Vector又是List接口的子接口。
既然说到Vector类,我们延伸一个知识点,即Vector与ArrayList的区别:
1. Vector的方法都是同步的(Synchronized),是线程安全的(thread-safe),而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好
2.当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。
栈的操作
栈除了继承了Vector类的所有方法之外,它还有自己独特的方法:
boolean empty():判断堆栈是否为空。
Object peek(): 返回栈顶元素,但不删除它。
Object pop(): 返回栈顶元素,并在这个过程中删除它。
Object push(Object element):压入element到堆栈,同时返回element。
int search(Object element):查找element对象,返回element对象所在位置的 下标,如果不存在element对象则返回-1。
注意看个方法的作用,返回类型和是否带参!下面我们通过一个自己创建的栈来演示其中的压栈,弹栈和返回栈顶元素的操作。
public class TryPre {
private List lis;
public TryPre() {
lis=new ArrayList();//创建集合对象,然后就可以接收栈元素
}
public Object push(Object ob)//压栈,该方法带参
{
return lis.add(ob);
}
public Object peek()//返回栈顶元素
{
// if(lis.size()==0)//当集合长度为0的时候就没法返回栈顶元素,所有才会发生异常
// {
// throw new TryPreException();
// }
return lis.get(lis.size()-1);
}
public Object pup()//弹栈
{
// if(lis.size()==0)//当集合长度为0的时候就没法弹栈
// {
// throw new TryPreException();
// }
Object ob=lis.get(lis.size()-1);//先存到ob里面
lis.remove(lis.size()-1);//删除栈顶元素
return ob;
} }
public class TryPreTest {
public static void main(String[] args) {
TryPre tp=new TryPre();
tp.push("01张无忌");
tp.push("02狮王");
tp.push("03鹰王");
tp.push("04蝙蝠王");
tp.push("05赵敏");
System.out.println("栈顶元素是:"+tp.peek());//当我们再一次调用peek()方法时返回的结果依然是一样的
for (int i = 0; i < 5; i++)
{
System.out.println("弹栈顺序是:"+tp.pup());
}
}
}
那么我们考虑一个问题,如果当i<5改为i<=5时会发生什么异常(会发生集合下标越界异常而不是栈空异常,这是因为这个栈是我们自己定义的栈,里面的方法也是自定义的,如果用Stack sk=new Stack()来创建对象,然后用对象去调用里面的操作方法那么当出现刚才这种情况时就会出现栈空异常)
下面我们来自定义一个异常来处理这种问题
//取消TryPre当中的注释代码和把TryPreTest中的i<5改为i<=5
public class TryPreException extends RuntimeException
{
//因为出现下标越界时没有提示强制抛出
public TryPreException()
{
// TODO Auto-generated constructor stub
super("栈空已经空了,无法弹出元素");
}
}