Java動(dòng)態(tài)循環(huán)隊(duì)列是如何實(shí)現(xiàn)的
一、隊(duì)列
1.1 定義
隊(duì)列 (Queue) 是一種限定性的有序線性表,它只允許在表的一端插入元素,而在另一端刪除元素,所以隊(duì)列具有先進(jìn)先出 (Fist In Fist Out,縮寫為FIFO)的特性。
- 在隊(duì)列中,允許插入的一端叫做隊(duì)尾(rear);
- 允許刪除的一端則稱為隊(duì)頭(front)。
- 隊(duì)列是一個(gè)有序列表,可以用數(shù)組或是鏈表來(lái)實(shí)現(xiàn)。
- 遵循先進(jìn)先出的原則。即:先存入隊(duì)列的數(shù)據(jù),要先取出。
1.2 抽象數(shù)據(jù)類型
數(shù)據(jù)元素:可以是任意類型的數(shù)據(jù),但必須屬于同一個(gè)數(shù)據(jù)對(duì)象。
關(guān)系:隊(duì)列中數(shù)據(jù)元素之間是線性關(guān)系。
基本操作:
1.初始化操作。使用構(gòu)造方法設(shè)置一個(gè)空隊(duì)列。
2.isEmpty():判空操作。若隊(duì)列為空,則返回TRUE,否則返回FALSE。
3.isFull():判滿操作。若隊(duì)列為滿,則返回TRUE,否則返回FALSE。
4.getSize():獲取隊(duì)列元素個(gè)數(shù)。
5.add(E e):進(jìn)隊(duì)操作。在隊(duì)列Q的隊(duì)尾插入e。如果隊(duì)滿,拋出異常。
6.poll():出隊(duì)操作。使隊(duì)列Q的隊(duì)頭元素出隊(duì),并用e返回其值。如果隊(duì)空,拋出異常。
7.getHead ():取隊(duì)頭元素操作。用e取得隊(duì)頭元素的值。如果隊(duì)列為空,則返回null。
8.clear():隊(duì)列置空操作。將隊(duì)列Q置為空隊(duì)列。
9.destroy():隊(duì)列銷毀操作。釋放隊(duì)列的空間。
1.3 順序存儲(chǔ)
隊(duì)列的一種順序存儲(chǔ)稱為順序隊(duì)列。與順序棧類似,在隊(duì)列的順序存儲(chǔ)結(jié)構(gòu)中,用一組地址連續(xù)的存儲(chǔ)單元依次存放從隊(duì)頭到隊(duì)尾的元素,如一維數(shù)組Queue[maxSize]。
二、數(shù)組隊(duì)列
由于隊(duì)列中隊(duì)頭和隊(duì)尾的位置都是動(dòng)態(tài)變化的,因此需要附設(shè)兩個(gè)指針 front和 rear。
- front:指示隊(duì)頭元素在數(shù)組中的位置;
- rear:指示真實(shí)隊(duì)尾元素相鄰的下一個(gè)位置。
2.1 思路分析
- 初始化隊(duì)列時(shí),令
front = rear = 0。 - 判斷隊(duì)空的條件:
front == rear。 - 判斷隊(duì)滿的條件:
rear == maxSize。 - 入隊(duì)時(shí),若尾指針rear 小于隊(duì)列的最大下標(biāo)
maxSize,則將數(shù)據(jù)存入rear所指的數(shù)組元素中,否則無(wú)法存入數(shù)據(jù);然后將尾指針往后移:rear + 1。 - 出隊(duì)時(shí),若隊(duì)列不為空,取出隊(duì)頭指針front所指的元素;然后將尾指針往后移:
front + 1。
2.2 代碼實(shí)現(xiàn)
定義接口方法:
/**
* description:自定義隊(duì)列接口
*
* @author RenShiWei
* Date: 2021/5/29 20:45
**/
public interface Queue<E> {
/**
* @return 是否隊(duì)空
*/
boolean isEmpty();
/**
* @return 是否隊(duì)滿
*/
boolean isFull();
/**
* @return 隊(duì)列的可承載元素個(gè)數(shù)
*/
int getCapacity();
/**
* @return 隊(duì)列元素個(gè)數(shù)
*/
int getSize();
/**
* 隊(duì)尾入隊(duì)
*
* @param e 入隊(duì)元素
*/
void add(E e);
/**
* 隊(duì)首出隊(duì)
*
* @return 出隊(duì)元素
*/
E poll();
/**
* 獲取隊(duì)首元素
*
* @return 隊(duì)首元素
*/
E getHead();
}
2.3 數(shù)組隊(duì)列實(shí)現(xiàn)
/**
* description:數(shù)組隊(duì)列
*
* @author RenShiWei
* Date: 2021/5/29 20:41
**/
public class ArrayQueue<E> implements Queue<E> {
/** 表示可存儲(chǔ)元素的最大容量 */
private int maxSize;
/** 隊(duì)列頭 */
private int front;
/** 隊(duì)列尾 */
private int rear;
/** 該數(shù)據(jù)用于存放數(shù)據(jù),模擬隊(duì)列 */
private E[] data;
/**
* 初始化隊(duì)列
*
* @param arrMaxSize 初始隊(duì)列最大容量
*/
@SuppressWarnings("unchecked")
public ArrayQueue(int arrMaxSize) {
maxSize = arrMaxSize;
data = (E[]) new Object[maxSize];
front = 0;
rear = 0;
}
/**
* @return 是否隊(duì)空
*/
@Override
public boolean isEmpty() {
return front == rear;
}
/**
* @return 是否隊(duì)滿
*/
@Override
public boolean isFull() {
return rear == maxSize;
}
/**
* @return 隊(duì)列元素個(gè)數(shù)
*/
@Override
public int getSize() {
return rear - front;
}
/**
* 隊(duì)尾入隊(duì)
*
* @param e 入隊(duì)元素
*/
@Override
public void add(E e) {
if (isFull()) {
throw new IllegalArgumentException("隊(duì)列已滿,不能入隊(duì)!");
}
data[rear++] = e;
}
/**
* 隊(duì)首出隊(duì)
*
* @return 出隊(duì)元素
*/
@Override
public E poll() {
if (isEmpty()) {
throw new IllegalArgumentException("隊(duì)列為空,不能出隊(duì)!");
}
//出隊(duì)位置置null
E temp = data[front];
data[front++] = null;
return temp;
}
/**
* 獲取隊(duì)首元素
* 如果隊(duì)空,返回null
*
* @return 隊(duì)首元素
*/
@Override
public E getHead() {
return data[front];
}
/**
* @return 隊(duì)列的可承載元素個(gè)數(shù)
*/
@Override
public int getCapacity() {
return data.length - 1;
}
/**
* @return 隊(duì)列的有效容量(未使用的空間數(shù)量)
*/
public int getEmptyCount() {
return maxSize - rear;
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append("Queue: ");
res.append("front [");
for (int i = front; i < rear; i++) {
res.append(data[i]);
if (i != rear - 1) {
res.append(", ");
}
}
res.append("] rear");
return res.toString();
}
/**
* 隊(duì)列測(cè)試
*/
public static void main(String[] args) {
ArrayQueue<Integer> queue = new ArrayQueue<>(5);
Scanner sc = new Scanner(System.in);
char c;
boolean loop = true;
while (loop) {
System.out.println("s(toString):輸出隊(duì)列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加數(shù)據(jù)到隊(duì)列");
System.out.println("p(poll):從隊(duì)列取出數(shù)據(jù)");
System.out.println("h(getHead):查看隊(duì)列頭的數(shù)據(jù)");
System.out.println("n(isEmpty):是否隊(duì)空");
System.out.println("f(isFull):是否隊(duì)滿");
c = sc.next().charAt(0);
switch (c) {
case 's':
System.out.println("當(dāng)前隊(duì)列:" + queue.toString() + "\t元素個(gè)數(shù):" + queue.getSize() + "\t有效容量:" + queue.getEmptyCount());
break;
case 'e':
sc.close();
loop = false;
break;
case 'a':
System.out.println("請(qǐng)輸入一個(gè)整數(shù)");
queue.add(sc.nextInt());
break;
case 'p':
System.out.printf("出隊(duì)元素:%d\n", queue.poll());
break;
case 'h':
System.out.printf("隊(duì)首元素:%d\n", queue.getHead());
break;
case 'n':
System.out.println("隊(duì)空:" + queue.isEmpty());
break;
case 'f':
System.out.println("隊(duì)滿:" + queue.isFull());
break;
default:
break;
}
}
System.out.println("程序退出");
}
}
2.4 分析
假溢出現(xiàn)象
在非空順序隊(duì)列中,隊(duì)頭指針始終指向當(dāng)前的隊(duì)頭元素,而隊(duì)尾指針始終指向真正隊(duì)尾元素。當(dāng)rear == maxSize - 1 時(shí),認(rèn)為隊(duì)滿。但此時(shí)不一定是真的隊(duì)滿,因?yàn)殡S著部分元素的出隊(duì),數(shù)組前面會(huì)出現(xiàn)一些空單元,如下圖所示。由于只能在隊(duì)尾入隊(duì),使得上述空單元無(wú)法使用。把這種現(xiàn)象稱為假溢出。

