【java基础】(五)java中的容器(知识模块较详细)

这一部分在工作中用的比较多,建议好好看一下。

容器:Java Api所提供的一系列类的实例,用于在程序中存放对象。

JDK所提供的容器API位于java.util包内。

容器API的类图结构如下图所示:

记住几点:1.Collection是一个一个的往里装,Map是一对一对(键值对key-value映射对)的往里装。

                  2.Collection下的Set接口数据对象没有顺序且不能重复(可以理解为数学中的集合),List中的数据对象有顺序且可以                          重复。那怎么判断里面存的对象是否重复呢?若中间存的对象互相equals就算是重复了。

                  3.HashSet、LinkedList、ArrayList、HashMap都是图中对应接口的实现类。

(1)Collection接口

Collection接口中所定义的方法(方法名比较直观,如果英语还将就一看基本就能猜出是干啥的):

int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();
...

collection方法的基本使用举例

import java.util.ArrayList;
import java.util.Collection;

/**
 * 说明:Collection方法应用
 *
 * @author huayu
 * @date 2018/8/31 12:06 PM
 */
public class CollectionDemo {
    public static void main(String[] args) {
        //这儿想想父类引用指向子类对象是怎么回事来着,在面向对象那篇博客中说过
        Collection collection=new ArrayList();
        //可以放入不同类型的对象
        collection.add("yuhua");
        collection.add(18);
        collection.add(21.0);
        collection.add(new Integer(10));
        collection.addAll(collection);
        System.out.println(collection.size());
        System.out.println(collection.hashCode());
        //内部执行调用了tostring()方法
        System.out.println(collection);
    }
}

结果:
8
-1207994999
[yuhua, 18, 21.0, 10, yuhua, 18, 21.0, 10]

 

/**
 * 说明:Collection方法应用HashSet
 *
 * @author huayu
 * @date 2018/8/31 12:06 PM
 */
public class CollectionDemo {
    public static void main(String[] args) {
        //hashset是拿hash表实现的set
        Collection collection=new HashSet();
        //可以放入不同类型的对象
        collection.add("yuhua");
        collection.add(18);
        collection.add(21.0);
        collection.add(new Integer(10));
        collection.addAll(collection);
        System.out.println(collection.size());
        System.out.println(collection.hashCode());
        //内部执行调用了tostring()方法
        System.out.println(collection);
    }
}

结果(观察一下跟上一个例子arraylist的区别)
4
1192550516
[18, 21.0, yuhua, 10]
import java.util.Collection;
import java.util.LinkedList;

/**
 * 说明:Collection方法应用LinkedList
 *
 * @author huayu
 * @date 2018/8/31 12:06 PM
 */
public class CollectionDemo {
    public static void main(String[] args) {
        Collection collection=new LinkedList();
        //可以放入不同类型的对象
        collection.add("yuhua");
        collection.add(18);
        collection.add(21.0);
        collection.add(new Integer(10));
        collection.addAll(collection);
        System.out.println(collection.size());
        System.out.println(collection.hashCode());
        //内部执行调用了tostring()方法
        System.out.println(collection);
    }
}
结果:
8
-1207994999
[yuhua, 18, 21.0, 10, yuhua, 18, 21.0, 10]

容器类对象在调用remove,contains等方法时需要比较对象是否相等,这会涉及到对象类型的equals方法和hashCode方法,对于自定义的类型,需要重写equals和hashCode方法以实现自定义的对象相等规则(注意:相等的对象应该具有相等的hash codes,比如,我们在查找词典的时候,通过索引去找字,在严格意义上讲那个索引就是一个对象,找的字就是一个值,所以当两个值一样的时候它的hashcode必须得一样,当重写equals方法时必须重写hashCode方法,在这个类的某个对象被当作索引(键)的时候使用)。

(2)Iterator接口

所有实现了Collection接口的容器类都有一个iterator()方法用以返回一个实现了Iterator接口的对象,这个对象可以是多种类型,不同的Collection实现类型遍历方式不同(用于遍历集合类)。

Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。

一句话总结,Iterator就是一个统一的遍历Collection中的元素的接口。

Iterator接口定义了如下方法

//判断游标右边是否有元素
boolean hasNext();
//返回游标右边的元素并将游标移动到下一个位置
E next();
//删除游标左边的元素,在执行完next之后该操作只能执行一次
default void remove()

 

