第十章、容器

一、Java容器的整体结构

二、List用法

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 测试List接口的常用方法
 */
public class TestList {
    public static void main(String[] args) {
        test3();
    }

    /**
     * 测试List的常用方法
     */
    public static void test1(){
        List list=new ArrayList();
        System.out.println(list.isEmpty());
        list.add("张三");
        System.out.println(list);
        System.out.println(list.isEmpty());

        list.add("李四");
        list.add("王五");
        System.out.println(list);
        System.out.println("List的大小:"+list.size());
        System.out.println("List是否包含:"+list.contains("李四"));

        list.remove("李四");
        System.out.println(list);

        Object[] objs=list.toArray();
        System.out.println("转换成Object数组:"+ Arrays.toString(objs));

        list.clear();
        System.out.println(list);
    }

    /**
     * 测试和索引操作的相关方法
     */
    public static void test2(){
        //List存储的是:有序,可重复
        List list=new ArrayList();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        System.out.println(list);

        list.add(2,"高");
        System.out.println(list);
        list.remove(2);
        System.out.println(list);
        list.set(2,"喝杯水");
        System.out.println(list);
        System.out.println(list.get(2));
        list.add("A");
        System.out.println(list);

        System.out.println(list.indexOf("A"));
        System.out.println(list.lastIndexOf("A"));
    }

    /**
     * 测试两个容器之间元素处理
     */
    public static void test3(){
        List list=new ArrayList();
        list.add("张三");
        list.add("李四");
        list.add("王五");
        list.add("马汉");

        List list1=new ArrayList();
        list1.add("张龙");
        list1.add("赵虎");
        list1.add("马汉");

        System.out.println(list.containsAll(list1));

        list.addAll(list1);
        System.out.println(list);
//        list.removeAll(list1);
//        System.out.println(list);

        System.out.println(list);
        System.out.println(list1);
        list.retainAll(list1);
        System.out.println(list);

    }
}

三、Set用法

/**
 * 测试Set
 * Set 无序,不可重复
 */
public class TestSet {
    public static void main(String[] args) {
        test2();
    }

    public static void test1(){
        Set set=new HashSet();
        set.add("hello");
        set.add("world");
        set.add("hello");   //相同的元素不再被加入

        System.out.println(set);
    }

    //Set中不可重复的核心:equals()方法
    public static void test2(){
        Emp e1=new Emp(1001,"张三");
        Emp e2=new Emp(1002,"李四");
        Emp e3=new Emp(1001,"王五");

        Set s=new HashSet();
        s.add(e1);
        s.add(e2);
        s.add(e3);
        System.out.println(s);
    }
}

class Emp{
    private int id;
    private String ename;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Emp emp = (Emp) o;
        return id == emp.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }

    @Override
    public String toString() {
        return "Emp{" +
                "id=" + id +
                ", ename='" + ename + '\'' +
                '}';
    }

    public Emp(int id, String ename) {
        this.id = id;
        this.ename = ename;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }
}

四、Map用法

 

/**
 * 测试Map的使用方法
 */
public class TestMap {
    public static void main(String[] args) {
        test4();
    }

    //Map的常见用法
    public static void test1() {
        Map m1 = new HashMap();
        m1.put(1, "one");
        m1.put(2, "two");
        m1.put(3, "three");
        System.out.println(m1);

        //如果键重复,就替换掉旧的键值对
        m1.put(2, "二");
        Object o = m1.get(2);
        System.out.println(o);
        System.out.println(m1);

        System.out.println(m1.containsKey(4));
        System.out.println(m1.containsValue("three"));

        m1.remove(2);
        System.out.println(m1);

        Map m2 = new HashMap();
        m2.put("yi", "111");
        m2.put("er", "222");
        m2.put(3, "333");

        m1.putAll(m2);
        System.out.println(m1);
    }

    //泛型的简单用法
    public static void test2() {
        List<String> list = new ArrayList<String>();
        list.add("name");
        String str = list.get(0);
        System.out.println(str);

        Set<Integer> set = new HashSet<>();
        set.add(123);
        System.out.println(set);

        Map<Integer, String> m2 = new HashMap<>();
        m2.put(1, "一");
        m2.put(2, "二");
        m2.put(3, "三");
    }

