java基础学习之类集框架(十)

类集框架的简介

类集的主要用处是在于其实现了动态对象数组的操作,并且定义了大量的操作。

单对象保存父接口:Collection

在这里插入图片描述

java.util.Collection是进行单对象保存的最大父接口,即每次利用Collection接口都只能保存
一个对象信息。

// A code block
public interface Collection<E> extends Iterable<E>

Collection接口的核心方法

NO.方法名称类型描述
1public boolean add(E e)普通向集合里面保存数据
2public boolean addAll(Collection<? extends E> c)普通追加一个集合
3public void clear()普通清空集合,根元素为null
4public boolean contains(Object o)普通判断是否包含指定内容,需要equals()支持
5public boolean isEmpty()普通判断是否是空集合(不是null)
6public boolean remove(Object o)普通删除对象,需要equals()支持
7public int size()普通取得集合中保存的元素个数
8public Object[] toArray()普通将集合变为对象数组保存
9public Iterator< E > iterator()普通为Iterator接口实例化(Interator接口定义)
对于表中的方法,一定要记住add()与iterator()两个方法。

Collection及其子接口继承关系
在这里插入图片描述

List子接口

List子接口最大的功能是里面所保存的数据可以存在有重复内容,并且在Collection子接口中List子接口是最为常用的一个子接口,在List接口中对Collection接口的功能进行了扩充

NO.方法名称类型描述
1public E get(int index)普通取得索引编号内容
2public E set(int index, E element)普通修改指定索引编号的内容
3public ListIterator< E> listIterator()普通为ListIterator接口实例化
新的子类:ArrayList

在这里插入图片描述

ArrayList子类是List子接口中最常用的一个子类。

常见用法

// An highlighted block
public class Demo{
	public static void main(String[] args){
		List<String> all = new ArrayList<>();
        System.out.println("长度:"+all.size()+",是否为空:"+all.isEmpty());
        //添加数据
        all.add("hello");
        all.add("hello");
        all.add("world");
        //删除数据,有重复的删除第一个
        all.remove("hello");
        //将list转化为数组
        String[] strings = all.toArray(new String[all.size()]);
        //for循环
        for(int x = 0; x < all.size(); x++){
            String str = all.get(x);
            System.out.println(str);
        }
        //foreach循环
        for(String s : all){
            System.out.println(s);
        }
        //iterator迭代器
        Iterator<String> iterator = all.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
            //remove需要在next方法之后操作
            iterator.remove();
        }
	}
}
执行结果:长度:0,是否为空:true
		hello
		world
		hello
		world
		hello
		world

请解释ArrayList和LinkedList的区别
实际上在List子接口中还存在一个LinkedList子类,而使用时大部分情况下都是利用子类为父接口实例化。

  1. ArrayList中采用顺序式的结果进行数据保存,并且可以自动生成相应的索引信息;
  2. LinkedList集合保存的是前后元素,也就是说,它每一个节点保存的是两个元素对象,一个它对应的下一个节点,以及另外一个它对应的上一个节点,所以LinkedList要占用比ArrayList更多的内存空间。同时LinkedList比ArrayList多实现了一个Queue队列数据接口。
旧的子类:Vector
// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        List<String> all = new Vector<String>();
        System.out.println("长度:"+all.size()+",是否为空:"+all.isEmpty());
        all.add("hello");
        all.add("hello");
        all.add("world");
        System.out.println("长度:"+all.size()+",是否为空:"+all.isEmpty());
        for(int x = 0; x < all.size();x++){
            String str = all.get(x);
            System.out.println(str);
        }
    }
}
执行结果:长度:0,是否为空:true
		长度:3,是否为空:false
		hello
		hello
		world

ArrayList和Vector子类的区别:

No区别点ArrayList(90%)Vector(10%)
1推出时间JDK1.2推出,属于新的类JDK1.0推出,属于旧的类
2性能采用异步处理采用同步处理
3数据安全非线程安全线程安全
4输出Iterator、ListIterator、foreachIterator、ListIterator、foreach、Enumeration

