List之ArrayList、LinkedList深入分析

集合

Java 集合, 也叫作容器,主要是由两大接口派生而来:一个是 Collection接口,主要用于存放单一元素;另一个是 Map 接口,主要用于存放键值对。对于Collection 接口,下面又有三个主要的子接口:ListSetQueue

Java 集合框架如下图所示:

Java 集合框架概览

Collection接口

概念:对象的容器,定义了对多个对象进项操作的的常用方法。可实现数组的功能。
与数组的区别:数组长度固定,集合长度不固定;数组可以存储基本类型和引用类型,集合只能存储引用类型
位置: java.util.*

接口中的方法

boolean add(Object obj) //添加一个对象。
boolean addAll(Collection c) //讲一个集合中的所有对象添加到此集合中。
void clear() //清空此集合中的所有对象。
boolean contains(Object o) //检查此集合中是否包含o对象。
boolean equals(Object o) //比较此集合是否与指定对象相等。
boolean isEmpty() //判断此集合是否为空。
boolean remove(Object o) //在此集合中移除o对象。
int size() //返回此集合中的元素个数。
Object[] toArray() //将此集合转换成数组。
/*** Collection接口的使用(一)* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断*/
public class Demo1{pubic static void main(String[] args){//创建集合Collection collection = new ArrayList();        
//      * 1.添加元素Collection.add("苹果");Collection.add("西瓜");Collection.add("榴莲");System.out.println("元素个数:"+collection.size());System.out.println(collection);
//      * 2.删除元素collection.remove("榴莲");System.out.println("删除之后:"+collection.size());
//      * 3.遍历元素//3.1 使用增强for for(Object object : collection){System.out.println(object);}//3.2 使用迭代器(迭代器专门用来遍历集合的一种方式)//hasnext();判断是否有下一个元素//next();获取下一个元素//remove();删除当前元素Iterator iterator=collection.Itertor();while(iterator.hasnext()){String object=(String)iterator.next();System.out.println(s);//删除操作//collection.remove(s);引发错误:并发修改异常//iterator.remove();应使用迭代器的方法
//      * 4.判断System.out.println(collection.contains("西瓜"));//trueSystem.out.println(collection.isEmpty());//false}}
}

Collection子接口

List集合

特点:有序、有下标、元素可以重复

/*** List子接口的使用(一)* 特点:1.有序有下标 2.可以重复* * 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.获取位置*/
public class Demo3 {public static void main(String[] args) {List list=new ArrayList<>();//1.添加元素list.add("tang");list.add("he");list.add(0,"yu");//插入操作System.out.println("元素个数:"+list.size());System.out.println(list.toString());//2.删除元素list.remove(0);//list.remove("yu");结果同上System.out.println("删除之后:"+list.size());System.out.println(list.toString());//3.遍历元素//3.1 使用for遍历for(int i=0;i<list.size();++i) {System.out.println(list.get(i));}//3.2 使用增强forfor(Object object:list) {System.out.println(object);}//3.3 使用迭代器Iterator iterator=list.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}//3.4使用列表迭代器,listIterator可以双向遍历,添加、删除及修改元素。ListIterator listIterator=list.listIterator();//从前往后while (listIterator.hasNext()) {System.out.println(listIterator.next());		}//从后往前(此时“遍历指针”已经指向末尾)while(listIterator.hasPrevious()) {System.out.println(listIterator.previous());}//4.判断System.out.println(list.isEmpty());System.out.println(list.contains("tang"));//5.获取位置System.out.println(list.indexOf("tang"));}
}
/*** List子接口的使用(二)* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.获取位置*/
public class Demo4 {public static void main(String[] args) {List list=new ArrayList();//1.添加数字数据(自动装箱)list.add(20);list.add(30);list.add(40);list.add(50);System.out.println("元素个数:"+list.size());System.out.println(list.toString());//2.删除元素list.remove(0);//list.remove(20);很明显数组越界错误,改成如下//list.remove(Object(20));//list.remove(new Integer(20));System.out.println("元素个数:"+list.size());System.out.println(list.toString());//3-5不再演示,与之前类似//6.补充方法subList,返回子集合,含头不含尾List list2=list.subList(1, 3);//[1,3)System.out.println(list2.toString());	}
}
ArrayList【重点】

ArrayList是List接口的实现类,也是开发当中最常用的集合类