    /**
     * 容器的遍历
     * 遍历List、Set
     */
    public static void test3() {

        List<String> s = new ArrayList<>();
//        Set<String> s=new HashSet<>();
        s.add("aa");
        s.add("bb");
        s.add("cc");
        //通过索引遍历list,只适用于List。
        for (int i = 0; i < s.size(); i++) {
            String temp = s.get(i);
            System.out.println(temp);
        }
        //通过增强for循环遍历list,适用于List、Set
        for (String temp : s) {
            System.out.println(temp);
        }
        //使用Iterator(迭代)对象遍历,适用于List、Set
        for (Iterator iter = s.iterator(); iter.hasNext(); ) {
            String temp = (String) iter.next();
            System.out.println(temp);
        }

    }

    /**
     * 容器的遍历
     * 遍历Map(遍历key和value)
     */
    public static void test4() {
        Map<String, String> map = new HashMap<>();
        map.put("one", "一");
        map.put("two", "二");
        map.put("three", "三");

        Set<String> keys = map.keySet();
        //通过增强for循环遍历Set,适用于List、Set
        for (String temp : keys) {
            System.out.println(temp);
        }
        //使用Iterator(迭代)对象遍历,适用于List、Set
        for (Iterator iter = keys.iterator(); iter.hasNext(); ) {
            String temp = (String) iter.next();
            System.out.println(temp);
        }

        //遍历健值
        for (String temp : keys) {
            System.out.println(map.get(temp));
        }
        Collection<String> values = map.values();
        for (String temp : values) {
            System.out.println(temp);
        }

        //使用EntrySet,遍历Key和value
        Set<Map.Entry<String,String>> entrySet=map.entrySet();
        for(Map.Entry e:entrySet){
            System.out.println(e.getKey()+"====="+e.getValue());
        }
    }
}

五、存取二维表格信息

package com.myproject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 使用容器的不同方式,存储表格的信息
 */
public class StoreTable {
    public static void main(String[] args) {
        test2();
    }

    //使用Map方式来存储
    public static void test1(){
        Map<String,Object> m1=new HashMap<>();
        m1.put("id",1001);
        m1.put("title","我爱开发");
        m1.put("createDate","2021-8-10");
        m1.put("length",300);

        Map<String,Object> m2=new HashMap<>();
        m2.put("id",1002);
        m2.put("title","我爱数据");
        m2.put("createDate","2021-9-10");
        m2.put("length",400);

        Map<String,Object> m3=new HashMap<>();
        m3.put("id",1003);
        m3.put("title","我爱编程");
        m3.put("createDate","2021-9-12");
        m3.put("length",500);

        //存储了整个表格的信息
        List<Map<String,Object>> list=new ArrayList<>();
        list.add(m1);
        list.add(m2);
        list.add(m3);

        System.out.println("id\t\ttitle\t\tcreateDate\tlength");
        for(int i=0;i<list.size();i++){
            Map<String,Object> temp=list.get(i);
            System.out.println(
            temp.get("id")+"\t"
            +temp.get("title")+"\t\t"
            +temp.get("createDate")+"\t"
            +temp.get("length")
            );
        }


    }

    //使用List+Javabean的方式来存储
    public static void test2(){
        VideoInfo v1=new VideoInfo(1001,"我爱开发","2021-8-10",300);
        VideoInfo v2=new VideoInfo(1002,"我爱数据","2021-9-10",400);
        VideoInfo v3=new VideoInfo(1003,"我爱编程","2021-9-12",380);

        List<VideoInfo> list=new ArrayList<>();
        list.add(v1);
        list.add(v2);
        list.add(v3);

//        for(int i=0;i<list.size();i++){
//            System.out.println(list);
//        }
        System.out.println("id\t\ttitle\tcreateDate\tlength");
        for(VideoInfo temp:list){
            System.out.println(temp);
        }
    }
}

class VideoInfo{
    private int id;
    private String title;
    private String createDate;
    private int length;

    public VideoInfo(int id, String title, String createDate, int length) {
        this.id = id;
        this.title = title;
        this.createDate = createDate;
        this.length = length;
    }

    @Override
    public String toString() {
        return
                getId() +"\t"
                + getTitle() + "\t"
                + getCreateDate() + "\t"
                + getLength();
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getCreateDate() {
        return createDate;
    }

    public void setCreateDate(String createDate) {
        this.createDate = createDate;
    }

    public String  getLength() {
        if(this.length<60){
            return this.length+"秒";
        }else if(this.length<3600){
            int minutes=this.length/60;
            int seconds=this.length%60;
            return minutes+"分"+seconds+"秒";
        }else{
            int hours=this.length/3600;
            int minutes=(this.length/3600)/60;
            int seconds=(this.length/3600)%60;
            return hours+"时"+minutes+"分"+seconds+"秒";
        }

    }

    public void setLength(int length) {
        this.length = length;
    }
}

六、泛型详解

/**
 * 测试泛型的基本用法
 */
public class TestGeneric {
    public static void main(String[] args) {

    }