Set子接口

在Collection接口下又有另外一个比较常用的子接口为Set子接口,但是Set子接口并不像List子接口那样对Collection接口进行了大量的扩充,而是简单地继承了Collection接口。也就是说无法使用get()方法根据索引取得保存数据的操作。在Set接口下有两个常用的子类:HashSet、TreeSet。

HashSet是散列存放数据,而TreeSet是有序存放的子类。在实际开发中,如果要使用TreeSet子类则必须同时使用比较器的概念,而HashSet子类相对于TreeSet子类更加容易一些,所以如果没有排序要求应优先考虑HashSet子类。

使用HashSet子类的特点

  • HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。
  • HashSet 允许有 null 值。
  • HashSet 是无序的,即不会记录插入的顺序。
  • HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对
    HashSet 的并发访问。

添加元素和删除元素

// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        Set<String> all = new HashSet<String>();
        all.add("jixianit");
        all.add("mldn");
        all.add("yootk");
        all.add("yootk");
        all.remove("mldn");
        System.out.println(all);
    }
}
执行结果:[jixianit, yootk]

可以看出在Set集合中不允许保存重复数据。
迭代 HashSet

public class App 
{
    public static void main( String[] args )
    {
        Set<String> all = new HashSet<>();
        all.add("jixianit");
        all.add("mldn");
        all.add("yootk");
        //使用foreach迭代
        for(String str : all){
            System.out.println(str);
        }
        //使用迭代器
        Iterator<String> iterator = all.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

关于"Hash"的说明
这种算法就是利用二进制的计算结果来设置保存的空间,根据数值的不同,最终保存空间的位置也不同,所以利用Hash算法保存的集合都是无序的,但是查找速度较快。

使用TreeSet子类

// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        Set<String> all = new TreeSet<String>();
        all.add("jixianit");
        all.add("mldn");
        all.add("yootk");
        all.add("yootk");
        System.out.println(all);
    }
}
执行结果:[jixianit, mldn,yootk]

TreeSet子类属于排序的类集结构,所以当使用TreeSet子类实例化Set接口后,所保存的数据将变为有序,默认情况按字母的升序排列。

关于数据排序的说明

TreeSet子类保存的内容可以进行排序,但是其排序是依靠比较器接口(Comparable)实现的,即如果要利用TreeSet子类保存任意类的对象,那么该对象所在的类必须要实现java.lang.Comparable接口。

// An highlighted block
class Book implements Comparable<Book>{
    private String title;
    private double price;
    public Book(String title,double price){
        this.title = title;
        this.price = price;
    }
    @Override
    public String toString(){
        return "书名:"+this.title+",价格:"+this.price;
    }

    @Override
    public int compareTo(Book o) {
        if(this.price > o.price){
            return 1;
        }else if(this.price < o.price){
            return -1;
        }else {
            return this.title.compareTo(o.title);
        }
    }
}
public class TestDemo {
    public static void main(String args[]) {
        Set<Book> all = new TreeSet<Book>();
        all.add(new Book("Java开发实战经典",79.8));
        all.add(new Book("Java开发实战经典",79.8));
        all.add(new Book("JSP开发实战经典",79.8));
        all.add(new Book("Android开发实战经典",89.8));
        System.out.println(all);
    }
}
执行结果:[书名:JSP开发实战经典,价格:79.8, 书名:Java开发实战经典,价格:79.8, 书名:Android开发实战经典,价格:89.8]

本程序首先利用TreeSet子类保存了若干个Book类对象,由于Book类实现了Comparable接口,所以会自动将保存的Book类对象强制转换为Comparable接口对象,然后调用compareTo()方法进行排序,如果发现比较结果为0则认为是重复元素,将不再进行保存。因此TreeSet数据的排序以及重复元素的消除依靠的都是Comparable接口。

