java学习笔记(二十二)集合

集合

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,我们就需要对这多个对象进行存储。而目前为止我们学习过的可以存储多个元素的东西是数组,但是呢,数组长度固定,不能适应变化的需求,所以,Java就提供了集合类供我们使用。
集合和数组的区别:

数组:
1.长度固定
2.可以存储基本类型,也可以存储引用类型
3.存储元素类型一致
集合:
1.长度可变
2.只可以存储引用类型
3.可以存储多种类型

集合体系图:
这里写图片描述
首先先介绍一下Collection这个接口
是集合的顶层结构,定义了集合的共性功能。
它有一些成员方法是所有集合所共有的:
成员方法:(看到E我们先把它理解为Object即可)

    A:添加功能
        boolean add(Object obj):往集合中添加一个元素
        boolean addAll(Collection c):往集合中添加多个元素
    B:删除功能
        void clear():清空所有元素
        boolean remove(Object o):从集合中删除一个元素
        boolean removeAll(Collection c):从集合中删除另一个集合的元素
    C:判断功能
        boolean contains(Object o):判断集合中是否包含指定的元素
        boolean containsAll(Collection c):判断集合中是否包含另一个集合的元素
        boolean isEmpty():判断集合是否为空。
    D:交集功能
        boolean retainAll(Collection c)
    E:迭代器(集合特有的遍历方式)
        Iterator iterator()
    F:长度功能
        int size():返回集合中元素的个数
    G:集合转数组
    Object[]toArray():把集合转成数组,然后遍历数组,其实就相当于遍历了集合。
public class CollectionDemo {
    public static void main(String[] args) {
//      A:添加功能
//          boolean add(Object obj):往集合中添加一个元素
//          boolean addAll(Collection c):往集合中添加多个元素
        Collection<String> c1=new ArrayList<String>();//创建Collection集合
        //向集合中添加元素
        c1.add("人机交互");
        c1.add("图像处理");
        c1.add("微机原理");
        //再创建一个集合对象
        Collection<String> c2=new ArrayList<String>();
        c2.add("c++");
        c2.add("java");
        //把集合c2的元素添加到c1中
        c1.addAll(c2);
        /*B:删除功能
         *          void clear():清空所有元素
         *          boolean remove(Object o):从集合中删除一个元素
         *          boolean removeAll(Collection c):从集合中删除另一个集合的元素*/
        c1.remove("c++");
        //c1.removeAll(c2);
        //c1.clear();
        /*C:判断功能
         *          boolean contains(Object o):判断集合中是否包含指定的元素
         *          boolean containsAll(Collection c):判断集合中是否包含另一个集合的元素
         *          boolean isEmpty():判断集合是否为空。*/
        //boolean contains = c1.contains("c++");
        boolean contains = c1.containsAll(c2);
        System.out.println(contains);
        /*D:交集功能
         *          boolean retainAll(Collection c)*/
        boolean retainAll = c1.retainAll(c2);//求出交集元素,并将没有交集的元素删除
        System.out.println(retainAll);
        //遍历集合c1
        Object[] arr = c1.toArray();
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
        //遍历集合c2
        Object[] arr1 = c2.toArray();
        for (int i = 0; i < arr1.length; i++) {
            System.out.println(arr1[i]);
        }           
    }
}

迭代器: Iterator iterator(),用来遍历集合中的元素

成员方法:
        Object next():返回迭代的下一个元素,并移动指向的位置
        boolean hasNext():判断是否有元素

迭代器是依赖于集合而存在的。所以,要想得到迭代器对象,必须先有集合对象。

    迭代步骤:
        A:通过集合对象获取到迭代器对象
        B:通过迭代器对象的hasNext()方法判断是否有元素
        C:通过迭代器对象的next()方法获取元素

练习:创建狗对象(带参数),存储到集合,用迭代器进行遍历并打印对象的属性数据
分析:1。先写一个Dog类
2.然后在创建一个空的集合
3.创建Dog对象
4.向集合中添加Dog对象元素
5.使用while循环加迭代器进行遍历
Dog类:

public class Dog {
    private String name;
    private int age;
    private String color;
    public Dog(String name, int age, String color) {
        super();
        this.name = name;
        this.age = age;
        this.color = color;
    }
    public Dog() {
        super();
        // TODO Auto-generated constructor stub
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }

}

然后写一个测试类:

