Java 集合深入理解 (六) :AbstractList类

前言
AbstractList 此类提供 List 接口的骨干实现,从而最大限度地减少了实现由“随机访问”数据存储(如数组)支持的接口所需的工作。对于连续的访问数据(如链表),应优先使用AbstractSequentialList,而非此类, 可以了解该类也是很有必要的

全篇注释

/**
*此类提供了{@link List}的框架实现接口以最小化实现此接口所需的工作
*由“随机访问”数据存储(如数组)支持。对于顺序访问数据(如链表),{@link AbstractSequentialList}应该优先于这个类使用。<p>要实现一个不可修改的列表,程序员只需扩展这个类并为{@link#get(int)}和{@link List#size()size()}方法。
*<p>要实现可修改列表,程序员必须另外重写{@link#set(int,Object)set(int,E)}方法(否则抛出一个{@code UnsupportedOperationException})。如果列表是
*可变大小程序员还必须重写{@link#add(int,Object)add(int,E)}和{@link#remove(int)}方法。
*<p>程序员通常应该提供void(无参数)和collection构造函数,按照{@link Collection}接口中的建议规范。
*<p>与其他抽象集合实现不同,程序员是这样做的<i>不</i>必须提供迭代器实现;迭代器和
*列表迭代器是由这个类在“随机访问”之上实现的方法:
*{@link#get(int)},
*{@link#set(int,Object)set(int,E)},
*{@link#add(int,Object)add(int,E)}和
*{@link#remove(int)}。
*<p>此类中每个非抽象方法的文档描述了其具体实施。如果正在实现的集合允许更高效的实现。
* <p>This class is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @author  Josh Bloch
 * @author  Neal Gafter
 * @since 1.2
 */

注释解析
1.框架实现接口以最小化实现此接口所需基本方法
2.由“随机访问”数据存储(如数组)支持
3.要实现一个不可修改的列表,程序员只需扩展这个类并为{@link#get(int)}和{@link List#size()size()}方法
4.要实现可修改列表,程序员必须另外重写 set(int,Object)set(int,E)
6.对于链表AbstractSequentialList应该优先于这个类使用;
7.如果add remove等方法 没有实现,则会抛出UnsupportedOperationException 异常的
这个和AbstractCollection 中的注释描述的很像,都利用的模板方法,保证一些基础方法的实现,然后如果要实现可修改的点,需要实现对应的方法

Java 集合深入理解 (八) :Collection接口和list接口深入理解

add 方法

抽象类是没有实现add方法的,如果继承者没有实现add(int index, E element)则会抛出UnsupportedOperationException异常

  /**
   *将指定的元素追加到此列表的末尾(可选)操作)。<p>支持此操作的列表可能会限制可以将元素添加到此列表中。特别是一些
   *列表将拒绝添加空元素,其他列表将强制对可能添加的元素类型的限制。列表类应该在其文档中明确指定任何限制可以添加哪些元素。
     *
     * <p>This implementation calls {@code add(size(), e)}.
     *
     * <p>注意,这个实现抛出一个
     * {@code UnsupportedOperationException} unless
     * {@link #add(int, Object) add(int, E)} 被覆盖.
     *
     * @param 要附加到此列表的元素
     * @return {@code true} (as specified by {@link Collection#add})
     * @throws UnsupportedOperationException if the {@code add} 操作 表示此列表不支持
     *        
     * @throws ClassCastException  如果指定元素的类
     *         阻止将其添加到此列表
     * @throws NullPointerException 如果指定的元素为null
     *         列表不允许空元素
     * @throws IllegalArgumentException 如果这个元素的某些属性
     *         阻止将其添加到此列表
     */
    public boolean add(E e) {
        add(size(), e);
        return true;
    }
 /**
     * {@inheritDoc}
     *
     * <p>这个实现总是抛出一个
     * {@code UnsupportedOperationException}.
     *
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @throws IllegalArgumentException      {@inheritDoc}
     * @throws IndexOutOfBoundsException     {@inheritDoc}
     */
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }
/**
     * {@inheritDoc}
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    abstract public E get(int index);
 /**
     * {@inheritDoc}
     *
     * <p>This implementation always throws an
     * {@code UnsupportedOperationException}.
     *
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @throws IllegalArgumentException      {@inheritDoc}
     * @throws IndexOutOfBoundsException     {@inheritDoc}
     */
    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }

 /**
     * {@inheritDoc}
     *
     * <p>This implementation always throws an
     * {@code UnsupportedOperationException}.
     *
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @throws IllegalArgumentException      {@inheritDoc}
     * @throws IndexOutOfBoundsException     {@inheritDoc}
     */
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    /**
     * {@inheritDoc}
     *
     * <p>This implementation always throws an
     * {@code UnsupportedOperationException}.
     *
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws IndexOutOfBoundsException     {@inheritDoc}
     */
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }

**抽象方法 **
继承者去实现 get(int index) set(int index, E element) remove(int index)
要不然在调用此方法时会抛出UnsupportedOperationException 异常

indexOf和lastIndexOf方法

抽象类提供了查找对象的方式
获取迭代器
一个从头开始寻找,一个从尾开始往前寻找,直到找到元素为止,包括调用的nextIndex 等方法,都是最后调用到get() 方法。

  /**
     * {@inheritDoc}
     *
     * <p>这个实现首先得到一个列表迭代器 (with
     * {@code listIterator()}).  然后,它在列表上迭代,直到找到指定的元素或到达列表的末尾。
     *
     * @throws ClassCastException   {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
    public int indexOf(Object o) {
        ListIterator<E> it = listIterator();
        if (o==null) {
            while (it.hasNext())
                if (it.next()==null)
                    return it.previousIndex();
        } else {
            while (it.hasNext())
                if (o.equals(it.next()))
                    return it.previousIndex();
        }
        return -1;
    }

    /**
     * {@inheritDoc}
     *
     * <p>这个实现首先得到一个指向末尾的列表迭代器
     * 名单上的 (with {@code listIterator(size())}).  然后,它迭代
     * 向后遍历列表,直到找到指定的元素,或者
     * 到达列表的开头。
     *
     * @throws ClassCastException   {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
    public int lastIndexOf(Object o) {
        ListIterator<E> it = listIterator(size());
        if (o==null) {
            while (it.hasPrevious())
                if (it.previous()==null)
                    return it.nextIndex();
        } else {
            while (it.hasPrevious())
                if (o.equals(it.previous()))
                    return it.nextIndex();
        }
        return -1;
    }

批量操作

clear()方法
调用的removeRange方法
removeRange方法
通过将任何后续元素向左移动(减少其索引),元素来缩短列表,操作调用及其子列表。重写此方法以利用列表实现的内部可以改进此列表上,性能及其子列表。
fromIndex 是包含了的,toIndex是不包含,for (int i=0, n=toIndex-fromIndex; i<n; i++) {
这个关键点在这里,toIndex=fromIndex 该循环也是会进去一次的,所以fromIndex 也是会被删除的。 这在比如说arraylist中就被覆盖了,重写的,也是提高效率

 /**
     * 从此列表中删除所有元素(可选操作)。
     * 此呼叫返回后,列表将为空。
     *
     * <p>This implementation calls {@code removeRange(0, size())}.
     *
     * <p>注意这个实现抛出
     * {@code UnsupportedOperationException} unless {@code remove(int
     * index)} or {@code removeRange(int fromIndex, int toIndex)} is
     * overridden.
     *
     * @throws UnsupportedOperationException if the {@code clear} operation
     *         is not supported by this list
     */
    public void clear() {
        removeRange(0, size());
    }

  /**
    *从此列表中删除索引介于{@code fromIndex}(包含)和{@code toIndex}(独占)。将任何后续元素向左移动(减少其索引)。
    *这个调用通过{@code(toIndex-fromlindex)}元素来缩短列表。(如果{@code toIndex==fromIndex},则此操作无效。)
    *<p>此方法由此列表上的{@code clear}操作调用及其子列表。重写此方法以利用列表实现的内部可以改进此列表上{@code clear}
     操作的	性能及其子列表。
	*<p>此实现在{@codefromindex},并重复调用{@codelistiterator.next}
	*后跟{@code ListIterator.remove},直到完成整个范围
	*已删除<b> 注意:如果{@codelistiterator.remove}需要线性
	*时间,这个实现需要二次时间</b>
 	* @param fromIndex index of first element to be removed
     * @param toIndex index after last element to be removed
     */
    protected void removeRange(int fromIndex, int toIndex) {
        ListIterator<E> it = listIterator(fromIndex);
        for (int i=0, n=toIndex-fromIndex; i<n; i++) {
            it.next();
            it.remove();
        }
    }