关于重复元素说明

TreeSet利用Comparable接口实现重复元素的判断,但是这样的操作只适合支持排序类集操作环境下;而其他子类(例如:HashSet)如果要消除重复元素,则必须依靠Object类中提供的两个方法。

  1. 取得哈希码:public int hashCode();
    先判断对象的哈希码是否相同,依靠哈希码取得一个对象的内容;
  2. 对象比较:public boolean equals(Object obj)。
    再将对象的属性进行依次的比较。

利用HashSet子类保存自定义对象。

// An highlighted block
class Book {
    private String title;
    private double price;
    public Book(String title,double price){
        this.title = title;
        this.price = price;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return Double.compare(book.price, price) == 0 &&
                Objects.equals(title, book.title);
    }

    @Override
    public int hashCode() {
        return Objects.hash(title, price);
    }

    @Override
    public String toString(){
        return "书名:"+this.title+",价格:"+this.price;
    }

}
public class TestDemo {
    public static void main(String args[]) {
        Set<Book> all = new HashSet<>();
        all.add(new Book("Java开发实战经典",79.8));
        all.add(new Book("Java开发实战经典",79.8));
        all.add(new Book("JSP开发实战经典",79.8));
        all.add(new Book("Android开发实战经典",89.8));
        System.out.println(all);
    }
}
执行结果:[书名:JSP开发实战经典,价格:79.8, 书名:Android开发实战经典,价格:89.8, 书名:Java开发实战经典,价格:79.8]

直接通过idea工具生成操作步骤:【Source】→【Generate hashCode() and equals()】

集合排序

对整型进行排序
public class App {
    public static void main( String[] args ) {
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(1);
        list.add(8);
        //升序排列
        Collections.sort(list);     //java.util.Collections
        System.out.println(list);
        //降序排列
        Collections.reverse(list);
        System.out.println(list);
    }
}
结果:[1, 5, 8]
	[8, 5, 1]
对字符串进行排序

根据首字母ascii码中的值来比较大小

public class App {
    public static void main( String[] args ) {
        List<String> list = new ArrayList<>();
        list.add("orange");
        list.add("tomato");
        list.add("apple");
        Collections.sort(list);     //java.util.Collections
        System.out.println(list);
    }
}
结果:[apple, orange, tomato]
根据Comparator接口进行排序

定义一个比较器实现Comparator接口中的compare()方法

根据名字进行升序排序(升序为从小到大)