問(wèn)題:目前這個(gè)數(shù)組使用一次就不能用(出隊(duì)的空間),沒(méi)有達(dá)到復(fù)用的效果。可使用算法將其改造成環(huán)形隊(duì)列(取模:%)。
三、環(huán)形隊(duì)列
為了解決假溢出現(xiàn)象并使得隊(duì)列空間得到充分利用,一個(gè)較巧妙的辦法是將順序隊(duì)列的數(shù)組看成一個(gè)環(huán)狀的空間,即規(guī)定最后一個(gè)單元的后繼為第一個(gè)單元,我們形象地稱之為循環(huán)隊(duì)列。
3.1 思路分析
- 初始化隊(duì)列時(shí),令
front = rear = 0。front指向隊(duì)列的第一個(gè)元素,rear指向隊(duì)列最后一個(gè)元素的后一個(gè)位置(希望損失一個(gè)位置作為約定,用來(lái)區(qū)分隊(duì)空和隊(duì)滿)。 - 判斷隊(duì)空的條件:
front == rear。 - 判斷隊(duì)滿的條件:
(rear + 1) % maxSize == front。 - 隊(duì)列中的元素個(gè)數(shù):
(rear + maxSize - front) % maxSize。 - 入隊(duì)時(shí),將數(shù)據(jù)存入
rear所指的數(shù)組元素中,指針變化:rear = ( rear+1) % maxSize。 - 出隊(duì)時(shí),將數(shù)據(jù)存入
front所指的數(shù)組元素中,指針變化:front = ( front+1 ) % maxSize。
下圖給出了循環(huán)隊(duì)列的幾種情況:
3.2 代碼實(shí)現(xiàn)
/**
* description:循環(huán)隊(duì)列
*
* @author RenShiWei
* Date: 2021/5/30 16:38
**/
public class LoopQueue<E> implements Queue<E> {
/** 存儲(chǔ)元素 數(shù)組的長(zhǎng)度(有效長(zhǎng)度需要-1) */
private int maxSize;
/** 隊(duì)列頭 */
private int front;
/** 隊(duì)列尾 */
private int rear;
/** 該數(shù)據(jù)用于存放數(shù)據(jù),模擬隊(duì)列 */
private E[] data;
/**
* 初始化環(huán)形隊(duì)列
*
* @param arrMaxSize 初始隊(duì)列容量
*/
@SuppressWarnings("unchecked")
public LoopQueue(int arrMaxSize) {
//循環(huán)隊(duì)列需要有意識(shí)浪費(fèi)一個(gè)空間
maxSize = arrMaxSize + 1;
data = (E[]) new Object[maxSize];
}
/**
* @return 是否隊(duì)空
*/
@Override
public boolean isEmpty() {
return front == rear;
}
/**
* @return 是否隊(duì)滿
*/
@Override
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
/**
* @return 隊(duì)列的可承載元素個(gè)數(shù)
*/
@Override
public int getCapacity() {
return data.length - 1;
}
/**
* @return 隊(duì)列元素個(gè)數(shù)
*/
@Override
public int getSize() {
return (rear + maxSize - front) % maxSize;
}
/**
* 隊(duì)尾入隊(duì)
*
* @param e 入隊(duì)元素
*/
@Override
public void add(E e) {
if (isFull()) {
throw new IllegalArgumentException("隊(duì)列已滿,不能入隊(duì)!");
}
data[rear] = e;
//rear指針后移一位
rear = (rear + 1) % maxSize;
}
/**
* 隊(duì)首出隊(duì)
*
* @return 出隊(duì)元素
*/
@Override
public E poll() {
if (isEmpty()) {
throw new IllegalArgumentException("隊(duì)列為空,不能出隊(duì)!");
}
E temp = data[front];
//出隊(duì)位置置null
data[front] = null;
//front指針后移一位
front = (front + 1) % maxSize;
return temp;
}
/**
* 獲取隊(duì)首元素
* 如果隊(duì)空,返回null
*
* @return 隊(duì)首元素
*/
@Override
public E getHead() {
return data[front];
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(String.format("Queue: size = %d , capacity = %d\n", getSize(), getCapacity()));
res.append("front [");
for (int i = front; i != rear; i = (i + 1) % data.length) {
res.append(data[i]);
if ((i + 1) % data.length != rear) {
res.append(", ");
}
}
res.append("] tail");
return res.toString();
}
/**
* 隊(duì)列測(cè)試
*/
public static void main(String[] args) {
LoopQueue<Integer> queue = new LoopQueue<>(5);
Scanner sc = new Scanner(System.in);
char c;
boolean loop = true;
while (loop) {
System.out.println("s(toString):輸出隊(duì)列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加數(shù)據(jù)到隊(duì)列");
System.out.println("p(poll):從隊(duì)列取出數(shù)據(jù)");
System.out.println("h(getHead):查看隊(duì)列頭的數(shù)據(jù)");
System.out.println("n(isEmpty):是否隊(duì)空");
System.out.println("f(isFull):是否隊(duì)滿");
c = sc.next().charAt(0);
switch (c) {
case 's':
System.out.println("當(dāng)前隊(duì)列:" + queue.toString());
break;
case 'e':
sc.close();
loop = false;
break;
case 'a':
System.out.println("請(qǐng)輸入一個(gè)整數(shù)");
queue.add(sc.nextInt());
break;
case 'p':
System.out.printf("出隊(duì)元素:%d\n", queue.poll());
break;
case 'h':
System.out.printf("隊(duì)首元素:%d\n", queue.getHead());
break;
case 'n':
System.out.println("隊(duì)空:" + queue.isEmpty());
break;
case 'f':
System.out.println("隊(duì)滿:" + queue.isFull());
break;
default:
break;
}
}
System.out.println("程序退出");
}
}
3.3 分析
相比數(shù)組隊(duì)列來(lái)說(shuō),循環(huán)隊(duì)列解決了數(shù)組空間不能再次利用的問(wèn)題。但依然存在一些問(wèn)題:
- 當(dāng)隊(duì)列真的滿的時(shí)候就不能再進(jìn)行入隊(duì)操作了。但是從我們常用的
ArrayList來(lái)分析,在存儲(chǔ)空間允許的條件下是可以一直添加元素的。 - 當(dāng)數(shù)組元素頻繁進(jìn)行入隊(duì)或者出隊(duì)操作時(shí),可能造成空間的浪費(fèi)。循環(huán)隊(duì)列其實(shí)只利用了有限的存儲(chǔ)空間,但是在最初實(shí)例化循環(huán)隊(duì)列的時(shí)候,如果空間聲明的很大,那么會(huì)造成一定程度上的空間浪費(fèi)。
- 假設(shè),聲明一個(gè)容量為20的循環(huán)隊(duì)列,但每次入隊(duì)2個(gè)元素后,又出隊(duì)2個(gè)元素,那么實(shí)際只利用了很有限的空間,造成了空間浪費(fèi),但又不能聲明的空間太小,并不能保證未來(lái)每次只入隊(duì)或者出隊(duì)2個(gè)元素。
因此,是否可以實(shí)現(xiàn)動(dòng)態(tài)的將循環(huán)隊(duì)列進(jìn)行擴(kuò)容或者縮容,上述兩個(gè)問(wèn)題,可以利用下面的動(dòng)態(tài)循環(huán)隊(duì)列來(lái)實(shí)現(xiàn)。
當(dāng)然,上述的數(shù)組隊(duì)列,也可以改造成動(dòng)態(tài)的,但是出隊(duì)元素的空間依然會(huì)浪費(fèi),所以沒(méi)必要進(jìn)行實(shí)現(xiàn)。
四、動(dòng)態(tài)循環(huán)隊(duì)列
為了解決循環(huán)隊(duì)列,隊(duì)滿不能入隊(duì),以及頻繁入隊(duì)出隊(duì)引起的空間浪費(fèi),而引出動(dòng)態(tài)循環(huán)隊(duì)列的概念。即在隊(duì)滿時(shí)進(jìn)行擴(kuò)容,在隊(duì)列元素個(gè)數(shù)下降到一定情況下進(jìn)行縮容。
4.1 思路分析
- 除了入隊(duì)和出隊(duì)操作,其他操作均與循環(huán)隊(duì)列相同。
- 循環(huán)隊(duì)列存儲(chǔ)元素的數(shù)組容量變更思路:使用擴(kuò)容一倍/縮容一倍的新數(shù)組接收原來(lái)循環(huán)隊(duì)列存儲(chǔ)的元素。接收后,將
front指針置為0;將rear指針值到最后一個(gè)元素的位置(即存儲(chǔ)有效元素的數(shù)量)。 - 什么時(shí)候擴(kuò)容:隊(duì)滿
- 什么時(shí)候縮容:隊(duì)列元素只有1/4,并且縮容后容量不為0。
- 數(shù)組容量為0時(shí),縮容會(huì)出現(xiàn)異常
- 為什么不在隊(duì)列元素只有1/2時(shí)縮容?當(dāng)數(shù)組元素為一半的時(shí)候一次添加,一次刪除,造成的一直擴(kuò)容和減小的操作。
4.2 代碼實(shí)現(xiàn)
/**
* description:動(dòng)態(tài)循環(huán)
*
* @author RenShiWei
* Date: 2021/5/30 17:06
**/
public class DynamicLoopQueue<E> implements Queue<E> {
/** 存儲(chǔ)元素 數(shù)組的長(zhǎng)度(有效長(zhǎng)度需要-1) */
private int maxSize;
/** 隊(duì)列頭 */
private int front;
/** 隊(duì)列尾 */
private int rear;
/** 該數(shù)據(jù)用于存放數(shù)據(jù),模擬隊(duì)列 */
private E[] data;
/**
* 初始化環(huán)形隊(duì)列
*
* @param arrMaxSize 初始隊(duì)列容量
*/
@SuppressWarnings("unchecked")
public DynamicLoopQueue(int arrMaxSize) {
//循環(huán)隊(duì)列需要有意識(shí)浪費(fèi)一個(gè)空間
maxSize = arrMaxSize + 1;
data = (E[]) new Object[maxSize];
}
/**
* @return 是否隊(duì)空
*/
@Override
public boolean isEmpty() {
return front == rear;
}
/**
* @return 是否隊(duì)滿
*/
@Override
public boolean isFull() {
return (rear + 1) % maxSize == front;
}
/**
* @return 隊(duì)列的可承載元素個(gè)數(shù)
*/
@Override
public int getCapacity() {
return data.length - 1;
}
/**
* @return 隊(duì)列元素個(gè)數(shù)
*/
@Override
public int getSize() {
return (rear + maxSize - front) % maxSize;
}
/**
* 隊(duì)尾入隊(duì)
*
* @param e 入隊(duì)元素
*/
@Override
public void add(E e) {
if (isFull()) {
//隊(duì)滿不再進(jìn)行報(bào)錯(cuò),而是進(jìn)行動(dòng)態(tài)擴(kuò)容
resize(getCapacity() * 2);
}
data[rear] = e;
//rear指針后移一位
rear = (rear + 1) % maxSize;
}
/**
* 隊(duì)首出隊(duì)
*
* @return 出隊(duì)元素
*/
@Override
public E poll() {
if (isEmpty()) {
throw new IllegalArgumentException("隊(duì)列為空,不能出隊(duì)!");
}
E temp = data[front];
//出隊(duì)位置置null
data[front] = null;
//front指針后移一位
front = (front + 1) % maxSize;
//當(dāng)數(shù)組實(shí)際元素減小到空間的一半的時(shí)候,對(duì)其進(jìn)行縮小
//if(size == data.length / 2)
/*
解決當(dāng)一半的時(shí)候一次添加,一次刪除,造成的一直擴(kuò)容和減小的操作,
增加必須要擴(kuò)容,所以可以讓縮容變得更懶時(shí)在進(jìn)行,即1/4時(shí)
data.length / 2 != 0防止數(shù)組大小最后變成0,造成異常
*/
if (getSize() == getCapacity() / 4 && getCapacity() / 2 != 0) {
resize(getCapacity() / 2);
}
return temp;
}
/**
* 獲取隊(duì)首元素
* 如果隊(duì)空,返回null
*
* @return 隊(duì)首元素
*/
@Override
public E getHead() {
return data[front];
}
/**
* 擴(kuò)容方法
*
* @param newCapacity 擴(kuò)容后的隊(duì)列大小
*/
@SuppressWarnings("unchecked")
private void resize(int newCapacity) {
E[] newData = (E[]) new Object[newCapacity + 1];
//有多個(gè)元素循環(huán)多少次
for (int i = 0; i < getSize(); i++) {
//循環(huán)隊(duì)列會(huì)發(fā)生偏移,重新賦值給新數(shù)組
newData[i] = data[(i + front) % data.length];
}
data = newData;
maxSize = data.length;
//重置指針
front = 0;
rear = getSize();
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
res.append(String.format("Queue: size = %d , capacity = %d\n", getSize(), getCapacity()));
res.append("front [");
for (int i = front; i != rear; i = (i + 1) % data.length) {
res.append(data[i]);
if ((i + 1) % data.length != rear) {
res.append(", ");
}
}
res.append("] tail");
return res.toString();
}
/**
* 隊(duì)列測(cè)試
*/
public static void main(String[] args) {
DynamicLoopQueue<Integer> queue = new DynamicLoopQueue<>(3);
Scanner sc = new Scanner(System.in);
char c;
boolean loop = true;
while (loop) {
System.out.println("s(toString):輸出隊(duì)列");
System.out.println("e(exit):退出程序");
System.out.println("a(add):添加數(shù)據(jù)到隊(duì)列");
System.out.println("p(poll):從隊(duì)列取出數(shù)據(jù)");
System.out.println("h(getHead):查看隊(duì)列頭的數(shù)據(jù)");
System.out.println("n(isEmpty):是否隊(duì)空");
System.out.println("f(isFull):是否隊(duì)滿");
c = sc.next().charAt(0);
switch (c) {
case 's':
System.out.println("當(dāng)前隊(duì)列:" + queue.toString());
break;
case 'e':
sc.close();
loop = false;
break;
case 'a':
System.out.println("請(qǐng)輸入一個(gè)整數(shù)");
queue.add(sc.nextInt());
break;
case 'p':
System.out.printf("出隊(duì)元素:%d\n", queue.poll());
break;
case 'h':
System.out.printf("隊(duì)首元素:%d\n", queue.getHead());
break;
case 'n':
System.out.println("隊(duì)空:" + queue.isEmpty());
break;
case 'f':
System.out.println("隊(duì)滿:" + queue.isFull());
break;
default:
break;
}
}
System.out.println("程序退出");
}
}
到此這篇關(guān)于Java動(dòng)態(tài)循環(huán)隊(duì)列是如何實(shí)現(xiàn)的的文章就介紹到這了,更多相關(guān)Java動(dòng)態(tài)循環(huán)隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot實(shí)現(xiàn)文件在線預(yù)覽功能的全過(guò)程
我們開(kāi)發(fā)業(yè)務(wù)系統(tǒng)的時(shí)候,經(jīng)常有那種文檔文件在線預(yù)覽的需求,下面這篇文章主要給大家介紹了關(guān)于SpringBoot實(shí)現(xiàn)文件在線預(yù)覽功能的相關(guān)資料,需要的朋友可以參考下2021-11-11
零基礎(chǔ)寫Java知乎爬蟲(chóng)之獲取知乎編輯推薦內(nèi)容
上篇文章我們拿百度首頁(yè)做了個(gè)小測(cè)試,今天我們來(lái)個(gè)復(fù)雜的,直接抓取知乎編輯推薦的內(nèi)容,小伙伴們可算松了口氣,終于進(jìn)入正題了,哈哈。2014-11-11
使用Java模擬鼠標(biāo)和鍵盤的詳細(xì)操作步驟
這篇文章主要介紹了使用Java模擬鼠標(biāo)和鍵盤的詳細(xì)操作步驟,要運(yùn)行上面提供的Java程序,您需要遵循幾個(gè)步驟來(lái)設(shè)置Java環(huán)境、編寫程序代碼,并執(zhí)行該程序,文中有相關(guān)的代碼示例,需要的朋友可以參考下2024-05-05
詳解SpringBoot啟動(dòng)項(xiàng)目后執(zhí)行方法的幾種方式
在項(xiàng)目開(kāi)發(fā)中某些場(chǎng)景必須要用到啟動(dòng)項(xiàng)目后立即執(zhí)行方式的功能,本文主要聊聊實(shí)現(xiàn)立即執(zhí)行的幾種方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09