Iterator方法使用举例:

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * 说明:Iterator方法使用简单举例
 *
 * @author huayu
 * @date 2018/8/31 12:06 PM
 */
public class CollectionDemo {
    public static void main(String[] args) {
        Collection collection=new LinkedList();
        //可以放入不同类型的对象
        collection.add("yuhua");
        collection.add(18);
        collection.add(21.0);
        collection.add(new Integer(10));
        collection.addAll(collection);
        collection.remove(18);
        Iterator iterator=collection.iterator();
        while(iterator.hasNext()){
            Object o=iterator.next();
            System.out.println(o);
        }
    }
}

结果
yuhua
21.0
10
yuhua
18
21.0
10

Iterator对象的remove方法是在迭代过程中删除元素的唯一安全的方法

import fundation.Student;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

/**
 * 说明:用Iterator迭代器遍历删除集合元素
 *
 * @author huayu
 * @date 2018/8/31 12:06 PM
 */
public class CollectionDemo {
    public static void main(String[] args) {
        Collection collection = new HashSet();
        collection.add(new Student("yu", 10));
        collection.add(new Student("hua", 20));
        //在Iterator执行的时候,会将涉及的元素锁住,只能它自己动
        for (Iterator iterator = collection.iterator(); iterator.hasNext(); ) {
            Student student = (Student) iterator.next();
            if (student.getName().length() < 3) {
                iterator.remove();
            }
        }
        System.out.println(collection);
    }
}

结果
[Student1 [name=hua, age=20]]

补充:JDK1.5增强的for循环(除了简单遍历并读出其中的内容外,不建议使用增强for循环)

增强的for循环对于遍历array或Collection的时候相当简便

缺陷:1.数组不能方便的访问下标值

           2.集合与使用Iterator相比,不能方便的删除结合中的内容,在内部也是调用Iterator


import java.util.ArrayList;
import java.util.Collection;

/**
 * 说明:增强for循环的使用
 *
 * @author huayu
 * @date 2018/9/3 1:01 PM
 */
public class ForDemo {
    public static void main(String[] args) {
        int[] arr={1,2,3,4,5};
        for(int i:arr){
            System.out.println(i);
        }
        Collection collection=new ArrayList();
        collection.add("yu");
        collection.add("hua");
        for(Object c:collection){
            System.out.println(c);
        }
    }
}

结果:
1
2
3
4
5
yu
hua

(3)Set接口

Set接口是Collection的子接口,Set接口没有提供额外的方法,但实现Set接口的容器类中的元素是没有顺序的,而且不可以重复。

Set容器可以与数学中“集合”的概念相对应。

JDK API中所提供的Set容器类有HashSet,TreeSet等。

Set接口中定义的方法

int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean retainAll(Collection<?> c);
boolean removeAll(Collection<?> c);
void clear();
boolean equals(Object o);
int hashCode();

Set方法举例

import java.util.HashSet;
import java.util.Set;

/**
 * 说明:Set举例
 *
 * @author huayu
 * @date 2018/9/3 1:13 
 */
public class HashSetDemo {
    public static void main(String[] args) {
        Set set=new HashSet();
        set.add("yu");
        set.add("hua");
        set.add("yuhua");
        //相同的元素不会被加入
        set.add("yu");
        set.add(new Integer(27));
        System.out.println(set);
    }
}

结果
[hua, yuhua, 27, yu]
import java.util.HashSet;
import java.util.Set;

/**
 * 说明:用set方法求交集与并集
 * 交集:以属于A且属于B的元素为元素的集合称为A与B的交(集)
 * 并集:以属于A或属于B的元素为元素的集合称为A与B的并(集)
 * 集合特性1:一个集合中,任何两个元素都认为是不相同的,即每个元素只能出现一次。
 * @author huayu
 * @date 2018/9/3 1:13
 */
public class HashSetDemo {
    public static void main(String[] args) {
        Set set1=new HashSet();
        Set set2=new HashSet();
        set1.add("a");
        set1.add("b");
        set1.add("c");
        set2.add("b");
        set2.add("c");
        set2.add("d");
        //求交集
        Set set=new HashSet(set1);
        set.retainAll(set2);
        //求并集
        Set set3=new HashSet(set1);
        set3.addAll(set2);
        System.out.println("set1、set2交集" + set);
        System.out.println("set1、set2并集" +set3);
    }
}