class NameComparator implements Comparator<Cat>{
    @Override
    public int compare(Cat o1, Cat o2) {	
        String name1 = o1.getName();
        String name2 = o2.getName();
        int i = name1.compareTo(name2);		//降序改为:name2.compareTo(name1);就行
        return i;
    }
}
public class App {
    public static void main( String[] args ) {
        List<Cat> list = new ArrayList<>();
        list.add(new Cat("huahua",5,"英国短毛猫"));
        list.add(new Cat("fanfan",2,"中华田园猫"));
        list.add(new Cat("maomao",3,"中华田园猫"));
        //实现比较器接口写法
        Collections.sort(list,new NameComparator());     //第一个参数要排序的集合,第二个参数是比较器
        //匿名内部类写法
        Collections.sort(list, new Comparator<Cat>() {
            @Override
            public int compare(Cat o1, Cat o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        //lambda写法
        Collections.sort(list, (o1, o2) -> o1.getName().compareTo(o2.getName()));
        Systemut.println(list);
    }
}
结果:[Cat{name='fanfan', month=2, species='中华田园猫'}, Cat{name='huahua', month=5, species='英国短毛猫'}, Cat{name='maomao', month=3, species='中华田园猫'}]

根据年龄进行降序排序

class NameComparator implements Comparator<Cat>{

	//如果要按照升序排序,则o1 小于o2,返回-1(负数),相等返回0,o1大于o2返回1(正数) 
	//如果要按照降序排序,则o1 大于o2,返回1(正数),相等返回0,o1小于o2返回-1(负数)
    @Override
    public int compare(Cat o1, Cat o2) {    
        int age1 = o1.getMonth();
        int age2 = o2.getMonth();
        return age2-age1;	//升序改为age1-age2就行
    }
}
public class App {
    public static void main( String[] args ) {
        List<Cat> list = new ArrayList<>();
        list.add(new Cat("huahua",5,"英国短毛猫"));
        list.add(new Cat("fanfan",2,"中华田园猫"));
        list.add(new Cat("maomao",3,"中华田园猫"));
        Collections.sort(list,new NameComparator());     //第一个参数要排序的集合,第二个参数是比较器
        System.out.println(list);
    }
}
结果:[Cat{name='huahua', month=5, species='英国短毛猫'}, Cat{name='maomao', month=3, species='中华田园猫'}, Cat{name='fanfan', month=2, species='中华田园猫'}]
根据Comparable接口进行排序

需要排序的集合类要实现Comparable接口中的compareTo()方法。
根据价格进行降序排序

// An highlighted block
class Book implements Comparable<Book>{
    private String title;
    private double price;
    public Book(String title,double price){
        this.title = title;
        this.price = price;
    }
    @Override
    public String toString(){
        return "书名:"+this.title+",价格:"+this.price;
    }

    @Override
    public int compareTo(Book o) {
        double price1 = this.getPrice();
        double price2 = o.getPrice();
        int i = new Double(price2 - price1).intValue();
        return i;
    }
}
public class TestDemo {
    public static void main(String args[]) {
        Set<Book> all = new TreeSet<Book>();
        all.add(new Book("Java开发实战经典",79.8));
        all.add(new Book("JSP开发实战经典",99.8));
        all.add(new Book("Android开发实战经典",89.8));
        System.out.println(all);
    }
}
执行结果:[书名:JSP开发实战经典,价格:99.8, 书名:Android开发实战经典,价格:89.8, 书名:Java开发实战经典,价格:79.8]

集合输出

迭代输出:Iterator

Iterator(迭代器)是集合输出操作中最为常见的接口,而在Collection接口中也提供了直接为Iterator接口实例化的方法(iterator()),所以任何集合类型都可以转换为Iterator接口输出。

Iterator接口中一共定义了两个抽象方法,

NO.方法类型描述
1public boolean hasNext()普通判断是否还有内容
2public E next()普通取出当前内容
3public void remove()普通删除当前元素

在这里插入图片描述

// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        List<String> all = new ArrayList<>();
        all.add("hello");
        all.add("hello");
        all.add("world");
        Iterator<String> iter = all.iterator();
        while (iter.hasNext()){
            String str = iter.next();
            System.out.println(str);
        }
    }
}
执行结果:hello
		 hello
		 world

关于Iterator接口中的remove()方法。
如果利用集合类(Collection、List、Set)提供的remove()方法会导致程序中断执行的问题,而如果非要进行集合元素的删除,只能利用Iterator接口提供的remove()方法才可以正常完成。

双向迭代:ListIterator

虽然利用Iterator可以实现集合的迭代输出操作,但是Iterator本身却存在一个问题:只能进行由前向后的输出。所以为了让输出变得更加灵活,在类集框架中就提供了一个ListIterator接口,利用此接口可以实现双向迭代。ListIterator属于Iterator的子接口,此接口常用方法如表:

NO.方法类型描述
1public boolean hasPrevious()普通判断是否有前一个元素
2public E previous()普通取出前一个元素
3public E add()普通向集合追加元素
4public E set()普通修改集合元素

实际上迭代器本质上就是一个指针的移动操作,而ListIterator与Iterator的迭代处理原理类似。所以如果要进行由后向前迭代,则必须先进行由前向后迭代。

// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        List<String> all = new ArrayList<>();
        all.add("hello");
        all.add("hello");
        all.add("mldn");
        all.add("world");
        ListIterator<String> iter = all.listIterator();
        while (iter.hasNext()){
            String str = iter.next();
            System.out.println(str);
        }
        System.out.println();
        while(iter.hasPrevious()){
            String str = iter.previous();
            System.out.println(str);
        }
    }
}
执行结果:hello
		hello
		mldn
		world
		
		world
		mldn
		hello
		hello