public class CollectionDemo {
    public static void main(String[] args) {
        //创建狗对象
        Dog d1 = new Dog("大黄",2,"黄色");
        Dog d2 = new Dog("小黑",2,"黑色");
        Dog d3 = new Dog("大花",2,"花色");
        //创建集合对象
        Collection c1=new ArrayList();
        //集合中添加狗对象元素
        c1.add(d1);
        c1.add(d2);
        c1.add(d3);
        //创建迭代器对象
        Iterator it = c1.iterator();

        //遍历
        while(it.hasNext()){
            Dog d=(Dog) it.next();
            System.out.println(d.getName()+" "+d.getAge()+" "+d.getAge());
        }   
    }
}

List接口:
(1)List集合的元素有序(存储和取出顺序一致),元素可重复

(2)List的特有功能:

    A:添加功能
    void add(int index,Object obj):在指定的位置添加元素
    B:删除功能
    Object remove(int index):通过指定的索引删除元素,并把删除的元素返回
    C:获取功能
    get(int index) 返回列表中指定位置的元素。
    D:替换功能
    Object set(int index,Object obj)

下面写一些简单的代码对这些功能进行测试:

public class ListDemo {
    public static void main(String[] args) {
        //创建List集合对象
        List<String> list = new ArrayList<String>();
        //给集合添加元素
        list.add("李白");
        list.add("杜甫");
        list.add("王维");
        //遍历集合
        print(list);
        System.out.println("----------------------------");
        //void add(int index,Object obj):在指定的位置添加元素
        list.add(1, "白居易");
        print(list);
        System.out.println("----------------------------");
        //Object remove(int index):通过指定的索引删除元素,并把删除的元素返回
        String remove = list.remove(1);
        print(list);
        System.out.println("--------------------------");
        System.out.println(remove);
        System.out.println("-----------------------------");
        //get(int index) 返回列表中指定位置的元素。
        String str = list.get(0);
        System.out.println(str);
        System.out.println("----------------------");
        //Object set(int index,Object obj)
        list.set(0, "苏轼");
        print(list);


    }
    public static void print(List<String> p){
        Iterator<String> it = p.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }       
    }
}

集合中还有一个集合工具类Collections类,可以实现List的倒序与洗牌与排序

    List中元素顺序可以被洗牌Collections.shuffle(list)
    List中元素顺序可以被倒序Collections.reverse(list)
    Collections.sort(list)对List元素排序
public class CollectionsDemo {
    public static void main(String[] args) {
        //创建List集合
        List list = new ArrayList();

        //给集合中添加元素
        list.add(2);
        list.add(8);
        list.add(1);
        list.add(3);

        //List中元素顺序可以被洗牌Collections.shuffle(list)
        //Collections.shuffle(list);

        //List中元素顺序可以被倒序Collections.reverse(list)
        //Collections.reverse(list);
        //Collections.sort(list)对List元素排序(字母数字分别进行测试)
        //如果是按字母是按照a-z的顺序进行排序
        //Collections.sort(list);
        //如果是按照数字进行排序,按照从小到大的顺序进行排列
        Collections.sort(list);
        //遍历集合
        for (Object object : list) {
            System.out.println(object);
        }   
    }
}

LinkedList:list集合接口的实现类
LinkedList特有功能:

    public void addFirst(E e)//向第一个位置添加元素
    public void addLast(E e)//向最后一个位置添加元素

    public E getFirst()//获取第一个元素
    public E getLast()//获取最后一个元素

    public E removeFirst()//移除第一个元素
    public E removeLast()//移除最后一个元素

简单的进行测试:

public class LinkedListDemo {
    public static void main(String[] args) {
        //创建一个LinkedList的集合
        LinkedList list = new LinkedList();
        list.add("hello");
        list.add("world");
        list.add("java");

        //          public void addFirst(E e)
        //          public void addLast(E e)
        //需求:在hello前面加上一个元素“c++”
        list.addFirst("c++");
        list.addLast("js");


//              public E getFirst()
//              public E getLast()
//      Object first = list.getFirst();
//      Object last = list.getLast();
//      System.out.println(first);
//      System.out.println(last);


//              public E removeFirst()
//              public E removeLast()
        Object removeFirst = list.removeFirst();
        Object removeLast = list.removeLast();
        System.out.println(removeFirst);
        System.out.println(removeLast);
        System.out.println("---------------");
        //遍历集合
        for(Object obj:list){
            System.out.println(obj);
        }

    }

}