结果
set1、set2交集[b, c]
set1、set2并集[a, b, c, d]

(4)List接口

List接口是Collection的子接口,实现List接口的容器类中的元素是有顺序的,而且可以重复。

List容器中的元素都对应一个整数型的序号记载其容器中的位置,可以根据序号存取容器中的元素。

JDK所提供的List容器类有ArrayList、LinkedList等。

List接口中方法:

int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);
default void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final ListIterator<E> li = this.listIterator();
    while (li.hasNext()) {
        li.set(operator.apply(li.next()));
    }
}
default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
     }
}
int hashCode();
E set(int index, E element);
void add(int index, E element);
E remove(int index);
int indexOf(Object o);
int lastIndexOf(Object o);
ListIterator<E> listIterator();
ListIterator<E> listIterator(int index);
List<E> subList(int fromIndex, int toIndex);
default Spliterator<E> spliterator() {
    return Spliterators.spliterator(this, Spliterator.ORDERED);
}

List方法举例

import java.util.LinkedList;
import java.util.List;

/**
 * 说明:list方法举例
 *
 * @author huayu
 * @date 2018/9/3 2:31 PM
 */
public class ListDemo {
    public static void main(String[] args) {
        List list=new LinkedList();
        for (int i = 0; i < 5 ; i++) {
            list.add("a"+i);
        }
        System.out.println(list);
        list.set(1,"a10");
        System.out.println(list);
        System.out.println(list.get(1)+"");
        System.out.println(list.indexOf("a10"));
        list.remove("a0");
        System.out.println(list);
    }
}
结果:
[a0, a1, a2, a3, a4]
[a0, a10, a2, a3, a4]
a10
1
[a10, a2, a3, a4]

 

Collections类List常用算法

类java.util.Collections提供了一些静态方法实现了基于List容器的一些常用算法。

//对List容器内的元素排序
public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
}
//对List容器内的对象进行随机排列
public static void shuffle(List<?> list) {
    Random rnd = r;
    if (rnd == null)
        r = rnd = new Random(); // harmless race.
    shuffle(list, rnd);
}
//对容器内的对象进行逆序排列
public static void reverse(List<?> list) 
//用一个特定的对象重写整个List容器
public static <T> void fill(List<? super T> list, T obj)
//将src List容器内容拷贝到dest List容器
public static <T> void copy(List<? super T> dest, List<? extends T> src)
//对于顺序的List容器,采用折半查找的方法查找特定的对象
int binarySearch(List<? extends Comparable<? super T>> list, T key)

List常用算法举例:

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * 说明:Collections类中List方法举例
 *
 * @author huayu
 * @date 2018/9/3 2:55 PM
 */
public class CollectionsMethodDemo {
    public static void main(String[] args) {
        List list1 = new LinkedList();
        List list2 = new LinkedList();
        for (int i = 0; i < 9; i++) {
            list1.add("a" + i);
        }
        for (int i = 0; i < 9; i++) {
            list2.add("1");
        }
        Collections.shuffle(list1);
        System.out.println(list1);
        Collections.reverse(list1);
        System.out.println(list1);
        Collections.sort(list1);
        System.out.println(list1);
        System.out.println("list2复制前"+list2);
        Collections.copy(list2, list1);
        System.out.println("list2复制后"+list2);
        System.out.println(Collections.binarySearch(list1, "a4"));
    }
}
结果:
[a8, a3, a1, a7, a2, a6, a4, a5, a0]
[a0, a5, a4, a6, a2, a7, a1, a3, a8]
[a0, a1, a2, a3, a4, a5, a6, a7, a8]
list2复制前[1, 1, 1, 1, 1, 1, 1, 1, 1]
list2复制后[a0, a1, a2, a3, a4, a5, a6, a7, a8]
4

知识链接:

Collection 和 Collections 的区别?

1.Collection 是一个接口,是 java 提供用于内存中存储单列数据的集合框架

2.Collections 是个一个工具类,提供 了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。

 

(5)Comparable接口(注意,跟自己的类比较才有意义,类不同比较没有意义,比如狗跟猫比)

针对上面排序算法想一下根据什么确定对象“大小”顺序?

所有可以“排序”的类都实现了java.lang.Comparable接口,Comparable接口中只有一个方法

public int compareTo(T o);
该方法:
返回0   表示this==o
返回正数 表示this>obj
返回负数 表示this<obj

