ArrayList源码分析(基于JDK11)

2023-10-29

ArrayList源码分析(基于JDK11)

类字段

	private static final long serialVersionUID = 8683452581122892189L;
    private static final int DEFAULT_CAPACITY = 10;  //初始容量
    private static final Object[] EMPTY_ELEMENTDATA = new Object[0];  //空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
    transient Object[] elementData;  //存储数组,根据需要进行初始化
    private int size;  //存储元素的数量
    private static final int MAX_ARRAY_SIZE = 2147483639;  //最大容量,此时接近于2的32次方,可再次扩容到2的32次方减一

ArrayList的类字段中定义了序列化ID、初始容量、最大容量、元素存储数组、元素数量等信息。从类字段中可以分析出,ArrayList的底层使用的是Object数组来存储元素,至于他的数组长度的可变性则是在该类中自己实现的逻辑。初始容量为10,最大容量为接近于2的32次方,当超过这个后,最大容量扩大到2的32次方。

构造函数

1、无参构造函数

	public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

无参构造函数只是将存储元素的数组初始化为默认的空元素数组,此时的数组的容量为零。此时的数组容量并不是默认的数组容量10,而是在第一个元素add时才扩容为10的。
2、有参构造函数

  • 自定义初始容量
	public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else {
            if (initialCapacity != 0) {
                throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
            }

            this.elementData = EMPTY_ELEMENTDATA;
        }

    }

拥有一个参数,就是初始化容量,为int值。当该值大于零时,数组初始化为该容量大小的数组,当该值小于零是,抛出非法参数异常,当该值为零时,初始化为空数组。

  • 使用集合进行初始化
	public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((this.size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                this.elementData = a;
            } else {
                this.elementData = Arrays.copyOf(a, this.size, Object[].class);
            }
        } else {
            this.elementData = EMPTY_ELEMENTDATA;
        }

    }

构造一个指定集合的列表,Collection作为参数传入。首先将该Collection存储的元素转化为Object数组,如果该数组的长度为零,则将ArrayList初始化为空数组。如果该数组长度不为零,分两种情况,第一种情况是传入的集合就是ArrayList类型的,则直降将elementData数组初始化为转化后的数组。如果不是ArrayList类型的,则将其拷贝为一个新数组用来初始化elementData。
Arrays.copyOf方法是浅拷贝,存储的对象是一样的,只是生成了新的引用,指向的还是原来的对象(打印拷贝前后对象的地址进行对比,发现地址一样)。

常用方法

1、添加元素和扩容

  • 添加元素
	public boolean add(E e) {
        ++this.modCount;  //修改次数加一
        this.add(e, this.elementData, this.size); //调用的是一个重载的方法
        return true;
    }
//上面的add调用的是该方法
	private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length) {  //如果长度已经达到最大,则扩充长度
            elementData = this.grow();
        }
        elementData[s] = e;   //否则直接将元素添加到数组中,并将size加一
        this.size = s + 1;
    }
//将元素添加到指定位置
	public void add(int index, E element) {
        this.rangeCheckForAdd(index);  //index范围检查,超出则抛出异常
        ++this.modCount;  //修改加一
        int s;
        Object[] elementData;
        if ((s = this.size) == (elementData = this.elementData).length) {  //达到数组容量则扩容
            elementData = this.grow();
        }

        System.arraycopy(elementData, index, elementData, index + 1, s - index);  //元素后移
        elementData[index] = element;  //添加元素
        this.size = s + 1;  //size加一
    }
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

JVM的数组拷贝方法,将原数组的srcPos位置开始的length长元素,拷贝到dest数组的destPos开始的位置。

//将指定Collection添加到现有的ArrayList中元素的后面
	public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        ++this.modCount;
        int numNew = a.length;
        if (numNew == 0) {
            return false;
        } else {
            Object[] elementData;
            int s;
            if (numNew > (elementData = this.elementData).length - (s = this.size)) {
                elementData = this.grow(s + numNew);  //容量不够则扩容
            }

            System.arraycopy(a, 0, elementData, s, numNew);  //拷贝到现有元素的后面
            this.size = s + numNew;  //size增加
            return true;
        }
    }