foreach输出
// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        List<String> all = new ArrayList<>();
        all.add("hello");
        all.add("hello");
        all.add("mldn");
        all.add("world");
        for(String str : all){
            System.out.println(str);
        }
    }
}
执行结果:hello
		 hello
		 world
Enumeration输出

Enumeration(枚举输出)是与Vector类一起在JDK1.0时推出的输出接口

// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        Vector<String> all = new Vector<>();
        all.add("hello");
        all.add("hello");
        all.add("mldn");
        all.add("world");
        Enumeration<String> enu = all.elements();
        while (enu.hasMoreElements()){
            String str = enu.nextElement();
            System.out.println(str);
        }
    }
}
执行结果:hello
		 hello
		 mldn

本程序与Iterator接口输出实现的最终效果是完全一致的,唯一的区别就是,如果要使用Enumeration接口实例化,就必须依靠Vector子类完成。

偶对象保存:Map接口

Collection每次只能够保存一个对象,所以属于单值保存父接口。而在类集中又提供有保存偶对象的集合:Map集合,利用Map结合可以保存一对关联数据(按照“key = value”的形式),如图13-4所示。,这样就可以实现根据key取得value的操作。

在这里插入图片描述在这里插入图片描述
Map接口的常用方法

NO.方法类型描述
1public V put(K key, V value)普通向集合中保存元素
2public V get(Object key)普通根据key查找对应的value数据
3public Set<Map.Entry<K,V>> entrySet()普通将Map集合转化为Set集合
4public Set keySet()普通取出全部的key

HashMap的使用

// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        HashMap<String,Integer> map = new HashMap<>();
        map.put("壹",1);
        map.put("贰",2);
        map.put("叁",3);
        map.put("叁",33);
        map.put("肆",4);
        map.put("空",null);
        map.put(null,0);
        map.remove("壹");
        System.out.println(map.get("叁"));
        System.out.println(map.get(null));
        System.out.println(map.get("空"));
    }
}
执行结果:33
		 0
		 null

从上可以发现如下特点:

  • 使用HashMap定义的Map集合是无序存放的;
  • 如果发现了重复的key会进行覆盖,使用新的内容替换旧的内容;
  • 使用HashMap子类保存数据时key或value可以保存为null。

遍历HashMap的key值

