Stack

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Stack相关的知识,希望对你有一定的参考价值。

1,定义,last-in-first-out(LIFO)

java.lang.Object
    java.util.AbstractCollection<E>
        java.util.AbstractList<E>
            java.util.Vector<E>
                java.util.Stack<E>
                
public class Stack<E> extends Vector<E> {}

2,构造函数

//初始化一个空栈
public Stack(){}

3,主要方法

3.1 入栈

public E push(E item) {
    addElement(item);
    return item;
}

public synchronized void addElement(E obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}
//并不是说随便的就是扩容为原来的两倍的
private void ensureCapacityHelper(int minCapacity) {
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {
        Object[] oldData = elementData;
        int newCapacity = (capacityIncrement > 0)?(oldCapacity + capacityIncrement) : (oldCapacity*2);
        if(newCapacity < minCapacity) {
            newCapacity = minCapacity;
        }
        elementData = Arrays.copyOf(elementData, newCapacity);            
    }
}

注:

1,调用的Vector的添加方法;

2,在这里,扩容的时候需要注意:

  2.1:Vector的构造方法是这样的,这里有牵扯到capacityIncrement增长因子的概念,所以在Vector扩容时需要注意,它并不是说随便的就是扩容,也并不一定是原来的两倍的,而且ArrayList也是同理,并不是随便就扩容,也并不一定是原来的两倍的。

//Vector 相关概念
protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;//增长因子
public Vector(int initialCapacity, int capacityIncrement) {
    super();//Vector extends AbstractList...,protected AbstractList() {}
    if(initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
    this.elementData = new Object[initialCapacity];
    this.capacityIncrement = capacityIncrement;
}

public Vector(int intialCapacity) {
    this(intialCapacity, 0);//capacityIncrement默认为0
}
//这是我们常用的方式,默认大小为10
public Vector() {
    this(10)
}

public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if(elementData.getClass() != Object[].class) 
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

   2.2,:HashMap,是达到了HashMap的阈值threshold(默认: threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);),再去扩容。

void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K, V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K, V>(hash, key, value, e);
if(size++ >= threshold)//超过阈值
    resize(2 * table.length);//新容量再具体判断是否
}

 3.2 出栈

public synchronized E peek() {
    int len = size();
    if (len == 0)
        throw new EmptyStackException();
    return elementAt(len - 1);
}

public synchronized void removeElementAt(int index) {
    modCount++;
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
    else if (index < 0)
        throw new ArrayIndexOutBoundsException(index);
    int j = elementCount - index - 1;
    if(j > 0)
        System.arraycopy(elementData, index + 1, elementData, index, j);
    elementCount--;
    elementData[elementCount] = null;/*to let gc do its work*/    
}
//本地的方法
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

注:

1,出栈,弹出栈顶元素。

2,方法removeElementAt(int index){...},取出指定位置index的元素,需要修改后的数组重新定位,所以使用了方法System.arraycopy(...){...}方法。

3,方法System.arraycopy(...){...}是一个native方法

  (使用native关键字说明这个方法是原生函数,是用C/C++语言实现的,然后编译成DLL,由Java去调。 这些函数的实现体在DLL中,JDK的源代码中并不包含。对于不同的平台它们也是不同的。这也是java的底层机制,实际上java就是在不同的平台上调用不同的native方法实现对操作系统的访问的。

  native参考:https://en.wikipedia.org/wiki/Java_Native_Interface;)

技术分享
void objArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d,
                           int dst_pos, int length, TRAPS) {
assert(s->is_objArray(), "must be obj array");

if (!d->is_objArray()) {
  THROW(vmSymbols::java_lang_ArrayStoreException());
}

// Check is all offsets and lengths are non negative
if (src_pos < 0 || dst_pos < 0 || length < 0) {
  THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
}
// Check if the ranges are valid
if  ( (((unsigned int) length + (unsigned int) src_pos) > (unsigned int) s->length())
   || (((unsigned int) length + (unsigned int) dst_pos) > (unsigned int) d->length()) )   {
  THROW(vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
}

// Special case. Boundary cases must be checked first
// This allows the following call: copy_array(s, s.length(), d.length(), 0).
// This is correct, since the position is supposed to be an ‘in between point‘, i.e., s.length(),
// points to the right of the last element.
if (length==0) {
  return;
}
if (UseCompressedOops) {
  narrowOop* const src = objArrayOop(s)->obj_at_addr<narrowOop>(src_pos);
  narrowOop* const dst = objArrayOop(d)->obj_at_addr<narrowOop>(dst_pos);
  do_copy<narrowOop>(s, src, d, dst, length, CHECK);
} else {
  oop* const src = objArrayOop(s)->obj_at_addr<oop>(src_pos);
  oop* const dst = objArrayOop(d)->obj_at_addr<oop>(dst_pos);
  do_copy<oop> (s, src, d, dst, length, CHECK);
  }
}
View Code

3.3 查找 

public synchronized int search(Object o) {
    int i = lastIndexOf(o);
    if (i >= 0) {
        return size() - i;
    }
    return -1;
}

public synchronized int lastIndexOf(Object o) {
    return lastIndexOf(0, elementCount - 1);
}

public synchronized int lastIndexOf(Object o, int index) {
    if(index >= elementCount)
        throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
    if( o == null) {
        for(int i = index; i >= 0; i--)
            if(elementData[i] == null)
                return i;        
    } else {
        for(int i = index; i >=0; i--)
            if(o.equals(elementData[i]))
                return i;
    }
    return -1;
}

 

  

以上是关于Stack的主要内容,如果未能解决你的问题,请参考以下文章

Android - 在单个活动应用程序中使用工具栏按钮弹出 Back Stack

微信小程序代码片段

VSCode自定义代码片段——CSS选择器

谷歌浏览器调试jsp 引入代码片段,如何调试代码片段中的js

片段和活动之间的核心区别是啥?哪些代码可以写成片段?

VSCode自定义代码片段——.vue文件的模板