JVM队列和栈是什么?有什么区别?
队列和栈都是被用来预存储数据的。
操作的名称不同。队列的插入称为入队,队列的删除称为出队。栈的插入称为进栈,栈的删除称为出栈。
可操作的方式不同。队列是在队尾入队,队头出队,即两边都可操作。而栈的进栈和出栈都是在栈顶进行的,无法对栈底直接进行操作。
操作的方法不同。队列是先进先出(FIFO),即队列的修改是依先进先出的原则进行的。新来的成员总是加入队尾(不能从中间插入),每次离开的成员总是队列头上(不允许中途离队)。而栈为后进先出(LIFO),即每次删除(出栈)的总是当前栈中最新的元素,即最后插入(进栈)的元素,而最先插入的被放在栈的底部,要到最后才能删除。
JAVA数据类型-栈与队列
一. 栈(Stack)
栈是一种只允许在一端进行插入或删除的线性表,一般为先进后出(LIFO)
1、栈的操作端通常被称为栈顶,另一端被称为栈底。
2、栈的插入操作称为进栈(压栈|push);栈删除操作称为出栈(弹栈|pop)。
对于栈我是这么理解,大家应该都打过羽毛球,羽毛球盒里的球都是叠在一起的,当我们放进一颗羽毛球时肯定是叠在最上面,下次我们要用的时候拿出来还是从这个最上面的取,这种就类似栈,采用先进后出规则。
//看下源码; public class Stack<E>extends Vector<E>
Stack类继承了Vector类,它通过五个操作对类 Vector 进行了扩展 ,允许将向量视为堆栈。
主要方法:
booleanempty() 测试堆栈是否为空。
Epeek() 查看堆栈顶部的对象,但不从堆栈中移除它。
Epop() 移除堆栈顶部的对象,并作为此函数的值返回该对象。
Epush(E item) 把项压入堆栈顶部。
intsearch(Object o) 返回对象在堆栈中的位置,以 1 为基数。
栈的实现(基于数组):
public class Stack{ private final int count; private String[] stackStr; private int ptr = -1; public Stack(){ ptr = -1; this.count = 100; stackStr = new String[this.count]; } public Stack(int count){ this.count = count; ptr = -1; stackStr = new String[this.count]; } public void push(String s) throws ArrayIndexOutOfBoundsException{ if (ptr < count - 1){ stackStr[++ptr] = s; } else System.out.print(s + " 压栈溢出! \n"); } public String pop(){ String s = stackStr[ptr]; ptr--; return s; } public Boolean isEmpty(){ if (ptr == -1) return true; else return false; } public String toString(){ String s = ""; for(int i = 0; i <= ptr; i++){ s = s + stackStr[i] + " "; } return s; } public static void main(String[] args){ Stack stk = new Stack(2); stk.push("a"); stk.push("b"); stk.push("c"); print(stk.toString()); print("\n"); stk.pop(); print(stk.toString()); } static void print(String s){ System.out.print(s); } }
Java栈与堆
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
3.我们知道Java中的数据类型有两种。 一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。
另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义
int a = 3;
int b = 3;
编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b的引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。
特别注意的是,这种字面值的引用与类对象的引用不同。通过字面值的引用来修改其值,不会导致另一个指向此字面值的引用的值也跟着改变的情况。如上例,我们定义完a与 b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。 然而对于类对象的引用则不同。假定两个类对象的引用同时指向一个对象,如果一个对象引用变量修改了这个对象的内部状态,那么另一个对象引用变量也即刻反映出这个变化,我们可以看下下面这一段代码:
public class Test { private String id=""; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } private String name=""; public static void main(String[] args) { Test test=new Test(); test.setId("1"); test.setName("cc"); changeId(test); System.out.println(test.getId()); } public static void changeId(Test test) { Test tt=new Test(); //tt=test; 如删去此处 tt.setId("5"); System.out.println(tt.getId()); } }
很明显执行上段代码结果是输出
5 1
但如果删去注释符号//,使tt和test指向同一个对象,则此时运行结果为:
5 5
另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。
每个JVM的线程都有自己的私有的栈空间,随线程创建而创建,java的stack存放的是frames ,java的stack和c的不同,只是存放本地变量,返回值和调用方法,不允许直接push和pop frames ,因为frames 可能是有heap分配的,所以j为ava的stack分配的内存不需要是连续的。java的heap是所有线程共享的,堆存放所有 runtime data ,里面是所有的对象实例和数组,heap是JVM启动时创建。
二. 队列(Queue):
什么是队列?
队列是一种常用的数据结构。队列Queue接口与List、Set同一级别,都是实现了Collection接口。在处理元素前用于保存元素的 collection。
这里看下定义:
队列是一种特殊的线性表,是一种先进先出(FIFO)的数据结构。它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。
结合生活很好理解,顾名思义,就像排队一样,正常情况下,先排的人先走,后排的人后走。而且根据FIFO规则,所有新元素都添加在末尾,对列表的头进行删除操作。
此外,我们熟悉的LinkedList,继承AbstractSequentialList<E>,实现List<E>, Deque<E>, Cloneable, java.io.Serializable等的接口
阻塞队列:BlockingQueue
阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。
在并发编程中,有时候需要使用线程安全的队列。如果要实现一个线程安全的队列有两种方式:一种是使用阻塞算法,另一种是使用非阻塞算法。
五个阻塞队列类:
ArrayBlockingQueue:一个由数组支持的有界队列。
LinkedBlockingQueue:一个由链接节点支持的可选有界队列。
PriorityBlockingQueue:一个由优先级堆支持的无界优先级队列。
DelayQueue:一个由优先级堆支持的、基于时间的调度队列。
SynchronousQueue:一个利用 BlockingQueue 接口的简单聚集(rendezvous)机制。
其方法有如下:
add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
put 添加一个元素 如果队列满,则阻塞
take 移除并返回队列头部的元素 如果队列为空,则阻塞
阻塞队列提供了可阻塞的put和take方法,它们与可定时的offer和poll是等价的。如果Queue已经满了,put方法会被阻塞直到有可用的空间;如果Queue是空的,那么take方法会被阻塞,直到有元素可用。Queue的长度可以有限,也可以无限;无限的Queue永远不会充满,所以它的put方法永远不会阻塞。
注意:poll和peek方法出错进返回null。因此,向队列中插入null值是不合法的
原文链接: https://www.yukx.com/jing/article/details/1953.html 优科学习网JVM队列和栈是什么?有什么区别?
-
在HTML中,如果你想让一个输入框(input元素)不可编辑,你可以通过设置其readonly属性来实现。示例如下:input type="text" value="此处内容不可编辑" readonly在上述代码中,readonly属性使得用户无法修改输入框中的内容。另外,如果你希望输入框完全不可交
-
ASP.NET教程ASP.NET又称为ASP+,基于.NETFramework的Web开发平台,是微软公司推出的新一代脚本语言。ASP.NET是一个使用HTML、CSS、JavaScript和服务器脚本创建网页和网站的开发框架。ASP.NET支持三种不一样的开发模式:WebPages(Web页面)、
-
C# 判断判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。下面是大多数编程语言中典型的判断结构的通常形式:判断语句C#提供了以下类型的判断语句。点击链接查看每个语句的细节。语句描述if语句一个 if语句 由一个布尔表达式后跟
-
C#循环有的时候,可能需要多次执行同一块代码。通常情况下,语句是顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推。编程语言提供了允许更为复杂的执行路径的多种控制结构。循环语句允许我们多次执行一个语句或语句组,下面是大多数编程语言中循环语句的通常形式:循环类型C#提供了以下几种循环类型
-
C#数组(Array)数组是一个存储相同类型元素的固定大小的顺序集合。数组是用来存储数据的集合,一般认为数组是一个同一类型变量的集合。声明数组变量并不是声明number0、number1、...、number99一个个单独的变量,而是声明一个就像numbers这样的变量,然后使用numbers[0]
-
ASP.NET是一个由微软公司开发的用于构建Web应用程序的框架,它是.NETFramework的一部分。它提供了一种模型-视图-控制器(MVC)架构、Web表单以及最新的ASP.NETCore中的RazorPages等多种开发模式,可以用来创建动态网页和Web服务。以下是一些基础的ASP.NET编