public class App 
{
    public static void main( String[] args )
    {
        HashMap<String,Integer> map = new HashMap<>();
        map.put("壹",1);
        map.put("贰",2);
        map.put("叁",3);
        map.put("叁",33);
        map.put("肆",4);
        map.put("空",null);
        Set<String> keySet = map.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

遍历HashMap的value值

public class App 
{
    public static void main( String[] args )
    {
        HashMap<String,Integer> map = new HashMap<>();
        map.put("壹",1);
        map.put("贰",2);
        map.put("叁",3);
        map.put("叁",33);
        map.put("肆",4);
        map.put("空",null);
        Collection<Integer> values = map.values();
        Iterator<Integer> iterator = values.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

Hashtable的使用

// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        Map<String,Integer> map = new Hashtable<>();
        map.put("壹",1);
        map.put("贰",2);
        map.put("叁",3);
        map.put("叁",33);
        map.put("肆",4);
        System.out.println(map.get("叁"));
    }
}
执行结果:33

使用Hashtable子类实例化的Map集合中,保存的key和value都不允许出现null,否则会出现"NullPointerException"异常

HashMap和Hashtable子类的区别:

No区别点HashMapHashtable
1推出时间JDK1.2推出,属于新的类JDK1.0推出,属于旧的类
2性能采用异步处理采用同步处理
3数据安全非线程安全线程安全
4设置null允许key或value内容为null不允许设置null

利用Iterator输出Map集合

进行Map集合保存时,所保存的key与value会自动包装为Map.Entry接口对象,也就是说如果利用Iterator进行迭代,那么每当使用next()方法读取数据时返回的都会是一个Map.Entry接口对象,此接口定义如下:
public static interface Map.Entry<K,V> {}
Map.Entry接口定义的常用方法

No方法类型描述
1public K getKey()普通取得数据中的key
2public V getValue()普通取得数据中的value
3public V setValue(V value)普通修改数据中的value
在这里插入图片描述
Iterator输出Map集合的操作步骤:
1.利用entrySet()方法将Map接口数据中的数据转换为Set接口实例进行保存,此时Set接口中所使用的泛型类型为Map.Entry,而Map.Entry中的K与V的泛型类型则与Map集合定义的K与V类型相同;
2.利用Set接口中的iterator()方法将Set集合转化为Iterator接口实例;
3.利用Iterator接口进行迭代输出,每一次迭代取得的都是Map.Entry接口实例,而后利用此接口实例进行key与value的分离。
// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        Map<String,Integer> map = new HashMap<>();
        map.put("壹",1);
        map.put("贰",2);
        map.put("叁",3);
        map.put("叁",33);
        map.put("肆",4);
        map.put("空",null);
        map.put(null,0);
        Set<Map.Entry<String,Integer>> set= map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = set.iterator();
        while (iterator.hasNext()){
            Map.Entry<String, Integer> next = iterator.next();
            System.out.println(next.getKey()+"="+next.getValue());
        }
    }
}
执行结果:贰=2
		null=0=33=4=1=null

自定义Map集合的key类型

在使用Map接口的时候可以发现,几乎可以使用任意的类型来作为key或value的存在,那么也就表示也可以使用自定义的类型作为key。那么这个作为key的自定义的类必须要覆写Object类之中的hashCode()与equals()两个方法,因为只有靠这两个方法才能够确定元素是否重复,而在Map中指的是是否能够找到。

// An highlighted block
class Book{
    private String title;
    public Book(String title){
        this.title = title;
    }

    @Override
    public String toString() {
        return "Book{" +
                "title='" + title + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return Objects.equals(title, book.title);
    }

    @Override
    public int hashCode() {
        return Objects.hash(title);
    }
}
public class TestDemo {
    public static void main(String args[]) {
        Map<Book, String> map = new HashMap<>();
        map.put(new Book("Java开发"),new String("Java"));
        System.out.println(map.get(new Book("Java开发")));
    }
}
执行结果:Java

Stack子类

栈也是一种动态对象数组,采用的是一种先进后出的数据结构形式,即:在栈中最早保存的数据最后才会取出,而最后保存的数据可以最先取出

在这里插入图片描述在这里插入图片描述
java.util包中可以利用Stack类实现栈的功能,此类定义如下:
public class Stack extends Vector
Stack类的常用方法

No方法类型描述
1public E push(E item)普通数据入栈
2public E pop()普通数据出栈,如果栈中没有数据,则调用此方法会抛出空栈异常(EmptyStackException)

观察栈的操作

// An highlighted block
public class TestDemo {
    public static void main(String args[]) {
        Stack<String> all = new Stack<String>();
        all.push("www.abc.com");
        all.push("www.hhh.com");
        all.push("www.trtr.com");
        System.out.println(all.pop());
        System.out.println(all.pop());
        System.out.println(all.pop());
        System.out.println(all.pop());
    }
}
执行结果:Exception in thread "main" java.util.EmptyStackException
				at java.util.Stack.peek(Stack.java:102)
				at java.util.Stack.pop(Stack.java:84)
				at chapter4.TestDemo.main(TestDemo.java:12)
			www.trtr.com
			www.hhh.com
			www.abc.com

Properties子类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值