//将指定Collection添加到现有的ArrayList的指定位置的后面,原有的则顺延到添加元素的后面
	public boolean addAll(int index, Collection<? extends E> c) {
        this.rangeCheckForAdd(index);
        Object[] a = c.toArray();
        ++this.modCount;
        int numNew = a.length;
        if (numNew == 0) {
            return false;
        } else {
            Object[] elementData;
            int s;
            if (numNew > (elementData = this.elementData).length - (s = this.size)) {
                elementData = this.grow(s + numNew);  //如果容量存不下,则扩容
            }

            int numMoved = s - index;
            if (numMoved > 0) {  //拷贝原数组空出中间位置
                System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
            }
			//拷贝Collection到ArrayList中
            System.arraycopy(a, 0, elementData, index, numNew);
            this.size = s + numNew;  //size增加
            return true;
        }
    }
  • 扩容
//通过传入的容量来扩容,扩容通过数组拷贝实现,实际的容量由newCapacity函数决定
	private Object[] grow(int minCapacity) {
        return this.elementData = Arrays.copyOf(this.elementData, this.newCapacity(minCapacity));
    }
//最开始的扩容函数,调用重载函数,并传入当前size加一作为参数
	private Object[] grow() {
        return this.grow(this.size + 1);
    }
//实际的扩容策略
	private int newCapacity(int minCapacity) {
        int oldCapacity = this.elementData.length;  //获取老数组的长度
        int newCapacity = oldCapacity + (oldCapacity >> 1);  //扩容1.5倍
        if (newCapacity - minCapacity <= 0) {  //安全策略,以为扩容后可能导致溢出
            if (this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                return Math.max(10, minCapacity);  //如果是数组,则设置默认数组容量,对应于第一次add
            } else if (minCapacity < 0) {
                throw new OutOfMemoryError();  //当达到数组最大容量,int最大值溢出后,抛出异常
            } else {
                return minCapacity;  //当老数组超过三分之二时,newCapacity会溢出,
                                     //此时就是每次添加数组加一。所以ArrayList的
            }
        } else {  //如果没有溢出,但是又不够,则最大容量扩大。否则返回新容量
            return newCapacity - 2147483639 <= 0 ? newCapacity : hugeCapacity(minCapacity);
        }
    }
//扩大最大容量
	private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) {  //超出抛异常
            throw new OutOfMemoryError();
        } else {  //扩容到最大的2的32次方减1
            return minCapacity > 2147483639 ? 2147483647 : 2147483639;
        }
    }

扩容总结:
1)当容量的1.5倍没有溢出,按1.5倍原容量扩容
2)容量的1.5倍溢出,分几种情况
- 第一次添加:设置默认初始容量10
- 老数组已经达到最大容量:溢出抛异常
- 老数组的1.5倍溢出:老数组加一
3)容量的1.5倍超过max容量,但是未溢出int取值范围,则扩容至int的最大值

2、删除元素

//删除指定索引处的元素
	public E remove(int index) {
        Objects.checkIndex(index, this.size);  //检验索引正确性
        Object[] es = this.elementData;
        E oldValue = es[index];
        this.fastRemove(es, index);  //调用fastRemove进行删除
        return oldValue;  //返回删除元素
    }
	private void fastRemove(Object[] es, int i) {
        ++this.modCount;
        int newSize;
        if ((newSize = this.size - 1) > i) {
            System.arraycopy(es, i + 1, es, i, newSize - i);  //通过拷贝来删除
        }
        es[this.size = newSize] = null;  //最后的元素设置为null
    }
//删除指定元素,返回值为boolean
	public boolean remove(Object o) {
        Object[] es = this.elementData;
        int size = this.size;
        int i = 0;
        if (o == null) {  //非null或非null,在数组中找到第一个然后调用fastRemove进行删除,如果没有,则返回false
            while(true) {
                if (i >= size) {
                    return false;
                }
                if (es[i] == null) {
                    break;
                }
                ++i;
            }
        } else {
            while(true) {
                if (i >= size) {
                    return false;
                }
                if (o.equals(es[i])) {
                    break;
                }
                ++i;
            }
        }
        this.fastRemove(es, i);
        return true;
    }
