Vector详细介绍(源码解析)和使用示例

概要

学完ArrayListLinkedList之后,我们接着学习Vector。学习方式还是和之前一样,先对Vector有个整体认识,然后再学习它的源码;最后再通过实例来学会使用它。
第1部分 Vector介绍
第2部分 Vector数据结构
第3部分 Vector源码解析(基于JDK1.6.0_45)
第4部分 Vector遍历方式
第5部分 Vector示例

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3308833.html

 

第1部分 Vector介绍

Vector简介

Vector 是矢量队列,它是JDK1.0版本添加的类。继承于AbstractList,实现了List, RandomAccess, Cloneable这些接口。
Vector 继承了AbstractList,实现了List;所以,它是一个队列,支持相关的添加、删除、修改、遍历等功能
Vector 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在Vector中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。
Vector 实现了Cloneable接口,即实现clone()函数。它能被克隆。

和ArrayList不同,Vector中的操作是线程安全的

 

Vector的构造函数

复制代码
Vector共有4个构造函数
// 默认构造函数
Vector()

// capacity是Vector的默认容量大小。当由于增加数据导致容量增加时,每次容量会增加一倍。
Vector(int capacity)

// capacity是Vector的默认容量大小,capacityIncrement是每次Vector容量增加时的增量值。
Vector(int capacity, int capacityIncrement)

// 创建一个包含collection的Vector
Vector(Collection<? extends E> collection)
复制代码

  

Vector的API

复制代码
synchronized boolean        add(E object)
             void           add(int location, E object)
synchronized boolean        addAll(Collection<? extends E> collection)
synchronized boolean        addAll(int location, Collection<? extends E> collection)
synchronized void           addElement(E object)
synchronized int            capacity()
             void           clear()
synchronized Object         clone()
             boolean        contains(Object object)
synchronized boolean        containsAll(Collection<?> collection)
synchronized void           copyInto(Object[] elements)
synchronized E              elementAt(int location)
             Enumeration<E> elements()
synchronized void           ensureCapacity(int minimumCapacity)
synchronized boolean        equals(Object object)
synchronized E              firstElement()
             E              get(int location)
synchronized int            hashCode()
synchronized int            indexOf(Object object, int location)
             int            indexOf(Object object)
synchronized void           insertElementAt(E object, int location)
synchronized boolean        isEmpty()
synchronized E              lastElement()
synchronized int            lastIndexOf(Object object, int location)
synchronized int            lastIndexOf(Object object)
synchronized E              remove(int location)
             boolean        remove(Object object)
synchronized boolean        removeAll(Collection<?> collection)
synchronized void           removeAllElements()
synchronized boolean        removeElement(Object object)
synchronized void           removeElementAt(int location)
synchronized boolean        retainAll(Collection<?> collection)
synchronized E              set(int location, E object)
synchronized void           setElementAt(E object, int location)
synchronized void           setSize(int length)
synchronized int            size()
synchronized List<E>        subList(int start, int end)
synchronized <T> T[]        toArray(T[] contents)
synchronized Object[]       toArray()
synchronized String         toString()
synchronized void           trimToSize()
复制代码

 

第2部分 Vector数据结构

Vector的继承关系

复制代码
java.lang.Object
   ↳     java.util.AbstractCollection<E>
         ↳     java.util.AbstractList<E>
               ↳     java.util.Vector<E>

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}
复制代码

 

Vector与Collection关系如下图

Vector的数据结构和ArrayList差不多,它包含了3个成员变量:elementData , elementCount, capacityIncrement

(01) elementData 是"Object[]类型的数组",它保存了添加到Vector中的元素。elementData是个动态数组,如果初始化Vector时,没指定动态数组的>大小,则使用默认大小10。随着Vector中元素的增加,Vector的容量也会动态增长,capacityIncrement是与容量增长相关的增长系数,具体的增长方式,请参考源码分析中的ensureCapacity()函数。

(02) elementCount 是动态数组的实际大小。

(03) capacityIncrement 是动态数组的增长系数。如果在创建Vector时,指定了capacityIncrement的大小;则,每次当Vector中动态数组容量增加时>,增加的大小都是capacityIncrement。

 