实现了Comparable接口的类通过实现compareTo方法从而确定该对象的排序方式(不实现Comparable接口直接调用Collections类中的sort方法对对象进行比较大小是不好使的!!!)。

对象之间比较大小方法举例:

/**
 * 说明:实现Comparable接口的Name类
 *
 * @author huayu
 * @date 2018/9/3 6:57 PM
 */
public class Name implements Comparable {
    private String firstName;
    private String lastName;

    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    @Override
    public String toString() {
        return "Name{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Name) {
            Name name = (Name) obj;
            return (firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
        }
        return super.equals(obj);
    }

    @Override
    public int hashCode() {
        return firstName.hashCode();
    }

    public int compareTo(Object o) {
        Name name = (Name) o;
        int lastComparation = lastName.compareTo(name.lastName);
        //先比较lastName再比较firstName
        return
                (lastComparation != 0 ? lastComparation : firstName.compareTo(name.firstName));
    }
}


import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

/**
 * 说明:测试Name的比较
 *
 * @author huayu
 * @date 2018/9/3 7:15 PM
 */
public class TestNameComparable {
    public static void main(String[] args) {
        List list=new LinkedList();
        list.add(new Name("shan","liu"));
        list.add(new Name("hua","yu"));
        list.add(new Name("cong","yu"));
        System.out.println("排序前"+list);
        Collections.sort(list);
        System.out.println("排序后"+list);
    }
}

结果
排序前[Name{firstName='shan', lastName='liu'}, Name{firstName='hua', lastName='yu'}, Name{firstName='cong', lastName='yu'}]
排序后[Name{firstName='shan', lastName='liu'}, Name{firstName='cong', lastName='yu'}, Name{firstName='hua', lastName='yu'}]

知识链接:

1.TreeMap 和 TreeSet 在排序时如何比较元素?

TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。

TreeMap 要求存放的键值对映射的键必须实现 Comparable 接口从而根据键对元素进行排序。

2.Collections 工具类中的 sort()方法如何比较元素?

Collections 工具类的 sort 方法有 两种重载的形式:

第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现 元素的比较;

public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }

第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是 Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java 中对函数式编程的支持)。

public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

(6)Map接口

实现Map接口的类用来存储 键-值(key-value) 对。

Map接口的实现类又HashMap和TreeMap等。

Map类中存储的键-值对通过键来标识,所以键值(作为索引)不能重复(若两个对象相互equals,他们的hashCode必须一样)。

Map接口的方法:

int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
void putAll(Map<? extends K, ? extends V> m);
void clear();
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();
//Entry<K,V>接口
interface Entry<K,V> {
        K getKey();

        V getValue();

        V setValue(V value);

        boolean equals(Object o);

        int hashCode();

        public static <K extends Comparable<? super K>, V> 
                Comparator<Map.Entry<K,V>> comparingByKey() {
                     return (Comparator<Map.Entry<K, V>> & Serializable)
                       (c1, c2) -> c1.getKey().compareTo(c2.getKey());
        }

}

boolean equals(Object o);
int hashCode();
...

Map方法举例:

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * 说明:Map方法举例
 *
 * @author huayu
 * @date 2018/9/3 8:12 PM
 */
public class MapDemo {
    public static void main(String[] args) {
        Map hashMap = new HashMap();
        Map treeMap = new TreeMap();
        hashMap.put("one", new Integer(1));
        hashMap.put("two", new Integer(2));
        hashMap.put("three", new Integer(3));
        treeMap.put("A", new Integer(1));
        treeMap.put("B", new Integer(2));
        System.out.println("hashMap中键值对个数" + hashMap.size());
        System.out.println(hashMap.containsKey("one"));
        System.out.println(treeMap.containsValue(new Integer(1)));
        if (hashMap.containsKey("two")) {
            int i = ((Integer) hashMap.get("two")).intValue();
            System.out.println(i);
        }
        Map hashMap1 = new HashMap(hashMap);
        System.out.println(hashMap1);
        hashMap1.putAll(treeMap);
        /*
          HashMap散列图、Hashtable散列表是按“有利于随机查找的散列(hash)的顺序”。
          并非按输入顺序。遍历时只能全部输出,而没有顺序。
          甚至可以rehash()重新散列,来获得更利于随机存取的内部顺序。
         总之,遍历HashMap或Hashtable时不要求顺序输出,即与顺序无关。
         */
        System.out.println("hashMap1中的东西" + hashMap1);
    }
}