ArrayList与LinkedList的相同点与不同点

相同点:有顺序的,元素可以重复
不同点:
(1)ArrayList特点:
    底层数据结构是数组,查询快,增删慢                                     
    线程不安全,效率高           
(2)LinkedList特点:
    底层数据结构是链表,查询慢,增删快
    线程不安全,效率高

集合的遍历方式:

    1.for(普通for)(list集合专有,因为有get()方法)
    2.Iterator(迭代器)
    3.foreach(增强for)

foreach的格式:

for(集合中的元素类型   变量名:集合名){
    }

需求:用List集合存储3个汽车对象,然后遍历。(用三种方式进行遍历)
分析:
1.创建汽车集合
2.创建汽车对象
3.创建list集合对象
4.向集合中添加对象元素
5.遍历

Car类:

public class Car {
    private String brand;
    private int price;
    private String color;
    public Car() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Car(String brand, int price, String color) {
        super();
        this.brand = brand;
        this.price = price;
        this.color = color;
    }
    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public int getPrice() {
        return price;
    }
    public void setPrice(int price) {
        this.price = price;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
}
public class ListDemo {
    public static void main(String[] args) {
        //创建汽车对象
        Car c1 = new Car("大众",20000,"黑色");
        Car c2 = new Car("奥迪",40000,"红色");
        Car c3 = new Car("奔驰",60000,"白色");
        //创建集合对象
        List list =new ArrayList();
        //集合中添加元素
        list.add(c1);
        list.add(c2);
        list.add(c3);
        //使用迭代器遍历
        Iterator it = list.iterator();
        while(it.hasNext()){
            Car c=(Car) it.next();
            System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor());
        }
        System.out.println("---------------------------");
        //使用for循环遍历
        for (int i = 0; i <list.size(); i++) {
            Car c=(Car) list.get(i);
            System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor());
        }
        System.out.println("---------------------------");

        //增强for循环
        for(Object obj:list){
            Car c=(Car) obj;
            System.out.println(c.getBrand()+" "+c.getPrice()+" "+c.getColor());

        }
    }

}

结果:
这里写图片描述
set集合中的hashset
HashSet 元素顺序:元素唯一,但是无序(它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变)
如何保证元素的唯一性的呢?
通过分析源码,我们知道HashSet集合保证元素的唯一性和add()方法相关。
如何我们想深入的了解,就必须看add()方法的源码,看它的底层依赖什么内容?

     if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {...}

   左边:e.hash == hash
            比较对象的哈希值。   
    右边:((k = e.key) == key || key.equals(k))
            左边:(k = e.key) == key
                比较对象的地址值。

            右边:key.equals(k)
            比较的是对象的内容是否相同。默认情况下比较的是地址值

    结论:
    底层数据结构是哈希表。
    哈希表依赖两个方法:hashCode()和equals()


    执行流程:
        首先判断哈希值是否相同,如果不同,就直接添加到集合。
        如果相同,继续执行equals(),看其返回值,
        如果是false,就直接添加到集合。
        如果是true,说明元素重复不添加。

所以我们在使用hashset集合时想要保住元素的唯一性,就必须重写hashCode()和equals()这两个方法。至于如何重写,eclipse提供了自动生成的方法

练习:创建一个HashSet集合,添加元素(学生对象元素),保证其唯一性。
Student类:在这个类中重写hashCode()和equals()这两个方法

public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

    //重写hashCode(),equals()方法
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

测试类:

public class HashSetDemo {

    public static void main(String[] args) {
        //创建集合
        HashSet<Student> hs = new HashSet<Student>();

        //创建学生对象
        Student s1 = new Student("郭德纲", 50);
        Student s2 = new Student("刘德华", 55);
        Student s3 = new Student("张学友", 56);
        Student s4 = new Student("黎明", 57);
        Student s5 = new Student("郭德纲", 50);

        //给集合中添加元素
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);
        hs.add(s5);

        //遍历集合
        for (Student student : hs) {
            System.out.println(student);
        }

    }

}

这里写图片描述
通过分析发现:郭德纲这个对象只出现了一次,保证了元素的唯一性
TreeSet
首先看一下它的两个构造方法:

    public TreeSet()
    //构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。

    TreeSet(Comparator<? super E> comparator) 
      构造一个新的空 TreeSet,它根据指定比较器进行排序