第3部分 Vector源码解析(基于JDK1.6.0_45)

为了更了解Vector的原理,下面对Vector源码代码作出分析。 

复制代码
  1 package java.util;
  2 
  3 public class Vector<E>
  4     extends AbstractList<E>
  5     implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  6 {
  7    
  8     // 保存Vector中数据的数组
  9     protected Object[] elementData;
 10 
 11     // 实际数据的数量
 12     protected int elementCount;
 13 
 14     // 容量增长系数
 15     protected int capacityIncrement;
 16 
 17     // Vector的序列版本号
 18     private static final long serialVersionUID = -2767605614048989439L;
 19 
 20     // Vector构造函数。默认容量是10。
 21     public Vector() {
 22         this(10);
 23     }
 24 
 25     // 指定Vector容量大小的构造函数
 26     public Vector(int initialCapacity) {
 27         this(initialCapacity, 0);
 28     }
 29 
 30     // 指定Vector"容量大小"和"增长系数"的构造函数
 31     public Vector(int initialCapacity, int capacityIncrement) {
 32         super();
 33         if (initialCapacity < 0)
 34             throw new IllegalArgumentException("Illegal Capacity: "+
 35                                                initialCapacity);
 36         // 新建一个数组,数组容量是initialCapacity
 37         this.elementData = new Object[initialCapacity];
 38         // 设置容量增长系数
 39         this.capacityIncrement = capacityIncrement;
 40     }
 41 
 42     // 指定集合的Vector构造函数。
 43     public Vector(Collection<? extends E> c) {
 44         // 获取“集合(c)”的数组,并将其赋值给elementData
 45         elementData = c.toArray();
 46         // 设置数组长度
 47         elementCount = elementData.length;
 48         // c.toArray might (incorrectly) not return Object[] (see 6260652)
 49         if (elementData.getClass() != Object[].class)
 50             elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
 51     }
 52 
 53     // 将数组Vector的全部元素都拷贝到数组anArray中
 54     public synchronized void copyInto(Object[] anArray) {
 55         System.arraycopy(elementData, 0, anArray, 0, elementCount);
 56     }
 57 
 58     // 将当前容量值设为 =实际元素个数
 59     public synchronized void trimToSize() {
 60         modCount++;
 61         int oldCapacity = elementData.length;
 62         if (elementCount < oldCapacity) {
 63             elementData = Arrays.copyOf(elementData, elementCount);
 64         }
 65     }
 66 
 67     // 确认“Vector容量”的帮助函数
 68     private void ensureCapacityHelper(int minCapacity) {
 69         int oldCapacity = elementData.length;
 70         // 当Vector的容量不足以容纳当前的全部元素,增加容量大小。
 71         // 若 容量增量系数>0(即capacityIncrement>0),则将容量增大当capacityIncrement
 72         // 否则,将容量增大一倍。
 73         if (minCapacity > oldCapacity) {
 74             Object[] oldData = elementData;
 75             int newCapacity = (capacityIncrement > 0) ?
 76                 (oldCapacity + capacityIncrement) : (oldCapacity * 2);
 77             if (newCapacity < minCapacity) {
 78                 newCapacity = minCapacity;
 79             }
 80             elementData = Arrays.copyOf(elementData, newCapacity);
 81         }
 82     }
 83 
 84     // 确定Vector的容量。
 85     public synchronized void ensureCapacity(int minCapacity) {
 86         // 将Vector的改变统计数+1
 87         modCount++;
 88         ensureCapacityHelper(minCapacity);
 89     }
 90 
 91     // 设置容量值为 newSize
 92     public synchronized void setSize(int newSize) {
 93         modCount++;
 94         if (newSize > elementCount) {
 95             // 若 "newSize 大于 Vector容量",则调整Vector的大小。
 96             ensureCapacityHelper(newSize);
 97         } else {
 98             // 若 "newSize 小于/等于 Vector容量",则将newSize位置开始的元素都设置为null
 99             for (int i = newSize ; i < elementCount ; i++) {
100                 elementData[i] = null;
101             }
102         }
103         elementCount = newSize;
104     }
105 
106     // 返回“Vector的总的容量”
107     public synchronized int capacity() {
108         return elementData.length;
109     }
110 
111     // 返回“Vector的实际大小”,即Vector中元素个数
112     public synchronized int size() {
113         return elementCount;
114     }
115 
116     // 判断Vector是否为空
117     public synchronized boolean isEmpty() {
118         return elementCount == 0;
119     }
120 
121     // 返回“Vector中全部元素对应的Enumeration”
122     public Enumeration<E> elements() {
123         // 通过匿名类实现Enumeration
124         return new Enumeration<E>() {
125             int count = 0;
126 
127             // 是否存在下一个元素
128             public boolean hasMoreElements() {
129                 return count < elementCount;
130             }
131 
132             // 获取下一个元素
133             public E nextElement() {
134                 synchronized (Vector.this) {
135                     if (count < elementCount) {
136                         return (E)elementData[count++];
137                     }
138                 }
139                 throw new NoSuchElementException("Vector Enumeration");
140             }
141         };
142     }
143 
144     // 返回Vector中是否包含对象(o)
145     public boolean contains(Object o) {
146         return indexOf(o, 0) >= 0;
147     }
148 
149 
150     // 从index位置开始向后查找元素(o)。
151     // 若找到,则返回元素的索引值;否则,返回-1
152     public synchronized int indexOf(Object o, int index) {
153         if (o == null) {
154             // 若查找元素为null,则正向找出null元素,并返回它对应的序号
155             for (int i = index ; i < elementCount ; i++)
156             if (elementData[i]==null)
157                 return i;
158         } else {
159             // 若查找元素不为null,则正向找出该元素,并返回它对应的序号
160             for (int i = index ; i < elementCount ; i++)
161             if (o.equals(elementData[i]))
162                 return i;
163         }
164         return -1;
165     }
166 
167     // 查找并返回元素(o)在Vector中的索引值
168     public int indexOf(Object o) {
169         return indexOf(o, 0);
170     }
171 
172     // 从后向前查找元素(o)。并返回元素的索引
173     public synchronized int lastIndexOf(Object o) {
174         return lastIndexOf(o, elementCount-1);
175     }
176 
177     // 从后向前查找元素(o)。开始位置是从前向后的第index个数;
178     // 若找到,则返回元素的“索引值”;否则,返回-1。
179     public synchronized int lastIndexOf(Object o, int index) {
180         if (index >= elementCount)
181             throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
182 
183         if (o == null) {
184             // 若查找元素为null,则反向找出null元素,并返回它对应的序号
185             for (int i = index; i >= 0; i--)
186             if (elementData[i]==null)
187                 return i;
188         } else {
189             // 若查找元素不为null,则反向找出该元素,并返回它对应的序号
190             for (int i = index; i >= 0; i--)
191             if (o.equals(elementData[i]))
192                 return i;
193         }
194         return -1;
195     }
196 
197     // 返回Vector中index位置的元素。
198     // 若index月结,则抛出异常
199     public synchronized E elementAt(int index) {
200         if (index >= elementCount) {
201             throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
202         }
203 
204         return (E)elementData[index];
205     }
206 
207     // 获取Vector中的第一个元素。
208     // 若失败,则抛出异常!
209     public synchronized E firstElement() {
210         if (elementCount == 0) {
211             throw new NoSuchElementException();
212         }
213         return (E)elementData[0];
214     }
215 
216     // 获取Vector中的最后一个元素。
217     // 若失败,则抛出异常!
218     public synchronized E lastElement() {
219         if (elementCount == 0) {
220             throw new NoSuchElementException();
221         }
222         return (E)elementData[elementCount - 1];
223     }
224 
225     // 设置index位置的元素值为obj
226     public synchronized void setElementAt(E obj, int index) {
227         if (index >= elementCount) {
228             throw new ArrayIndexOutOfBoundsException(index + " >= " +
229                                  elementCount);
230         }
231         elementData[index] = obj;
232     }
233 
234     // 删除index位置的元素
235     public synchronized void removeElementAt(int index) {
236         modCount++;
237         if (index >= elementCount) {
238             throw new ArrayIndexOutOfBoundsException(index + " >= " +
239                                  elementCount);
240         } else if (index < 0) {
241             throw new ArrayIndexOutOfBoundsException(index);
242         }
243 
244         int j = elementCount - index - 1;
245         if (j > 0) {
246             System.arraycopy(elementData, index + 1, elementData, index, j);
247         }
248         elementCount--;
249         elementData[elementCount] = null; /* to let gc do its work */
250     }
251 
252     // 在index位置处插入元素(obj)
253     public synchronized void insertElementAt(E obj, int index) {
254         modCount++;
255         if (index > elementCount) {
256             throw new ArrayIndexOutOfBoundsException(index
257                                  + " > " + elementCount);
258         }
259         ensureCapacityHelper(elementCount + 1);
260         System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
261         elementData[index] = obj;
262         elementCount++;
263     }
264 
265     // 将“元素obj”添加到Vector末尾
266     public synchronized void addElement(E obj) {
267         modCount++;
268         ensureCapacityHelper(elementCount + 1);
269         elementData[elementCount++] = obj;
270     }
271 
272     // 在Vector中查找并删除元素obj。
273     // 成功的话,返回true;否则,返回false。
274     public synchronized boolean removeElement(Object obj) {
275         modCount++;
276         int i = indexOf(obj);
277         if (i >= 0) {
278             removeElementAt(i);
279             return true;
280         }
281         return false;
282     }
283 
284     // 删除Vector中的全部元素
285     public synchronized void removeAllElements() {
286         modCount++;
287         // 将Vector中的全部元素设为null
288         for (int i = 0; i < elementCount; i++)
289             elementData[i] = null;
290 
291         elementCount = 0;
292     }
293 
294     // 克隆函数
295     public synchronized Object clone() {
296         try {
297             Vector<E> v = (Vector<E>) super.clone();
298             // 将当前Vector的全部元素拷贝到v中
299             v.elementData = Arrays.copyOf(elementData, elementCount);
300             v.modCount = 0;
301             return v;
302         } catch (CloneNotSupportedException e) {
303             // this shouldn't happen, since we are Cloneable
304             throw new InternalError();
305         }
306     }
307 
308     // 返回Object数组
309     public synchronized Object[] toArray() {
310         return Arrays.copyOf(elementData, elementCount);
311     }
312 
313     // 返回Vector的模板数组。所谓模板数组,即可以将T设为任意的数据类型
314     public synchronized <T> T[] toArray(T[] a) {
315         // 若数组a的大小 < Vector的元素个数;
316         // 则新建一个T[]数组,数组大小是“Vector的元素个数”,并将“Vector”全部拷贝到新数组中
317         if (a.length < elementCount)
318             return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
319 
320         // 若数组a的大小 >= Vector的元素个数;
321         // 则将Vector的全部元素都拷贝到数组a中。
322     System.arraycopy(elementData, 0, a, 0, elementCount);
323 
324         if (a.length > elementCount)
325             a[elementCount] = null;
326 
327         return a;
328     }
329 
330     // 获取index位置的元素
331     public synchronized E get(int index) {
332         if (index >= elementCount)
333             throw new ArrayIndexOutOfBoundsException(index);
334 
335         return (E)elementData[index];
336     }
337 
338     // 设置index位置的值为element。并返回index位置的原始值
339     public synchronized E set(int index, E element) {
340         if (index >= elementCount)
341             throw new ArrayIndexOutOfBoundsException(index);
342 
343         Object oldValue = elementData[index];
344         elementData[index] = element;
345         return (E)oldValue;
346     }
347 
348     // 将“元素e”添加到Vector最后。
349     public synchronized boolean add(E e) {
350         modCount++;
351         ensureCapacityHelper(elementCount + 1);
352         elementData[elementCount++] = e;
353         return true;
354     }
355 
356     // 删除Vector中的元素o
357     public boolean remove(Object o) {
358         return removeElement(o);
359     }
360 
361     // 在index位置添加元素element
362     public void add(int index, E element) {
363         insertElementAt(element, index);
364     }
365 
366     // 删除index位置的元素,并返回index位置的原始值
367     public synchronized E remove(int index) {
368         modCount++;
369         if (index >= elementCount)
370             throw new ArrayIndexOutOfBoundsException(index);
371         Object oldValue = elementData[index];
372 
373         int numMoved = elementCount - index - 1;
374         if (numMoved > 0)
375             System.arraycopy(elementData, index+1, elementData, index,
376                      numMoved);
377         elementData[--elementCount] = null; // Let gc do its work
378 
379         return (E)oldValue;
380     }
381 
382     // 清空Vector
383     public void clear() {
384         removeAllElements();
385     }
386 
387     // 返回Vector是否包含集合c
388     public synchronized boolean containsAll(Collection<?> c) {
389         return super.containsAll(c);
390     }
391 
392     // 将集合c添加到Vector中
393     public synchronized boolean addAll(Collection<? extends E> c) {
394         modCount++;
395         Object[] a = c.toArray();
396         int numNew = a.length;
397         ensureCapacityHelper(elementCount + numNew);
398         // 将集合c的全部元素拷贝到数组elementData中
399         System.arraycopy(a, 0, elementData, elementCount, numNew);
400         elementCount += numNew;
401         return numNew != 0;
402     }
403 
404     // 删除集合c的全部元素
405     public synchronized boolean removeAll(Collection<?> c) {
406         return super.removeAll(c);
407     }
408 
409     // 删除“非集合c中的元素”
410     public synchronized boolean retainAll(Collection<?> c)  {
411         return super.retainAll(c);
412     }
413 
414     // 从index位置开始,将集合c添加到Vector中
415     public synchronized boolean addAll(int index, Collection<? extends E> c) {
416         modCount++;
417         if (index < 0 || index > elementCount)
418             throw new ArrayIndexOutOfBoundsException(index);
419 
420         Object[] a = c.toArray();
421         int numNew = a.length;
422         ensureCapacityHelper(elementCount + numNew);
423 
424         int numMoved = elementCount - index;
425         if (numMoved > 0)
426         System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
427 
428         System.arraycopy(a, 0, elementData, index, numNew);
429         elementCount += numNew;
430         return numNew != 0;
431     }
432 
433     // 返回两个对象是否相等
434     public synchronized boolean equals(Object o) {
435         return super.equals(o);
436     }
437 
438     // 计算哈希值
439     public synchronized int hashCode() {
440         return super.hashCode();
441     }
442 
443     // 调用父类的toString()
444     public synchronized String toString() {
445         return super.toString();
446     }
447 
448     // 获取Vector中fromIndex(包括)到toIndex(不包括)的子集
449     public synchronized List<E> subList(int fromIndex, int toIndex) {
450         return Collections.synchronizedList(super.subList(fromIndex, toIndex), this);
451     }
452 
453     // 删除Vector中fromIndex到toIndex的元素
454     protected synchronized void removeRange(int fromIndex, int toIndex) {
455         modCount++;
456         int numMoved = elementCount - toIndex;
457         System.arraycopy(elementData, toIndex, elementData, fromIndex,
458                          numMoved);
459 
460         // Let gc do its work
461         int newElementCount = elementCount - (toIndex-fromIndex);
462         while (elementCount != newElementCount)
463             elementData[--elementCount] = null;
464     }
465 
466     // java.io.Serializable的写入函数
467     private synchronized void writeObject(java.io.ObjectOutputStream s)
468         throws java.io.IOException {
469         s.defaultWriteObject();
470     }
471 }
复制代码