结果
hashMap中键值对个数3
true
true
2
{two=2, three=3, one=1}
hashMap1中的东西{A=1, B=2, two=2, three=3, one=1}

扩展:java的拆装包问题,jdk1.5之后就支持了(Auto-boxing/unboxing)

在合适的时机自动打包、解包(自动将基础类型转换为对象,自动将对象转换为基础类型)

以上的例子也可以这么写:

/**
 * 说明:自动打包,解包释例
 *
 * @author huayu
 * @date 2018/9/3 8:12 PM
 */
public class MapDemo {
    public static void main(String[] args) {
        Map hashMap = new HashMap();
        Map treeMap = new TreeMap();
        //虽然在这输入的是基本数据1,但是它实际扔进去的仍是个对象(自动装箱)
        hashMap.put("one", 1);
        hashMap.put("two",2);
        hashMap.put("three", 3);
        treeMap.put("A", 1);
        treeMap.put("B", 2);
        System.out.println("hashMap中键值对个数" + hashMap.size());
        System.out.println(hashMap.containsKey("one"));
        System.out.println(treeMap.containsValue(new Integer(1)));
        if (hashMap.containsKey("two")) {
            //自动拆箱
            int i = (Integer) hashMap.get("two");
            System.out.println(i);
        }
        Map hashMap1 = new HashMap(hashMap);
        System.out.println(hashMap1);
        hashMap1.putAll(treeMap);
        /*
          HashMap散列图、Hashtable散列表是按“有利于随机查找的散列(hash)的顺序”。
          并非按输入顺序。遍历时只能全部输出,而没有顺序。
          甚至可以rehash()重新散列,来获得更利于随机存取的内部顺序。
         总之,遍历HashMap或Hashtable时不要求顺序输出,即与顺序无关。
         */
        System.out.println("hashMap1中的东西" + hashMap1);
    }
}
结果:
hashMap中键值对个数3
true
true
2
{two=2, three=3, one=1}
hashMap1中的东西{A=1, B=2, two=2, three=3, one=1}

(7)在这一模块的知识做个系统的学习还缺泛型这一部分,以下是链接

https://blog.csdn.net/Myuhua/article/details/82380691

 

知识链接:

1)如何选择数据结构?

衡量标准:读的效率和改的效率

Aarry读快改满

Linked改快读慢

Hash在两者之间

2)List 和 Set 以及 Map 之间的区别是什么?

List:Collection 下的子接口,保存有序的、可重复的数据

Set:Collection 下的子接口,保存无序的、不可重复的数据

Map:定义用来保存键-值对特点的数据。要求键不能重复。

Set 和 Map 容器都有基于哈希存储和排序树的两种实现版本,基于哈希存储的版本理 论存取时间复杂度为 O(1),而基于排序树版本的实现在插入或删除元素时会按照元素或元素的 键(key)构成排序树从而达到排序和去重的效果。

3)HashMap 的工作原理是什么?

HashMap map = new HashMap();//底层创建了长度为 16 的 Entry 数组向 HashMap 中添加 entry1(key,value),需要首先计算 entry1 中 key 的哈希值(根据 key 所在类的 hashCode()计算得到),此哈希值经过处理以后,得到在底层 Entry[]数组中要存储的位置 i.如果位置 i 上没有元素,则 entry1 直接添加成功。如果位置 i 上已经存在 entry2(或还有链表存在的 entry3,entry4),则需要通过循环的方法,依次比较 entry1 中 key 和其他的 entry 是否 equals.如果返回值为 true.则使用 entry1 的 value 去替换 equals 为 true 的 entry 的 value.如果遍历一遍以后,发现所有的 equals 返回都为 false,则 entry1 仍可添加成功。entry1 指向原有的 entry 元素。

4)HashMap 和 Hashtable 的区别?

HashMap:1作为 Map 的主要实现类2线程安全的3可以存储 null 的 key 和 value

Hashtable:2Map 的古老实现类2线程不安全的3不可以存储 null 的 key 和 value

(8)最后,对这一模块的知识总结一下。

      对于这章我们使用1136总结:

     一张图

     一个类:Collections

    三个知识点:增强For循环、Generic、Auto-boxing/unboxing

    六个接口

 

  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小猿架构

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

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

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

打赏作者

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

抵扣说明:

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

余额充值