    public static void test1(){
        Generic1<Integer> g1=new Generic1<>();
        g1.aa(22);
        g1.bb(333);

        Generic1<String> g2=new Generic1<>();
        g2.aa("111");
        g2.bb("aaa");

    }
}

//定义一个简单的泛型类
class Generic1<T>{
    public T aa(T obj){
        System.out.println(obj);
        return obj;
    }

    public <N> void bb(N obj){
        System.out.println(obj);
    }
}

interface MyList<E>{
    int size();
    boolean isEmpty();
    void add(E e);
    E get(int index);
}

class MyArrayList<E> implements MyList<E>{

    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public void add(E e) {

    }

    @Override
    public E get(int index) {
        return null;
    }
}
package com.myproject;

import java.util.ArrayList;
import java.util.List;

/**
 * 通配符?和上下限定
 */
public class TestGeneric2 {
    public static void main(String[] args) {
        List<Aniaml> list1=new ArrayList<>();
        List<Dog> list2=new ArrayList<>();
        List<TaiDi> list3=new ArrayList<>();

//        test1(list1);
        test1(list2);
        test1(list3);

        test2(list1);
        test2(list2);
//        test2(list3);
    }
    //Dog和它的子类
    public static void test1(List<? extends Dog> list){
        System.out.println(list);
    }
    //Dog和它的父类
    public static void  test2(List<? super Dog> list){
        System.out.println(list);
    }
}

class Aniaml{}

class Dog extends Aniaml{}

class TaiDi extends Dog{}
/**
 * 测试边遍历、边删除(使用迭代器Iterator进行遍历删除)
 */
public class IteratorTest {
    public static void main(String[] args) {
        List<String> list=new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        list.add("bad");
        list.add("bag");

        System.out.println(list);
        //边遍历边删除时,容器的size会发生变化
//        for(int i=0;i<list.size();i++){
//            String temp=list.get(i);
//
//            if(temp.startsWith("b")){
//                list.remove(i);
//            }
//            System.out.println("size:"+list.size());
//        }
        //使用迭代器对象,他始终指向下一个元素,不关心容器的整体变化
        for(Iterator<String> iter=list.iterator();iter.hasNext();){
            String temp=iter.next();
            if(temp.startsWith("b")){
                iter.remove();
            }
        }
        System.out.println(list);
    }
}

七、手写容器

package com.myproject;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义的MyList接口,模仿的是List接口
 * @param <E>
 */
public interface MyList<E> {

//    List list=new ArrayList();
    int size();
    boolean isEmpty();
    void add(E obj);
    public void add(int index,E obj);
    public E set(int index,E obj);
    public E get(int index);

    public boolean contains(E obj);
    Object[] toArray();
    boolean remove(E obj);
    void remove(int index);
    void clear();
}

package com.myproject;

import java.util.Arrays;

public class MyArrarList<E> implements MyList<E> {

    private int size;
    private Object[] elementData;

    public static void main(String[] args) {
        MyArrarList<String> myList=new MyArrarList<>(10);
        System.out.println(myList);

        myList.add("aa");
        myList.add("bb");
        myList.add("cc");
        myList.add("dd");
        myList.add("ee");
        myList.add("ff");

        myList.add(2,"xrm");
        myList.set(2,"zs");

        String str=myList.get(2);
        System.out.println(str);

        System.out.println(myList.contains("eee"));

        System.out.println(myList.toArray());

        myList.remove(2);
        myList.remove("dd");
        System.out.println(myList);
        myList.clear();
    }

    public MyArrarList() {
        this(10);
    }