总结
(01) Vector实际上是通过一个数组去保存数据的。当我们构造Vecotr时;若使用默认构造函数,则Vector的默认容量大小是10
(02) 当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。
(03) Vector的克隆函数,即是将全部元素克隆到一个数组中。

 

第4部分 Vector遍历方式

Vector支持4种遍历方式。建议使用下面的第二种去遍历Vector,因为效率问题。

(01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
    value = (Integer)vec.get(i);        
}

 

(02) 第二种,随机访问,通过索引值去遍历。
由于Vector实现了RandomAccess接口,它支持通过索引值去随机访问元素。

Integer value = null;
int size = vec.size();
for (int i=0; i<size; i++) {
    value = (Integer)vec.get(i);        
}

 

(03) 第三种,另一种for循环。如下:

Integer value = null;
for (Integer integ:vec) {
    value = integ;
}

 

(04) 第四种,Enumeration遍历。如下: 

Integer value = null;
Enumeration enu = vec.elements();
while (enu.hasMoreElements()) {
    value = (Integer)enu.nextElement();
}

 

测试这些遍历方式效率的代码如下

复制代码
 1 import java.util.*;
 2 
 3 /*
 4  * @desc Vector遍历方式和效率的测试程序。
 5  *
 6  * @author skywang
 7  */
 8 public class VectorRandomAccessTest {
 9 
10     public static void main(String[] args) {
11         Vector vec= new Vector();
12         for (int i=0; i<100000; i++)
13             vec.add(i);
14         iteratorThroughRandomAccess(vec) ;
15         iteratorThroughIterator(vec) ;
16         iteratorThroughFor2(vec) ;
17         iteratorThroughEnumeration(vec) ;
18     
19     }
20 
21     private static void isRandomAccessSupported(List list) {
22         if (list instanceof RandomAccess) {
23             System.out.println("RandomAccess implemented!");
24         } else {
25             System.out.println("RandomAccess not implemented!");
26         }
27 
28     }
29 
30     public static void iteratorThroughRandomAccess(List list) {
31 
32         long startTime;
33         long endTime;
34         startTime = System.currentTimeMillis();
35         for (int i=0; i<list.size(); i++) {
36             list.get(i);
37         }
38         endTime = System.currentTimeMillis();
39         long interval = endTime - startTime;
40         System.out.println("iteratorThroughRandomAccess:" + interval+" ms");
41     }
42 
43     public static void iteratorThroughIterator(List list) {
44 
45         long startTime;
46         long endTime;
47         startTime = System.currentTimeMillis();
48         for(Iterator iter = list.iterator(); iter.hasNext(); ) {
49             iter.next();
50         }
51         endTime = System.currentTimeMillis();
52         long interval = endTime - startTime;
53         System.out.println("iteratorThroughIterator:" + interval+" ms");
54     }
55 
56 
57     public static void iteratorThroughFor2(List list) {
58 
59         long startTime;
60         long endTime;
61         startTime = System.currentTimeMillis();
62         for(Object obj:list)
63             ;
64         endTime = System.currentTimeMillis();
65         long interval = endTime - startTime;
66         System.out.println("iteratorThroughFor2:" + interval+" ms");
67     }
68 
69     public static void iteratorThroughEnumeration(Vector vec) {
70 
71         long startTime;
72         long endTime;
73         startTime = System.currentTimeMillis();
74         for(Enumeration enu = vec.elements(); enu.hasMoreElements(); ) {
75             enu.nextElement();
76         }
77         endTime = System.currentTimeMillis();
78         long interval = endTime - startTime;
79         System.out.println("iteratorThroughEnumeration:" + interval+" ms");
80     }
81 }
复制代码

运行结果

iteratorThroughRandomAccess:6 ms
iteratorThroughIterator:9 ms
iteratorThroughFor2:8 ms
iteratorThroughEnumeration:7 ms

总结:遍历Vector,使用索引的随机访问方式最快,使用迭代器最慢。

 

第5部分 Vector示例

下面通过示例学习如何使用Vector

  View Code

运行结果

复制代码
vec:[100, 2, 300, 3, 4, 5]
vec.indexOf(100):0
vec.lastIndexOf(100):0
vec.firstElement():100
vec.elementAt(2):300
vec.lastElement():5
size:6
capacity:10
vec 2 to 4:[2, 300, 3]
nextElement():100
nextElement():2
nextElement():300
nextElement():3
nextElement():4
nextElement():5
vec.retain():true
vec:[100, 300]
str:100
str:300
vec.isEmpty():true
复制代码

 

转自:http://www.cnblogs.com/skywang12345/p/3308833.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值