//删除指定索引范围内的元素
	protected void removeRange(int fromIndex, int toIndex) {
        if (fromIndex > toIndex) {
            throw new IndexOutOfBoundsException(outOfBoundsMsg(fromIndex, toIndex));
        } else {
            ++this.modCount;
            this.shiftTailOverGap(this.elementData, fromIndex, toIndex);
        }
    }
    private void shiftTailOverGap(Object[] es, int lo, int hi) {
        System.arraycopy(es, hi, es, lo, this.size - hi);  //拷贝删除范围后的到删除初始位置
        int to = this.size;
        for(int i = this.size -= hi - lo; i < to; ++i) {  //删掉多余的元素
            es[i] = null;
        }
    }
//删除或保留指定集合中包含的所有元素
	public boolean removeAll(Collection<?> c) {  //删除指定指定集合包含的元素
        return this.batchRemove(c, false, 0, this.size);
    }
    public boolean retainAll(Collection<?> c) {  //保留指定集合包含的元素
        return this.batchRemove(c, true, 0, this.size);
    }
    boolean batchRemove(Collection<?> c, boolean complement, int from, int end) {  //实际调用的方法
        Objects.requireNonNull(c);
        Object[] es = this.elementData;

        for(int r = from; r != end; ++r) {
            if (c.contains(es[r]) != complement) {  //如果存在
                int w = r++;

                try {
                    for(; r < end; ++r) {
                        Object e;
                        if (c.contains(e = es[r]) == complement) {  //循环前移
                            es[w++] = e;
                        }
                    }
                } catch (Throwable var12) {
                    System.arraycopy(es, r, es, w, end - r);
                    w += end - r;
                    throw var12;
                } finally {
                    this.modCount += end - w;
                    this.shiftTailOverGap(es, w, end);
                }
                return true;
            }
        }
        return false;
    }

3、清除ArrayList

	public void clear() {
        ++this.modCount;
        Object[] es = this.elementData;
        int to = this.size;
        for(int i = this.size = 0; i < to; ++i) {  //遍历整个数组设置为null,并把size设置为0
            es[i] = null;
        }
    }

4、其他常用方法

//获取指定索引处的元素,由于是数组存储,所以复杂度是O(1)
	public E get(int index) {
        Objects.checkIndex(index, this.size);
        return this.elementData(index);
    }
//设置指定索引处的值,并返回之前的值
	public E set(int index, E element) {
        Objects.checkIndex(index, this.size);
        E oldValue = this.elementData(index);
        this.elementData[index] = element;
        return oldValue;
    }
//整理ArrayList,将其容量设置为当前元素size大小
	public void trimToSize() {
        ++this.modCount;
        if (this.size < this.elementData.length) {
            this.elementData = this.size == 0 ? EMPTY_ELEMENTDATA : Arrays.copyOf(this.elementData, this.size);  //copyOf返回新数组对象
        }
    }
//返回当前ArrayList中元素的个数
	public int size() {
        return this.size;
    }
//判断ArrayList中是否有元素
	public boolean isEmpty() {
        return this.size == 0;
    }
//判断是否包含指定元素,调用indexOf判断
	public boolean contains(Object o) {
        return this.indexOf(o) >= 0;
    }
//调用indexOfRange判断
	public int indexOf(Object o) {
        return this.indexOfRange(o, 0, this.size);
    }
//最终判断逻辑,判断是否包含指定元素
    int indexOfRange(Object o, int start, int end) {
        Object[] es = this.elementData;
        int i;
        if (o == null) {  //因为可添加null,所以判断null
            for(i = start; i < end; ++i) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for(i = start; i < end; ++i) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;  //没有则返回-1
    }
//从后往前判断是否包含指定元素
    public int lastIndexOf(Object o) {
        return this.lastIndexOfRange(o, 0, this.size);
    }
    int lastIndexOfRange(Object o, int start, int end) {
        Object[] es = this.elementData;
        int i;
        if (o == null) {
            for(i = end - 1; i >= start; --i) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for(i = end - 1; i >= start; --i) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;  //没有返回-1
    }
//转化为数组,分两种,这一种是不传入参数,转化为Object数组
	public Object[] toArray() {
        return Arrays.copyOf(this.elementData, this.size);
    }
//第二种是传入具体的数组类型,转化为具体类型的数组。如果类型不匹配,编译器会报错。
//传入的参数可以为new T[0],返回会重新生成一个新的T[]类型的数组
    public <T> T[] toArray(T[] a) {
        if (a.length < this.size) {
            return Arrays.copyOf(this.elementData, this.size, a.getClass());
        } else {
            System.arraycopy(this.elementData, 0, a, 0, this.size);
            if (a.length > this.size) {
                a[this.size] = null;
            }

            return a;
        }
    }
//排序,实际调用的是Arrays中的sort
	public void sort(Comparator<? super E> c) {
        int expectedModCount = this.modCount;
        Arrays.sort(this.elementData, 0, this.size, c);
        if (this.modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        } else {
            ++this.modCount;
        }
    }
//返回子序列,返回的是一个ArrayList中内部类的实例
	public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, this.size);
        return new ArrayList.SubList(this, fromIndex, toIndex);
    }