元素顺序:使用元素的自然顺序对元素进行排序,或者根据创建 set时提供的 Comparator进行排序,具体取决于使用的构造方法。
底层算法:二叉树
元素要求, 加入自定义JavaBean
对java中已有数据类型的存入:

 1.如果是Integer类型的数据,按大小顺序存入
 2.如果是String类型的数据,按首字母a-z的顺序存入

练习:创建集合存储Integer类型的元素(20,18,23,22,17,24,19,18,24)

public class TreeSetDemo {
    public static void main(String[] args) {

        //创建一个TreeSet集合
        TreeSet<Integer> ts = new TreeSet<Integer>();
        //给集合中存储元素
        //(20,18,23,22,17,24,19,18,24)
        ts.add(20);
        ts.add(18);
        ts.add(23);
        ts.add(22);
        ts.add(17);
        ts.add(24);
        ts.add(19);
        ts.add(18);
        ts.add(24);

        //遍历集合
        for (Integer integer : ts) {
            System.out.print(integer+" ");
        }

    }

}
//结果:17 18 19 20 22 23 24 

分析:TreeSet集合特点:

      1.元素唯一
      2.元素有序

这里写图片描述
那么在存入自定义对象元素时如何保证元素有序呢?分析Integer类和String类之后发现这两个类实现了一个Comparable接口,并重写comparaTo()方法,所以我们在存入自定义对象元素是也需要重写这个方法,就可以保证元素有序.当然还有另外一种方法,我们首先看一下第二种构造方法,它需要一个比较器实现类对象,那么我们可以用匿名类部类重写比较器中的Compare方法进行比较来保证元素有序。

练习:创建集合存储Student类型的元素,并保证其有序性
方式一:
1.创建Student类并实现Comparable接口,并重写comparaTo()方法
2.创建学生对象
3.使用无参构造创建空TreeSet集合
4.添加学生元素
5.遍历
学生类中实现的compareto方法

public int compareTo(Student s) {
        //就是写的是元素的比较规则,由你自己去动手写出
        //按照学生的年龄进行排序
        /**
         * 两个对象进行比较:
         * s
         * this
         */
        int num = this.age - s.age;
        //判断年龄是否相同,如果相同比较姓名
        /**
         * 写这个比较规则的时候注意两点:
         * 1.他有主要条件,先按照主要条件进行排序
         * 2.如果主要条件相同,就需要你自己分析出来他的次要条件,再去按照次要条件进行比较
         */

        int num2 = num==0?this.name.compareTo(s.name):num;
        return num2;
    }

测试类:

public class TreeSetDemo {
    public static void main(String[] args) {
        //创建TreeSet集合,存储自定义对象
        TreeSet<Student> ts = new TreeSet<Student>();

        //给集合中添加Student对象
        Student s = new Student("guodegang", 50);
        Student s6 = new Student("liuyifei", 50);
        Student s2 = new Student("zhangxueyou", 55);
        Student s3 = new Student("amu", 45);
        Student s4 = new Student("tf-boys", 18);
        Student s5 = new Student("wangfeng", 49);

        ts.add(s);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        //遍历集合
        for (Student student : ts) {
            System.out.println(student);
        }

    }

}

这里写图片描述
方法二
1.创建Student类
2.创建学生对象
3.使用使用带选择器的有参构造创建空TreeSet集合
4.匿名类部类重写比较器中的Compare方法进行比较来保证元素有序。
5.添加学生元素
6.遍历

public class TreeSetDemo {
    public static void main(String[] args) {
        //使用匿名内部类来进行改进
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getAge() - s2.getAge();
                int num2 = num==0?s1.getName().compareTo(s2.getName()):num;
                return num2;
            }
        });

        //创建对象存入集合
        Student s = new Student("guodegang", 50);
        Student s6 = new Student("liuyifei", 50);
        Student s2 = new Student("zhangxueyou", 55);
        Student s3 = new Student("amu", 45);
        Student s4 = new Student("tf-boys", 18);
        Student s5 = new Student("wangfeng", 49);

        ts.add(s);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        ts.add(s6);

        //遍历集合
        for (Student student : ts) {
            System.out.println(student);
        }


    }

}

两者结果完全相同
HashSet与TreeSet的相同点与不同点
相同点:

单列集合,元素不可重复

不同点:

1. 底层存储的数据结构不同
    HashSet底层用的是HashMap哈希表结构存储,而TreeSet底层用的是TreeMap树结构存储