    public MyArrarList(int initialCapacity) {
        if(initialCapacity<0){
            try {
                throw new Exception("容器初始化大小不能为负数!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        elementData=new Object[initialCapacity];
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public void add(E obj) {
        ensureCapacity();

        elementData[size]=obj;
        size++;
    }

    @Override
    public void add(int index, E obj) {     //在索引位置插入一个元素,其余元素后移

        rangeCheck(index);

        ensureCapacity();

        System.arraycopy(elementData,index,elementData,index+1,size-index);
        elementData[index]=obj;
        size++;
    }

    //检查索引是否超出范围
    private void rangeCheck(int index){
        //索引是否合法的判断
        if(index<0 || index==size){
            try {
                throw new Exception("索引必须位于0到size-1之间");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //检查容量,判断是否需要扩充
    private void ensureCapacity(){
        if(size==elementData.length){   //需要数组扩容
            Object[] newArray=new Object[elementData.length*2+1];
            System.arraycopy(elementData,0,newArray,0,elementData.length);
            elementData=newArray;
        }
    }

    @Override
    public E set(int index, E obj) {    //在指定索引位置替换元素,并将旧的元素返回
        rangeCheck(index);

        Object oldValue=elementData[index];
        elementData[index]=obj;

        return (E)oldValue;
    }

    @Override
    public E get(int index){
        rangeCheck(index);
        return (E)elementData[index];
    }

    @Override
    public boolean contains(E obj) {
        for(int i=0;i<size;i++){
            if(elementData[i].equals(obj)){
                return true;
            }
        }
        return false;
    }

    @Override
    public Object[] toArray() {
        return elementData;
    }

    @Override
    public boolean remove(E obj) {  //删除指定的对象
        for(int i=0;i<size;i++){
            if(elementData[i].equals(obj)){
                remove(i);
                return true;
            }
        }
        return false;
    }

    @Override
    public void remove(int index){
        rangeCheck(index);
        //删除指定位置的对象
        int numRemove=size-(index+1);
        if(numRemove>0){
            System.arraycopy(elementData,index+1,elementData,index,numRemove);
        }

        size--;
        elementData[size]=null;
    }

    @Override
    public void clear() {
        for(int i=0;i<size;i++){
            elementData[i]=null;
        }
        size=0;
    }

    @Override
    public String toString() {
        StringBuilder sb=new StringBuilder();
        sb.append("[");
        for(int i=0;i<size;i++){
            sb.append(elementData[i]+"\t");
        }
        sb.append("]");
        return sb.toString();

    }
}

八、LinkedList类

/**
 * 自定义的MyList接口,模仿的是List接口
 * @param <E>
 */
public interface MyList<E> {

    //    List list=new ArrayList();
    int size();
    boolean isEmpty();
    void add(E obj);
    public void add(int index,E obj);
    public E set(int index,E obj);
    public E get(int index);

    public boolean contains(E obj);
    Object[] toArray();
    boolean remove(E obj);
    void remove(int index);
    void clear();
}

public class MyLinkedList<E> implements MyList<E> {

    private int size;
    private Node first;     //第一个节点
    private Node last;      //最后一个节点

    public static void main(String[] args) {
        MyLinkedList<String> mlList=new MyLinkedList<>();
        mlList.add("aa");
        mlList.add("bb");
        mlList.add("cc");
        mlList.add("dd");

        Node node=mlList.node(2);
        mlList.add("zhangsan");
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public void add(E obj) {
        Node n=new Node();
        //给容器增加一个obj,实际上增加一个节点(使用这个节点存储obj)
        if(first==null){
            //增加第一个节点
            n.setPrevious(null);
            n.setObj(obj);
            n.setNext(null);

            first=n;
            last=n;
        }else{
            n.setPrevious(last);
            n.setObj(obj);
            n.setNext(null);

            last.setNext(n);
            last=n;
        }
        size++;
    }

    private  Node node(int index){
        rangeCheck(index);
        Node tmp=null;
        if(first!=null){
            if(index<(size>>1)){
                tmp=first;
                for(int i=0;i<index;i++){
                    tmp=tmp.next;
                }
            }else{
                tmp=last;
                for(int i=size-1;i>index;i--){
                    tmp=tmp.previous;
                }
            }

        }
        return tmp;
    }

    @Override
    public void add(int index, E obj) {
        Node temp=node(index);
        Node newNode=new Node();
        newNode.obj=obj;

        if(temp!=null){
            Node up=temp.previous;

            up.next=newNode;
            newNode.previous=up;

            newNode.next=temp;
            temp.previous=newNode;
        }

        size++;

    }

    @Override
    public E set(int index, E obj) {
        rangeCheck(index);
        Node tmp=node(index);
        tmp.obj=obj;
        return (E) tmp.obj;
    }

    @Override
    public E get(int index) {
        return (E)node(index).obj;
    }

    @Override
    public boolean contains(E obj) {
        for(int i=0;i<size;i++){
            if(node(i).obj.equals(obj)){
                return true;
            }
        }

        return false;
    }

    @Override
    public Object[] toArray() {
        Object[] objs=new Object[size];
        for(int i=0;i<size;i++){
            objs[i]=node(i).obj;
        }

        return objs;
    }

    @Override
    public boolean remove(E obj) {

        for(int i=0;i<size;i++){
            if(node(i).obj.equals(obj)){
                remove(i);
                return true;
            }
        }
        return false;
    }

    @Override
    public void remove(int index) {

        rangeCheck(index);
        Node temp=node(index);

        if(temp!=null){
            Node up=temp.previous;
            Node next=temp.next;

            up.next=next;
            next.previous=up;

            size--;
        }
    }

    @Override
    public void clear() {

        for(int i=0;i<size;i++){
            remove(i);
        }

    }

    @Override
    public String toString() {
        StringBuilder sb=new StringBuilder();
        sb.append("[");
        for(int i=0;i<size;i++){
            sb.append(node(i).obj+"\t");
        }
        sb.append("]");
        return sb.toString();

    }

    //检查索引是否超出范围
    private void rangeCheck(int index){
        //索引是否合法的判断
        if(index<0 || index==size){
            try {
                throw new Exception("索引必须位于0到size-1之间");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

/**
 * 链表中的节点类
 */
class Node{
    Node previous;  //上一个节点
    Node next;      //下一个节点

    Object obj;     //真正存储的信息

    public Node() {
    }

    public Node(Node previous, Node next, Object obj) {
        this.previous = previous;
        this.next = next;
        this.obj = obj;
    }

    public Node getPrevious() {
        return previous;
    }

    public void setPrevious(Node previous) {
        this.previous = previous;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }
}

九、HashMap类

public interface MyMap<k,v> {

    /**
     * 自定义Map接口
     * @param key
     * @param value
     */
    public void put(k key,v value);
    public v get(k key);
    public boolean containsKey(k key);
    public boolean containsValue(v value);
    public void remove(k key);

    public int size();
    public boolean isEmpty();

}

/**
 * 手工实现的HashMap
 */
public class MyHashMap<k,v> implements MyMap<k,v> {

    public static final int INITIAL_CAPACITY=16;
    private int size;

    private Entry[] table;

    public MyHashMap(){
        table=new Entry[INITIAL_CAPACITY];
    }

    public static void main(String[] args) {

        MyHashMap<String,String> map=new MyHashMap<>();
        System.out.println(map);

        map.put("a","AAA");
        map.put("b","BBB");
        map.put("c","CCC");
        map.put("d","DDD");
        map.put("a","aaa");

        System.out.println(map.get("c"));
        System.out.println(map);
        map.remove("a");
        System.out.println(map);
    }

    private int hash(k key){
        int hashCode=key.hashCode();    //有可能为负数
        hashCode=hashCode<0?-hashCode:hashCode;     //确保正数

//        int index=hashCode/hashCode;    //最差的算法,hashCode退化成链表
//        int index=hashCode%table.length;    //早期的jdk就是这样的算法
        return hashCode&(table.length-1);    //位运算,效率较高
    }

    @Override
    public void put(k key, v value) {
        int index=hash(key);

        Entry entry=new Entry(key,value,index,null);

        if(table[index]==null){
            table[index]=entry;
        }else{
            Entry e=table[index];
            Entry last=e;

            while(e!=null){
                if(e.key.equals(key)){
                    e.value=value;      //如果Key相等,则直接覆盖value
                    return;
                }
                last=e;     //保存最后一个
                e=e.next;
            }
            //上面整个循环结束,没有return,则说明整个单向链表中没有Entry的key和传入的key相等
            //则添加到链表的最后
            last.next=entry;
        }
        size++;
    }

    @Override
    public v get(k key) {
        int index=hash(key);
        if(table[index]!=null){
            Entry e=table[index];
            while (e!=null){
                if(e.key.equals(key)){
                    return (v)e.value;     //如果key相等,则返回对应的value
                }
                e=e.next;
            }
        }
        return null;
    }

    @Override
    public boolean containsKey(k key) {
        return false;
    }

    @Override
    public boolean containsValue(v value) {
        return false;
    }

    @Override
    public void remove(k key) {

        int index=hash(key);
        if(table[index]!=null){
            Entry e=table[index];
            Entry pre=null; //上一个节点
            while(e!=null){
                if(e.key.equals(key)){
                    if(pre==null){
                        table[index]=e.next;    //它的下一个节点前移
                    }else{
                        pre.next=e.next;    //相当于把e移除
                        size--;
                    }
                }
                pre=e;
                e=e.next;
            }
        }

    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public String toString() {
        StringBuilder sb=new StringBuilder();
        sb.append("[");
        for(Entry e:table){
            while(e!=null) {
                sb.append("{"+e.key+":"+e.value+"}\t");
                e=e.next;
            }
        }
        sb.append("]");
        return sb.toString();
    }

}

class Entry<k,v>{

    k key;
    v value;
    int hash;
    Entry next;     //下一个节点

    public Entry() {
    }

    public Entry(k key, v value, int hash, Entry next) {
        this.key = key;
        this.value = value;
        this.hash = hash;
        this.next = next;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值