  • 数组结构实现,查询快、增删慢;
  • JDK1.2版本,运行效率快、线程不安全。
/*** ArrayList的使用* 存储结构:数组;* 特点:查找遍历速度快,增删慢。* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.查找*/
public class Demo5 {public static void main(String[] args) {ArrayList arrayList=new ArrayList<>();//1.添加元素Student s1=new Student("唐", 21);Student s2=new Student("何", 22);Student s3=new Student("余", 21);arrayList.add(s1);arrayList.add(s2);arrayList.add(s3);System.out.println("元素个数:"+arrayList.size());System.out.println(arrayList.toString());//2.删除元素arrayList.remove(s1);//arrayList.remove(new Student("唐", 21));//注:这样可以删除吗(不可以)?显然这是两个不同的对象。//假如两个对象属性相同便认为其是同一对象,那么如何修改代码?//romove的底层是调用对象的equals方法//所以想对象属性相同就修改,就必须修改对象的equals方法//        若一定要写包含任何类型的集合,可以这样写,Object就是包含任何类
//        ArrayList<Object> list1=new ArrayList<>();//        1.获取某个索引位置处的元素值get(index)String e=list.get(4);System.out.println(e);//        2.获取集合的大小size()System.out.println(list.size());//        3.完成遍历for(int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}//        4.删除某个索引位置的元素值,并返回被删除的元素值remove(index)System.out.println(list);String e2=list.remove(1);System.out.println("e2=" + e2);System.out.println(list);//        5.直接删除元素值,remove(value) 删除成功返回true,删除失败返回false,如果存在多个相同的元素,只会删除第一次出现的目标元素System.out.println(list.remove("hwq"));System.out.println(list);//        6.修改某个索引位置处的元素值,并会返回被修改的元素 set(index,element(要修改的值))String name=list.set(0,"牛");System.out.println(name);System.out.println(list);//        7.contains:查找元素是否存在System.out.println(list.contains("牛"));//        8.clear 清空集合list.clear();//        9.isEmpty 判断是否为空System.out.println(list.isEmpty());//        10.addAll:添加多个元素ArrayList list1 = new ArrayList();list1.add("红雷梦");list1.add("三国");list.addAll(list1);System.out.println(list);//        11.containsAll 查找多个元素System.out.println(list.containsAll(list1));//        12.removeAll:删除多个元素list.removeAll(list1);System.out.println(list);}
}
ArrayList源码分析【重点】

ArrayList 是Java集合框架中常用的动态数组实现,它提供了动态增长的能力,允许在数组尾部进行快速的随机访问。下面我们将对 ArrayList 的源码进行分析,深入了解其实现原理和关键方法。

1. 类声明和继承关系
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {// ...
}
  • ArrayList 类继承自 AbstractList,实现了 List 接口,同时还实现了 RandomAccess(随机访问标记接口)、Cloneable(可克隆接口)、Serializable(可序列化接口)。
2. 成员变量
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private static final int DEFAULT_CAPACITY = 10;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  • elementData:存储元素的数组。
  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA:空数组,用于延迟数组的初始化。
  • DEFAULT_CAPACITY:默认初始容量。
  • MAX_ARRAY_SIZE:数组的最大容量。
3. 构造方法
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: " +initialCapacity);}
}public ArrayList(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {this.elementData = EMPTY_ELEMENTDATA;}
}
  • ArrayList 提供了多个构造方法,包括默认构造方法、指定初始容量的构造方法以及接收 Collection 的构造方法。
  • 在默认构造方法中,使用了延迟加载的技术,初始时 elementDataDEFAULTCAPACITY_EMPTY_ELEMENTDATA也就是空数组这点非常重要‼️,只有在第一次add添加元素时才会初始化为默认容量(10)的数组。
4. 核心方法
4.1 add 方法
public boolean add(E e) {ensureCapacityInternal(size + 1);elementData[size++] = e;return true;
}private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;
}private void ensureExplicitCapacity(int minCapacity) {modCount++;if (minCapacity - elementData.length > 0)grow(minCapacity);
}private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}
  • add 方法:添加元素,确保容量足够,如果需要,进行数组扩容。
  • ensureCapacityInternal 方法:确保容量足够的内部方法,负责调用 ensureExplicitCapacity 进行实际的扩容操作。
  • calculateCapacity 方法:计算容量的方法,处理空数组的情况。
  • grow 方法:数组扩容的核心方法,通过 Arrays.copyOf 进行扩容,新容量为原容量的1.5倍。
理解过程
//这是一个空的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

这段源码说明当你没有向集合中添加任何元素时,集合容量为0。那么默认的10个容量怎么来的呢?

这就得看看add方法的源码了:

public boolean add(E e) {ensureCapacityInternal(size + 1);  // Increments modCount!!elementData[size++] = e;return true;
}

假设你new了一个数组,当前容量为0,size当然也为0。这时调用add方法进入到ensureCapacityInternal(size + 1);该方法源码如下:

private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

该方法中的参数minCapacity传入的值为size+1也就是 1,接着我们再进入到calculateCapacity(elementData, minCapacity)里面:

private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;
}