总结

1、ArrayList底层使用的是Object数组。
2、初始容量为10,可传入参数设置初始化容量。无参构造时,初始化容量为0,第一个add时容量扩为初始容量10。
3、基础扩容策略为原数组长度的1.5倍。超过最大容量但是还未溢出,则扩大最大容量。超过三分之二,则每次加一。溢出int最大值则抛出异常。
4、增加和删除使用的都是arrayCopy方法。实现RandomAccess,可支持快速访问,推荐遍历使用for。增删复杂度O(n),查询和修改复杂度O(1)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ArrayList源码分析(基于JDK11) 的相关文章

  • Java Try Catch Final 没有 Catch 的情况下会阻塞

    我正在审查一些新代码 该程序只有一个 try 和一个 finally 块 既然排除了 catch 块 那么如果 try 块遇到异常或任何可抛出的内容 它如何工作 它直接进入finally块吗 如果 try 块中的任何代码可以引发已检查异常
  • 无法解析类型为 xxx 的任何 bean;限定符:[@javax.enterprise.inject.Any()]

    我有一个 LoginProvider 接口 public interface LoginProvider boolean login String username String password 以及两种不同的实现 public clas
  • 使用cameltestsupport进行Camel单元测试,模板始终为空

    我正在用 Camel 做一个简单的单元测试 我想做的就是从文件 在资源下 读取 JSON 内容 将其发送到 Java 类进行验证 这是我试图测试的路线 无论我做什么 模板 我用来发送正文 json 始终为空 这是我的代码 public cl
  • Spring安全“记住我”cookie在第一个请求中不可用

    我无法在登录请求后检索 Spring 记住我 cookie 但它在对受保护页面的下一个请求中工作正常 谁能告诉我怎样才能立即得到它 我在登录请求中设置了记住我的 cookie 但在 Spring 重定向回原始 受保护的 url 后无法检索它
  • Android 自定义视图不能以正确的方式处理透明度/alpha

    我正在绘制自定义视图 在此视图中 我使用两个不同的绘画和路径对象在画布上绘画 我基本上是在绘制两个重叠的形状 添加 Alpha 后 视图中重叠的部分比图像的其余部分更暗 这是不希望的 但我不知道如何解决它 这是我的代码片段 用于展示我如何在
  • 如何从 Retrofit2 获取字符串响应?

    我正在做 android 正在寻找一种方法来执行超级基本的 http GET POST 请求 我不断收到错误 java lang IllegalArgumentException Unable to create converter for
  • 如何让spring为JdbcMetadataStore创建相应的schema?

    我想使用此处描述的 jdbc 元数据存储 https docs spring io spring integration docs 5 2 0 BUILD SNAPSHOT reference html jdbc html jdbc met
  • 如何将 android.net.Uri 转换为 java.net.URL? [复制]

    这个问题在这里已经有答案了 有没有办法从Uri to URL 我正在使用的库需要这个 它only接受一个URL但我需要在我的设备上使用图像 如果该方案的Uri is http or https new URL uri toString 应该
  • Java:正则表达式排除空值

    在问题中here https stackoverflow com questions 51359056 java regexp for a separated group of digits 我得到了正则表达式来匹配 1 到 99 之间的一
  • 将表值参数与 SQL Server JDBC 结合使用

    任何人都可以提供一些有关如何将表值参数 TVP 与 SQL Server JDBC 一起使用的指导吗 我使用的是微软提供的6 0版本的SQL Server驱动程序 我已经查看了官方文档 https msdn microsoft com en
  • Java 收集返回顶级项目的映射的嵌套流

    我有以下模型 class Item String name List
  • Spring Security OAuth2简单配置

    我有一个简单的项目 需要以下简单的配置 我有一个 密码 grant type 这意味着我可以提交用户名 密码 用户在登录表单中输入 并在成功时获得 access token 有了该 access token 我就可以请求 API 并获取用户
  • 在 Spring Boot Actuator 健康检查 API 中启用日志记录

    我正在使用 Spring boot Actuator APIproject https imobilenumbertracker com 拥有一个健康检查端点 并通过以下方式启用它 management endpoints web base
  • JSON 到 hashmap (杰克逊)

    我想将 JSON 转换为 HashMapJackson http jackson codehaus org 这是我的 JSON String json Opleidingen name Bijz trajecten zorg en welz
  • Android - 9 补丁

    我正在尝试使用 9 块图片创建一个新的微调器背景 我尝试了很多方法来获得完美的图像 但都失败了 s Here is my 9 patch 当我用Draw 9 patch模拟时 内容看起来不错 但是带有箭头的部分没有显示 或者当它显示时 这部
  • Hibernate 和可序列化实体

    有谁知道是否有一个框架能够从实体类中剥离 Hibernate 集合以使它们可序列化 我查看了 BeanLib 但它似乎只进行实体的深层复制 而不允许我为实体类中的集合类型指定实现映射 BeanLib 目前不适用于 Hibernate 3 5
  • 在android中跟踪FTP上传数据?

    我有一个运行 Android 的 FTP 系统 但我希望能够在上传时跟踪字节 这样我就可以在上传过程中更新进度条 安卓可以实现这个功能吗 现在 我正在使用org apache common net ftp我正在使用的代码如下 另外 我在 A
  • Java &= 运算符应用 & 或 && 吗?

    Assuming boolean a false 我想知道是否这样做 a b 相当于 a a b logical AND a is false hence b is not evaluated 或者另一方面 这意味着 a a b Bitwi
  • 嵌入式 Jetty - 以编程方式添加基于表单的身份验证

    有没有一种方法可以按如下方式以编程方式添加基于表单的身份验证 我用的是我自己的LdapLoginModule 最初我使用基本身份验证并且工作正常 但现在我想在登录页面上进行更多控制 例如显示徽标等 有没有好的样品 我正在使用嵌入式 jett
  • JAXB - 列表<可序列化>?

    我使用 xjc 制作了一些课程 public class MyType XmlElementRefs XmlElementRef name MyInnerType type JAXBElement class required false