2.存储时保证数据唯一性依据不同
   HashSet是通过复写hashCode()方法和equals()方法来保证的,而TreeSet通过Compareable接口的compareTo()方法来保证的
3.有序性不一样
 HashSet无序,TreeSet有序

Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

Map接口中的方法概述(创建集合测试方法):

    A:删除功能
        void clear():移除集合中的所有键值对元素
        V remove(Object key):根据键移除键值对元素,并返回值
    B:判断功能
        boolean containsKey(Object key):判断集合中是否包含指定的键
        boolean containsValue(Object value):判断集合中是否包含指定的值
        boolean isEmpty():判断集合是否为空
    C:获取功能
        Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合,遍历键值对对象,
        利用getKey(),getValue()取出键和值(理解即可)

        V get(Object key):根据键获取值
        Set<K> keySet():获取所有的键
        Collection<V> values():获取所有的值
    D:添加功能
        V put(K key,V value):集合添加键值对
    E:长度功能
        int size():键值对对数。

进行功能测试:

public class MapDemo {
    public static void main(String[] args) {
        //创建一个Map集合
        //键是学号--值是姓名
        Map<Integer,String> map = new HashMap<Integer,String>();

        //V put(K key,V value):集合添加键值对
        map.put(1, "周杰伦");
        map.put(2, "郭德纲");
        map.put(3, "刘德华");
        map.put(4, "张学友");

        //void clear():移除集合中的所有键值对元素
        //map.clear();

        //V remove(Object key):根据键移除键值对元素,并返回值
        //String remove = map.remove(1);
        //System.out.println(remove);


        //boolean containsKey(Object key):判断集合中是否包含指定的键
        //boolean containsKey = map.containsKey(2);
        //System.out.println(containsKey);

        //boolean containsValue(Object value):判断集合中是否包含指定的值
        //boolean containsValue = map.containsValue("周杰伦");
        //System.out.println(containsValue);

        //boolean isEmpty():判断集合是否为空
        //System.out.println(map.isEmpty());

        //int size():键值对对数。
        //System.out.println(map.size());

        //Collection<V> values():获取所有的值
        /*
        Collection<String> values = map.values();
        Iterator<String> it = values.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }*/


        //Set<Map.Entry<K,V>> entrySet():获取键值对对象的集合,遍历键值对对象,
        //利用getKey(),getValue()取出键和值(理解即可)
        Set<Entry<Integer,String>> entrySet = map.entrySet();
        for (Entry<Integer, String> entry : entrySet) {
            System.out.println(entry.getKey()+"  "+entry.getValue());
        }

        System.out.println("--------------------");
        //Set<K> keySet():获取所有的键
        Set<Integer> keys = map.keySet();
        for (Integer key : keys) {
            //V get(Object key):根据键获取值
            System.out.println(key+"  "+map.get(key));
        }

    }

}

HashMap

 元素顺序:元素顺序不可预测
 底层算法:哈希算法
 对键没有要求(仅仅相对于TreeMap来说)
public class HashMapDemo {
    public static void main(String[] args) {
        // 1.存入(String,String)主要讲解遍历方式,键:丈夫  值:妻子
        HashMap<String, String> hm = new HashMap<String,String>();

        //给键值对集合存入元素
        hm.put("文章", "马伊琍");
        hm.put("黄晓明", "baby");
        hm.put("汪老师", "章子怡");
        hm.put("周杰伦", "昆凌");
        //hm.put("文章", "姚笛");,当后面存入的元素和前面的键的值相同的时候,前面的元素的值会被后面的元素的值代替

        //遍历,通过建找值
        Set<String> keys = hm.keySet();
        for (String key : keys) {
            System.out.println(key+"  "+hm.get(key));
        }

        System.out.println("-------------");
        //通过找到结婚证,来分别找到丈夫和妻子
        Set<Entry<String,String>> entrySet = hm.entrySet();
        for (Entry<String, String> entry : entrySet) {
            System.out.println(entry.getKey()+"  "+entry.getValue());
        }

    }

}

Treemap

 元素顺序:元素顺序与键的排序规则有关
底层算法:Tree算法

.HashMap与TreeMap的相同点与不同点

相同点:主要用于存储键(key)值(value)对,根据键得到值,因此键不允许键重复,但允许值重复。 
不同点:
    1.HashMap里面存入的键值对在取出的时候是随机的,也是我们最常用的一个Map.根据键可以直接获取它的值,
具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。  
    2.TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值