上文说过,elementData就是存放元素的数组,当前容量为0,if条件成立,返回默认容量DEFAULT_CAPACITY也就是10。这个值作为参数又传入ensureExplicitCapacity()方法中,进入该方法查看源码:

private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0) // 当需要的空间大于现在数组的容量就要考虑扩容grow(minCapacity); //数组扩容
}

我们先不要管modCount这个变量。

因为elementData数组长度为0,所以if条件成立,调用grow方法,重要的部分来了,我们再次进入到grow方法的源码中:

private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length; // 现在数组的容量0int newCapacity = oldCapacity + (oldCapacity >> 1); // 新数组的容量0if (newCapacity - minCapacity < 0) // 成立newCapacity = minCapacity;//newCapacity = 10if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}

这个方法先声明了一个oldCapacity变量将数组长度赋给它,其值为0;又声明了一个newCapacity变量其值为oldCapacity+一个增量,可以发现这个增量是和原数组长度有关的量,当然在这里也为0。第一个if条件满足,newCapacity的值为10(这就是默认的容量,不理解的话再看看前面)。第二个if条件不成立,也可以不用注意,因为MAX_ARRAY_SIZE的定义如下:

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

这个值太大了以至于第二个if条件没有了解的必要。

最后一句话就是为elementData数组赋予了新的长度,Arrays.copyOf()方法返回的数组是新的数组对象,原数组对象不会改变,该拷贝不会影响原来的数组。copyOf()的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值。