随机推荐

  • React 16官网 (main concepts) 浏览

    翻译一下官网 顺便了解一下React 16版本的新特性 照旧 从Hello World开始 ReactDOM render h1 Hello world h1 document getElementById root 在集成了React的必
  • 母版页使用问题(显示系统时间 js)

    在使用母版页的时候 发现源文件控件元素的ID和生成HTML文件的ID不一致 表单from的name属性和id属性变成了aspnetForm 控件的id属性被无缘无故了加上了ctl00 ContentPlaceHolder1 前缀 其name
  • 基于Arduino nano 的6路循迹小车

    define leftA PIN 7 define leftB PIN 6 define left Pwm PIN 5 define STBY 8 define rightA PIN 9 define rightB PIN 10 defin
  • python经典练习十道(四)

    1 请输入星期几的第1个字母 用来判断是星期几 如果第1个字母一样 则继续判断第2个字母 以此类推 week Sunny Monday Tuesday Wednesday Thursday Friday Saturday while Tru
  • node搭建一个简单的脚手架

    一 什么是脚手架 脚手架 Scaffold 是指在软件开发过程中为提高开发效率而提供的一套基础代码结构 组织规范 开发工具和工程化配置的工具 脚手架可以帮助开发团队快速搭建项目的基础框架 规范项目的开发流程 并提供一些常用的功能和工具 脚手
  • mpvue返回页面,当前页面数据不会清空

    遇到问题 使用mpvue时 编辑页面会将数据加载到页面上 点击返回 新增页面时 进入的同一页面会发现数据仍然在 页面没有被卸载 数据没有清空 解决方案 在进入页面时 在生命周期内重置data数据 mounted Object assign
  • vue,elementui更改文件名下载,并添加el-progress进度条

    功能 vue elementui更改文件名下载 下载添加el progress进度条 需求 公司需要下载fastdfs文件系统文件 通过http方式 并修改下载的文件名 ps 跨域问题通过配置nginx解决 下载组件代码如下
  • 基于BC-linux/Centos下的K8S单机环境搭建

    搭建前环境准备 配置虚拟机 详细的配置流程比较简单 这里就直接放配置完成的设置 处理器是4个单核 内存是8G 硬盘空间是60G 重点是网络适配器选择NAT模式 另外这里的镜像是选择的BC linux 基于Centos下的 版本是7 6的 下
  • TCP拥塞控制

    拥塞 在某段时间 若对网络中某资源的需求超过了该资源所能提供的可用部分 网络的性能就要变坏 产生拥塞 congestion 拥塞原因 某结点缓存容量太小 某链路带宽不足 某些处理机处理效率太慢 拥塞会累积 不断加剧 增加资源并不能从根本上解
  • QtXlsx编译、使用笔记

    换个方式操作ms office excel 第一次知道QtXlsx 记录一下使用方式 项目地址 http qtxlsx debao me 网上说的编译方式没搞定 vs2013 qt5 5 1加入pro文件 pri文件 都失败 用了一个简单方
  • IIS安装配置和简单网站部署流程

    IIS安装和网站配置 环境 win10 注意 这是在win10下部署iis 开发环境下部署 开发测试 非windows server IIS简介 Internet Information Services 简称IIS 是微软提供基于wind
  • 零基础小白如何入门python爬虫?3年程序员分享python爬虫学习攻略(文内有福利)

    如果你是非计算机专业 完全是零基础编程 这篇文章就是专门为你写的 内容不长 2分钟就能看完 但还是希望能给你一些帮助 以前从纯白零基础学Python 很多坑都没人踩 现在经常看到很多Python学习群里的新朋友总是喊着 从入门到放弃 觉得学
  • 【ROS】ROS1人机界面开发:在QtCreator中创建ROS1功能包

    ROS 郭老二博文之 ROS目录 1 版本要求 ROS的QtCreator插件要和QtCreator版本对应一致 否则报错 本人QtCreator版本为 10 0 1 需要下载安装ros qtc plugin的版本也要为10 0版本 2 安
  • 用Python绘制地理图

    当您的数据包含地理信息时 丰富的地图可视化可以为您理解数据和解释分析结果的最终用户提供重要价值 Plotly Plotly是一个著名的库 用于在Python中创建交互式绘图和仪表板 安装Plotly 在命令提示符中运行这两个命令 以在我们的
  • 六、windows环境下netcat的安装及使用

    windows环境下netcat的安装及使用 s小菜鸟 2019 01 03 21 05 51 5080 收藏 14 1 下载netcat 下载地址 https eternallybored org misc netcat 2 解压文件 3
  • Java中的NIO编程

    1 BIO和NIO简介 BIO NIO AIO简介 1 Java BIO 同步并阻塞 传统阻塞型 服务器实现模式为一个连接一个线程 即客户端有连接请求时服务器端就需要启动一个线程进行处理 如果这个连接不做任何事情会造成不必要的线程开销 2
  • 中国天气网全城市代码weather_cityId

    Ctrl F 查询 城市名字 http mobile weather com cn data forecast 101010100 html 1381891660081 北京 gt 101010100 海淀 gt 101010200 朝阳
  • 【openWrt】自定义后台访问端口

    通过ssh访问openwrt系统 修改 ect config uhttpd文件 再重启openwrt即可
  • 无人不苦,不必喊疼

    张爱玲说 生活是一袭华美的长袍 里面爬满了虱子 对于大多数人来说 生活都是外面光鲜亮丽 里面却各有各的苦楚 尤其对于成人 更是早已被生活的风霜 侵袭得体无完肤 可是 生活再不易 也总要拼尽了全力往前走 才能趟过荆棘丛生 走上康庄大道 1成人
  • ArrayList源码分析(基于JDK11)

    ArrayList源码分析 基于JDK11 类字段 private static final long serialVersionUID 8683452581122892189L private static final int DEFAU