addAll 方法
addAll 这个公共的方法,通过调用抽象的 add(index++, e);去实现,确实效率会慢很多,所以像arraylist这些实现类,就重写该方法

 /**
     * {@inheritDoc}
     *
     * <p>此实现获取指定集合上的迭代器并对其进行迭代,插入从 在适当的位置迭代这个列表,一次一个,
     * using {@code add(int, E)}.
     * 为了提高效率,许多实现将覆盖此方法。
     *
     * <p>Note that this implementation throws an
     * {@code UnsupportedOperationException} unless
     * {@link #add(int, Object) add(int, E)} is overridden.
     *
     * @throws UnsupportedOperationException {@inheritDoc}
     * @throws ClassCastException            {@inheritDoc}
     * @throws NullPointerException          {@inheritDoc}
     * @throws IllegalArgumentException      {@inheritDoc}
     * @throws IndexOutOfBoundsException     {@inheritDoc}
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }

迭代器

这其中有两个迭代器通过iterator 和listIterator 方法给我们使用
1.Itr 迭代器
1.属性
cursor 后续调用下一个要返回的元素的索引。
lastRet 最近对下一个或的调用返回的元素的索引上一个。如果此元素被调用删除,则重置为-1移除。
也就是记录上个元素的索引,这在next方法中就能对比,如果remove了的话,就重置为-1;
2.next 和 remove方法
并在remove等操作中添加对lastRet 的判断, 防止多次删除等操作

2.ListItr
该迭代器 解释是实现依赖于备份列表,
从源码来说,相当于 Itr的增强,
set 方法,对节点的替换,
previous方法,后置遍历的方法
add 方法, 添加数据到末尾

Java 集合深入理解 (三) :java.util 包的集合中 fail-fast 快速失败机制

 /**
    *按正确的顺序返回此列表中元素的迭代器。<p>此实现返回迭代器接口,依赖于支持列表的{@code size()},
     *{@code get(int)}和{@code remove(int)}方法。
    *<p>请注意,此方法返回的迭代器将抛出{@link UnsupportedOperationException}响应其
    *{@code remove}方法,除非列表的{@code remove(int)}方法已覆盖。
    *<p>此实现可以在规范中所述的并发修改的面
    *对于(protected){@link#modCount}字段。
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * {@inheritDoc}
     *
     * <p>This implementation returns {@code listIterator(0)}.
     *
     * @see #listIterator(int)
     */
    public ListIterator<E> listIterator() {
        return listIterator(0);
    }

    /**
     * {@inheritDoc}
     *
    *<p>此实现返回{@code ListIterator}接口,扩展了{@code迭代器}由{@code迭代器()}方法返回的接口。
    *{@code ListIterator}实现依赖于备份列表{@code get(int)},{@code set(int,E)},{@code add(int,E)}
    *以及{@code remove(int)}方法。<p>注意,此实现返回的列表迭代器将
    *抛出{@link unsportDoperationException}来响应
    *{@code remove}、{@code set}和{@code add}方法,除非列表的{@code remove(int)}、{@code set(int,E)和
    *{@code add(int,E)}方法被重写。
    *<p>此实现可以在
    *并发修改的面,如规范中所述
    *(受保护){@link\modCount}字段。
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public ListIterator<E> listIterator(final int index) {
        rangeCheckForAdd(index);

        return new ListItr(index);
    }

    private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         */
        int cursor = 0;

       /**
       *最近对下一个或的调用返回的元素的索引上一个。如果此元素被调用删除,则重置为-1移除。
        */
        int lastRet = -1;

        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         */
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size();
        }

        public E next() {
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
 private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public E previous() {
            checkForComodification();
            try {
                int i = cursor - 1;
                E previous = get(i);
                lastRet = cursor = i;
                return previous;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor-1;
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.set(lastRet, e);
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                AbstractList.this.add(i, e);
                lastRet = -1;
                cursor = i + 1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

在这里插入图片描述

subList 操作

返回的是父集合的一部分视图 也就是 还是操作的原来那个集合,只是因为 指针限制,所以操作的,指针区间的那部分。
new 一个SubList 对象,并在提供 add 方法 或者remove方法,set等方法, 将原有的集合持有着,后续操作

 /**
     * {@inheritDoc}
     *
    *<p>这个实现返回一个包含子类的列表{@code AbstractList}。子类在私有字段中存储
    *备份列表中子列表的偏移量,子列表的大小(在其生命周期内可能会发生变化)和
    *{@code modCount}支持列表的值。有两种变体子类,其中一个实现{@code RandomAccess}。
    *如果此列表实现{@code RandomAccess},则返回的列表将
    *是实现{@code RandomAccess}的子类的实例。
    *<p>子类的{@code set(int,E)},{@code get(int)},
    *{@code add(int,E)},{@code remove(int)},{@code addAll(int,
     *Collection)}和{@code removeRange(int,int)}方法
    *委托给备份抽象列表中相应的方法,在边界检查索引并调整偏移量之后。这个
    *{@code addAll(Collection c)}方法只返回{@code addAll(size,
    *c)}。
    *<p>方法{@CodeListIterator(int)}返回一个“包装器对象”在备份列表上的列表迭代器上,使用
    *备份列表上的相应方法。{@code iterator}方法
    *只返回{@code lisiterator()},和{@code size}方法只返回子类的{@code size}字段。
    *<p>所有方法首先检查支持列表等于其预期值,并抛出
     *{@code ConcurrentModificationException}如果不是。
     *
     * @throws IndexOutOfBoundsException if an endpoint index value is out of range
     *         {@code (fromIndex < 0 || toIndex > size)}
     * @throws IllegalArgumentException if the endpoint indices are out of order
     *         {@code (fromIndex > toIndex)}
     */
    public List<E> subList(int fromIndex, int toIndex) {
        return (this instanceof RandomAccess ?
                new RandomAccessSubList<>(this, fromIndex, toIndex) :
                new SubList<>(this, fromIndex, toIndex));
    }
class SubList<E> extends AbstractList<E> {
    private final AbstractList<E> l;
    private final int offset;
    private int size;

    SubList(AbstractList<E> list, int fromIndex, int toIndex) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > list.size())
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
        l = list;
        offset = fromIndex;
        size = toIndex - fromIndex;
        this.modCount = l.modCount;
    }

    public E set(int index, E element) {
        rangeCheck(index);
        checkForComodification();
        return l.set(index+offset, element);
    }

    public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        return l.get(index+offset);
    }

    public int size() {
        checkForComodification();
        return size;
    }

    public void add(int index, E element) {
        rangeCheckForAdd(index);
        checkForComodification();
        l.add(index+offset, element);
        this.modCount = l.modCount;
        size++;
    }

    public E remove(int index) {
        rangeCheck(index);
        checkForComodification();
        E result = l.remove(index+offset);
        this.modCount = l.modCount;
        size--;
        return result;
    }

    protected void removeRange(int fromIndex, int toIndex) {
        checkForComodification();
        l.removeRange(fromIndex+offset, toIndex+offset);
        this.modCount = l.modCount;
        size -= (toIndex-fromIndex);
    }

    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        int cSize = c.size();
        if (cSize==0)
            return false;

        checkForComodification();
        l.addAll(offset+index, c);
        this.modCount = l.modCount;
        size += cSize;
        return true;
    }

    public Iterator<E> iterator() {
        return listIterator();
    }

   
    public List<E> subList(int fromIndex, int toIndex) {
        return new SubList<>(this, fromIndex, toIndex);
    }

    private void rangeCheck(int index) {
        if (index < 0 || index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private void rangeCheckForAdd(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    private String outOfBoundsMsg(int index) {
        return "Index: "+index+", Size: "+size;
    }

    private void checkForComodification() {
        if (this.modCount != l.modCount)
            throw new ConcurrentModificationException();
    }
}

在这里插入图片描述

比较和散列

1.equals 会比较 对象是否相等
通过 获取两个集合的迭代器去,遍历集合中数据,最后判断对象equals是否相等
2.hashCode 方法
返回对应的hashcode值

/**
    *将指定对象与此列表进行相等性比较。退换商品
	*{@code true}当且仅当指定的对象也是列表时,两者
	*列表具有相同的大小,并且
	*这两个列表是相等的(两个元素{@code e1}和
	*{@code e2}如果{@code(e1==null),则{@code e2}等于</i>?e2==空:
	*equals(e2))})换句话说,两个列表被定义为
	*如果它们包含相同顺序的相同元素,则相等。<p>
	*此实现首先检查指定的对象是否为
	*列表。如果是,则返回{@code true};如果没有,它会检查
	*指定的对象是一个列表。如果不是,则返回{@code false};如果是的话,
	*它遍历两个列表,比较相应的元素对。
	*如果任何比较返回{@code false},则此方法返回
	*{@code false}。如果任一迭代器在
	*另一个返回{@code false}(因为列表长度不等);
	*否则,当迭代完成时,它返回{@code true}。
     *
     * @param o the object to be compared for equality with this list
     * @return {@code true} if the specified object is equal to this list
     */
    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof List))
            return false;

        ListIterator<E> e1 = listIterator();
        ListIterator<?> e2 = ((List<?>) o).listIterator();
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }

    /**
     * 返回此列表的哈希代码值。
     *
     * <p>This implementation uses exactly the code that is used to define the
     * list hash function in the documentation for the {@link List#hashCode}
     * method.
     *
     * @return the hash code value for this list
     */
    public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }

总结

整个AbstractList 很多抽象方法 需要继承实现包括set add 等等,如果未实现则会抛出异常,也实现了批量的操作方法,但是建议的继承者自己实现,因为效率会高一点,包括提供的sublist 以及 迭代器的功能。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
引用\[1\]中的异常"java.lang.UnsupportedOperationException: null"是由于在使用Arrays.asList()方法将数组转换为列表时,生成的列表是Arrays的内部ArrayList,而不是java.util.ArrayList。这两个ArrayList都继承自AbstractList,但是Arrays的内部ArrayList没有重写AbstractList的add和remove方法,而是直接抛出了java.lang.UnsupportedOperationException异常。因此,当使用add或remove方法时,会导致该异常的抛出。\[2\] 另外,引用\[3\]中提到,如果在xml文件中的resultType型定义错误,也会导致似的异常。在这种情况下,需要确保resultType的型与实际的实体型匹配,以避免出现java.lang.UnsupportedOperationException异常。\[3\] #### 引用[.reference_title] - *1* *2* [java.lang.UnsupportedOperationException: null异常处理](https://blog.csdn.net/qq_40236927/article/details/123198161)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Caused by: java.lang.UnsupportedOperationException: null 解决办法](https://blog.csdn.net/qq_37950196/article/details/108627860)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踩踩踩从踩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值