这时候再回到add的方法中,接着就向下执行elementData[size++] = e;到这里为止关于ArrayList就讲解得差不多了,当数组长度为10的时候你们可以试着过一下源码,查一下每次的增量是多少(答案是每次扩容为原来的1.5倍

总结

  1. 存储元素的结构是Object[]数字,具体的Object由new ArrayList();的T决定

  2. 没有给定初始容量,默认初始容量为10,当添加元素后才初始化为10

  3. 达到额定容量,每次扩容为原来的1.5倍,比如初始容量为10,当添加第11个元素的时候,发现容量不足了,就会调用grow方法进行扩容,扩容后容量为(10 + 10 / 2) = 15 ,如果初始容量为33,则扩容后的容量为(33 + 33 / 2) = 49,会舍弃小数部分,因为底层使用了位运算 >> 1

Vector

Vector在实际开发中使用较少,为了保证线程安全,很多方法使用了synchronized而牺牲了性能,大部分源码和ArrayList相同,这里就不深入介绍了

在这里插入图片描述

  • 数组结构实现,查询快、增删慢;
  • JDK1.0版本,运行效率慢、线程安全。
/*** Vector的演示使用* *1.添加数据*2.删除数据*3.遍历*4.判断*/
public class Demo1 {public static void main(String[] args) {Vector vector=new Vector<>();//1.添加数据vector.add("tang");vector.add("he");vector.add("yu");System.out.println("元素个数:"+vector.size());//2.删除数据/** vector.remove(0); vector.remove("tang");*///3.遍历//使用枚举器Enumeration enumeration=vector.elements();while (enumeration.hasMoreElements()) {String s = (String) enumeration.nextElement();System.out.println(s);}//4.判断System.out.println(vector.isEmpty());System.out.println(vector.contains("he"));//5. Vector其他方法//firstElement()  lastElement()  ElementAt();}
}
LinkedList
  • 特点:链表结构实现,增删快,查询慢
/*** LinkedList的用法* 存储结构:双向链表* 1.添加元素* 2.删除元素* 3.遍历* 4.判断*/
public class Demo2 {public static void main(String[] args) {LinkedList linkedList=new LinkedList<>();Student s1=new Student("唐", 21);Student s2=new Student("何", 22);Student s3=new Student("余", 21);//1.添加元素linkedList.add(s1);linkedList.add(s2);linkedList.add(s3);linkedList.add(s3);System.out.println("元素个数:"+linkedList.size());System.out.println(linkedList.toString());//2.删除元素/** linkedList.remove(new Student("唐", 21));* System.out.println(linkedList.toString());*///3.遍历//3.1 使用forfor(int i=0;i<linkedList.size();++i) {System.out.println(linkedList.get(i));}//3.2 使用增强forfor(Object object:linkedList) {Student student=(Student) object;System.out.println(student.toString());}//3.3 使用迭代器Iterator iterator =linkedList.iterator();while (iterator.hasNext()) {Student student = (Student) iterator.next();System.out.println(student.toString());}//3.4 使用列表迭代器(略)//4. 判断System.out.println(linkedList.contains(s1));System.out.println(linkedList.isEmpty());System.out.println(linkedList.indexOf(s3));}
}
LinkedList源码分析

LinkedList首先有三个属性:

  • 链表大小:transient int size = 0;
  • (指向)第一个结点/头结点:transient Node<E> first;
  • (指向)最后一个结点/尾结点:transient Node<E> last;

关于Node类型我们再进入到类里看看:

private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}

首先item存放的是实际数据;next指向下一个结点而prev指向上一个结点。

Node带参构造方法的三个参数分别是前一个结点、存储的数据、后一个结点,调用这个构造方法时将它们赋值给当前对象。

LinkedList是如何添加元素的呢?先看看add方法:

public boolean add(E e) {linkLast(e);return true;
}

进入到linkLast方法:

void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++;
}

假设刚开始new了一个LinkedList对象,first和last属性都为空,调用add进入到linkLast方法。

首先创建一个Node变量 l 将last(此时为空)赋给它,然后new一个newNode变量存储数据,并且它的前驱指向l,后继指向null;再把last指向newNode。如下图所示:

img

如果满足if条件,说明这是添加的第一个结点,将first指向newNode:

img

至此,LinkedList对象的第一个数据添加完毕。假设需要再添加一个数据,我们可以再来走一遍,过程同上不再赘述,图示如下:

img

ArrayList和LinkedList区别
  • ArrayList:必须开辟连续空间,查询快,增删慢。
  • LinkedList:无需开辟连续空间,查询慢,增删快。

img

总结

在不能提前确定容器大小的情况下可以使用List接口实现的集合类,ArrayList适合频繁查询、修改的场景,不适合频繁增删的场景;而LinkedList则相反

如果觉得本篇文章对你有帮助,可否点个小赞😺;篇幅较长建议收藏🫠;关注一手等待后续更新更多干货🚀

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/270958.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python刷题】环形链表

问题描述 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&a…

论文阅读:SDXL Improving Latent Diffusion Models for High-Resolution Image Synthesis

SDXL Improving Latent Diffusion Models for High-Resolution Image Synthesis 论文链接 代码链接 介绍 背景&#xff1a;Stable Diffusion在合成高分辨率图片方面表现出色&#xff0c;但是仍然需要提高本文提出了SD XL&#xff0c;使用了更大的UNet网络&#xff0c;以及增…

MyBatis的#{}和${}:安全与灵活并存的SQL之道

MyBatis的#{}和${}&#xff1a;安全与灵活并存的SQL之道 MyBatis是一款广泛使用的Java持久化框架&#xff0c;提供了强大的SQL映射和数据库操作功能。在编写MyBatis的SQL语句时&#xff0c;我们经常会遇到#{}和${}两种不同的占位符语法。本文将详细解析#{}和${}的区别以及它们在…

今天面了一个来字节要求月薪23K,明显感觉他背了很多面试题...

最近有朋友去字节面试&#xff0c;面试前后进行了20天左右&#xff0c;包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说&#xff0c;80%的人都会栽在第一轮面试&#xff0c;要不是他面试前做足准备&#xff0c;估计都坚持不完后面几轮面试。 其实&…

迭代器失效问题(C++)

迭代器失效就是迭代器指向的位置已经不是原来的含义了&#xff0c;或者是指向的位置是非法的。以下是失效的几种情况&#xff1a; 删除元素&#xff1a; 此处发生了迭代器的失效&#xff0c;因为erase返回的是下一个元素的位置的迭代器&#xff0c;所以在删除1这个元素的时候&…

JavaEE之volatile关键字

一.内存可见性问题 什么是内存可见性问题 计算机运行的程序/代码&#xff0c;往往需要访问数据。这些数据往往存在于内存中。 cup使用此变量时&#xff0c;就会把内存中的数据先读出来&#xff0c;加载到cpu寄存器中&#xff0c;再去参与运算。 但是&#xff0c;关键是cpu读…

MySQL 教程 2.4

MySQL UNION 操作符 本教程为大家介绍 MySQL UNION 操作符的语法和实例。 描述 MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合&#xff0c;并去除重复的行。 UNION 操作符必须由两个或多个 SELECT 语句组成&#xff0c;每个 SELECT 语句的列数…

【kubernetes】关于k8s集群如何将pod调度到指定node节点?

目录 一、k8s的watch机制 二、scheduler的调度策略 Predicate&#xff08;预选策略&#xff09; 常见算法&#xff1a; priorities&#xff08;优选策略&#xff09;常见的算法有&#xff1a; 三、k8s的标签管理之增删改查 四、k8s的将pod调度到指定node的方法 方案一&am…

P1308 [NOIP2011 普及组] 统计单词数

题目描述&#xff1a; 思路&#xff1a; 1、首先判断一下&#xff0c;此字符是不是字母&#xff0c;因为题目给出有可能有空格的存在&#xff0c;如果是字母&#xff0c;全部变成小写字母&#xff0c;这样方便后面比较 2、把文章全部变为字符串&#xff0c;用字符串数组来存&…

Pytorch学习 day05(RandomCrop、Transforms工具使用总结)

RandomCrop 将PIL或Tensor格式的输入图片&#xff0c;随机裁剪指定尺寸的部分输入尺寸可以为序列或单个整形数字代码如下&#xff1a; from PIL import Image from torchvision import transforms from torch.utils.tensorboard import SummaryWriterimg Image.open("i…

《剑指offer》76--删除链表中重复的结点[C++]

目录 题目&#xff1a; 思路&#xff1a; 贴代码&#xff1a; 代码输出 题目&#xff1a; 在一个排序的链表中&#xff0c;存在重复的结点&#xff0c;请删除该链表中重复的结点&#xff0c;重复的结点不保留&#xff0c;最后返回链表头指针。 如&#xff1a; 链表1->…

.Net6使用JWT认证和授权

文章目录 目的实现案例一.项目所需包&#xff1a;二.配置项目 appsettings.json 文件&#xff1a;三.创建Model文件夹&#xff0c;添加AppConfig类和UserRole类1.AppConfig类获取appsettings.json文件中的值2.UserRole类用于区分用户信息和权限 四.主体代码案例&#xff1a;1.L…

kasan排查kernel内存越界示例(linux5.18.11)

参考资料&#xff1a; 1&#xff0c;内核源码目录中的Documentation\dev-tools\kasan.rst 2&#xff0c;KASAN - Kernel Address Sanitizer | Naveen Naidu (naveenaidu.dev) 一、kasan实现原理 KASAN&#xff08;Kernel Address SANitizer&#xff09;是一个动态内存非法访…

C#与python交互(flask发送Get/Post请求)

先运行python&#xff0c;再运行C# **ps: 注意修改端口号**python发送Get/Post请求 # -*- coding: utf-8 -*- # Time : 2024/1/25 15:52 # Author : YY # File : post_test.py # Content&#xff1a;提交数据给客户端 from flask import Flask, request, jsonify, redirect…

使用Kali搭建钓鱼网站教程

一、前言 使用kali工具一分钟制作出和目标网站一模一样的钓鱼网站。目标用户使用钓鱼网站登录自己的账号&#xff0c;账号密码将被自动劫持。 二、钓鱼网站的制作过程 1.在虚拟机VMvare中登录kali linux 2.准备一个目标网址 3.在kail中搜索使用工具 4.在弹出的选项中选择第一…

C++初阶:初识C++

目录 1. 前言&#xff1a;C 与 C语言2. C对于C语言语法的完善与补充2.1 命名冲突与命名空间2.1.1 命名空间的定义2.1.2 调用方式 2.3 补充&#xff1a;流的概念2.4 缺省参数2.4.1 缺省参数的使用 2.5 函数重载2.5.1 什么是函数重载2.5.2 函数重载的使用2.5.3 特殊情况&#xff…

Docker基础教程 - 1 Docker简介

更好的阅读体验&#xff1a;点这里 &#xff08; www.doubibiji.com &#xff09; 1 Docker简介 Docker是一个强大的容器化平台&#xff0c;让你能够更轻松地构建、部署和运行应用程序。 下面我们来学习 Docker。 1.1 Docker是什么 1 现在遇到的问题 每次部署一台服务器&…

OpenAI 大声朗读出来

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

Kubernetes-3

Kubernetes学习第3天 Kubernetes-31、查看实时的cpu和内存消耗1.1、kubectl top node 2、卷的使用2.1、什么是卷&#xff1f;1. 解决数据持久性问题2. Kubernetes 中的卷抽象概念3. 共享数据示例4. Kubernetes 中的卷使用5. 不同类型的卷6. 灵活、可靠的数据管理 2.2、联想到do…

[设计模式Java实现附plantuml源码~行为型]定义算法的框架——模板方法模式

前言&#xff1a; 为什么之前写过Golang 版的设计模式&#xff0c;还在重新写Java 版&#xff1f; 答&#xff1a;因为对于我而言&#xff0c;当然也希望对正在学习的大伙有帮助。Java作为一门纯面向对象的语言&#xff0c;更适合用于学习设计模式。 为什么类图要附上uml 因为很…