day10 可变参数、Stream流、斗地主游戏

目录

一、可变参数

1.1 可变参数的概述和注意事项

1.2 创建不可变集合

二、Stream流

2.1 Stream流的思想

2.2 Stream流的特点

2.3 Stream流的方法

2.3.1 Stream流的获取方法

2.3.2 Stream流的中间方法-filter

2.3.3 Stream流的其他中间方法

2.3.4 Stream流的终结方法

2.3.5 Stream流的收集方法

2.4 Stream流的练习 

三、斗地主游戏


一、可变参数

1.1 可变参数的概述和注意事项

可变参数介绍
java1.5之后
  - 可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
  - 方法的参数类型已经确定,个数不确定,我们可以使用可变参数

- 可变参数定义格式

  ```java
  修饰符 返回值类型 方法名(数据类型… 变量名) {  }
  ```

- 可变参数的注意事项

  - 可变参数的本质其实是一个数组
  - 如果一个方法有多个参数,包含可变参数,可变参数要放在最后
案例1

public class Demo01 {
    public static void main(String[] args) {
        System.out.println(sum(1,2,3,4,5));
    }
    public static int sum(int... a) {
        int sum = 0;
        for(int i : a) {
            sum += i;
        }
        return sum;
    }
}

案例2

public class Demo02 {
    public static void main(String[] args) {
        int index1 = getIndex(4, 1, 2, 3, 4, 5, 6);
        System.out.println(index1);
    }

    //如果有多个参数,可变参数放在最后
    public static int getIndex(int num, int... arr) {
        int index = -1;
        for (int i = 0; i < arr.length; i++) {
            if (num == arr[i]) {
                index = i;
                break;
            }
        }
        return index;
    }
}

1.2 创建不可变集合

可变参数的应用场景: 创建不可变集合
    将参数中的数据封装成一个集合, 该集合的特点是长度和内容都不能发生改变

创建不可变集合
- 在List、Set、Map接口中,都存在of方法,可以创建一个不可变的集合
  - 1.这个集合不能添加,不能删除,不能修改
    2.set 中不能添加重复的元素

  - 3.但是可以结合集合的带参构造,实现集合的批量添加
- 在Map接口中,还有一个ofEntries方法可以提高代码的阅读性
  - 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中

创建不可变集合的方法
    1. static<E> List<E> of(E...elements); 创建一个具有指定元素的List集合对象
    2. static<E> Set<E> of(E...elements); 创建一个具有指定元素的Set集合对象
    3. static<K,V> Map<K,V> of(E...elements); 创建一个具有指定元素的Map集合对象
        ofEntries(Map.entry(K1,V1),Map.entry(K2,V2)..); 提升代码的阅读性
public class Demo {
    public static void main(String[] args) {
        method1();
        method2();
        method3();
    }

    public static void method1() {

        //static <K , V>   Map<K,V>  of(E…elements) 创建一个具有指定元素的Map集合对象
        Map<String, String> map = Map.of("12", "23", "45", "67");
        System.out.println(map); //{12=23, 45=67}

        //在Map接口中,还有一个ofEntries方法可以提高代码的阅读性
        // 首先会把键值对封装成一个Entry对象,再把这个Entry对象添加到集合当中
        Map<String, String> map1 = Map.ofEntries(Map.entry("666", "777"), Map.entry("888", "999"));
        System.out.println(map1); //{888=999, 666=777}
    }

    // static <E>  List<E>  of(E…elements)  创建一个具有指定元素的List集合对象
    public static void method2() {
        List<String> list = List.of("111", "222", "333");
        System.out.println(list); //[111, 222, 333]

        //集合的批量添加
        //首先是通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数。
        //再创建一个ArrayList集合,并把这个不可变的集合中所有的数据,都添加到ArrayList中。
        ArrayList<String> list1 = new ArrayList<>(List.of("9999", "66666", "55555"));
        System.out.println(list1); //[9999, 66666, 55555]
    }

    //static <E>  Set<E>  of(E…elements)  创建一个具有指定元素的Set集合对象,不能添加重复元素
    public static void method3() {
        Set<String> set = Set.of("00", "11", "22", "33");
        System.out.println(set); //[22, 33, 00, 11]
    }
}

二、Stream流

2.1 Stream流的思想

流水线操作
   瓶子 -> 检查瓶子 -> 消毒 -> 罐装 -> 密封 -> 包装

Stream流理解为代码流水线
   获取方法(获取Stream流将数据放在流水线) -> 中间方法(过滤操作等) -> 终结方法(执行后就不能调用其他方法了)

2.2 Stream流的特点

Stream流的好处

- 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印
- Stream流把真正的函数式编程风格引入到Java中
- 代码简洁
注意:Stream流只能修改流里面的内容,不能直接修改数据源中的数据

2.3 Stream流的方法

Stream流的三类方法
- 获取Stream流
  - 创建一条流水线,并把数据放到流水线上准备进行操作
- 中间方法
  - 流水线上的操作
  - 一次操作完毕之后,还可以继续进行其他操作
- 终结方法
  - 一个Stream流只能有一个终结方法
  - 是流水线上的最后一个操作

2.3.1 Stream流的获取方法

第一类:获取方法, 操作的数据类型不同, 获取方法也不同
   1. 单列集合: 使用Collection中的默认方法stream()生成流
   2. 双列集合: 通过ketSet或者entrySet获取Set集合, 再获取Stream流 (间接获取)
   3. 数组: Arrays中的静态方法stream()生成流
   4. 同种数据类型的数个数据: 通过Stream.of(T...values)生成流, 参数是可变参数

public class Demo02 {
    public static void main(String[] args) {
        method1();
        method2();
        method3();
        method4();
    }

    //同一类型的多个数据
    //通过Stream接口的静态方法of(T... values)生成流
    public static void method4() {
        Stream.of(1,2,3,4,5,6,7,8).forEach(a-> System.out.println(a));//1 2 3 4 5 6 7 8 9
    }

    //数组
    //通过Arrays中的静态方法stream生成流
    public static void method3() {
        int[] arr = {1, 2, 3, 4};
        Arrays.stream(arr).forEach(num -> System.out.println(num));//1 2 3 4
    }

    //双列集合
    //Map体系集合
    //把Map转成Set集合,间接的生成流
    public static void method2() {
        HashMap<String, String> map = new HashMap<>();
        map.put("444", "666");
        map.put("111", "222");
        map.put("777", "888");
        map.keySet().stream().forEach(k-> System.out.println(k));//111 444 777
        map.entrySet().stream().forEach(kv-> System.out.println(kv));//111=222 444=666 777=888
    }

    //单列集合
    //Collection体系集合
    //使用默认方法stream()生成流, default Stream<E> stream()
    public static void method1() {
        ArrayList<String> list = new ArrayList<>();
        list.add("123");
        list.add("456");
        list.add("789");

        list.stream().forEach(s -> System.out.println(s));//123 456 789
    }
}

2.3.2 Stream流的中间方法-filter

Stream<T> filter(Predicate predicate)用于对流中的数据进行过滤
public class Demo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(List.of("张三", "李四", "王麻子", "二流子", "大混子"));

        //Stream<T> filter(Predicate predicate)用于对流中的数据进行过滤
        list.stream().filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
        //王麻子  二流子  大混子

        //ofEntries方法可以提高代码的阅读性
        HashMap<String, String> map = new HashMap<>(Map.ofEntries(Map.entry("张三", "789"), Map.entry("李四", "456")));

        map.keySet().stream().forEach(k -> System.out.println(k));//李四 张三
        map.entrySet().stream().forEach(kv-> System.out.println(kv));//李四=456 张三=789
    }
}

2.3.3 Stream流的其他中间方法

截取  Stream<T> limit(long maxSize)
跳过  Stream<T> skip(long n)
去重  Stream<T> distinct()
      自定义类,要去重的话,需重写equals nad hashcode方法
合并  static <T> Stream<T> concat(Stream a, Stream b)
//自定义类,要去重的话,需重写equals nad hashcode方法
public class Demo {
    public static void main(String[] args) {
        ArrayList<Student> list1 = new ArrayList<>();
        list1.add(new Student("张三", 23));
        list1.add(new Student("李四", 24));
        list1.add(new Student("王五", 25));
        list1.add(new Student("王五", 25));
        list1.add(new Student("二狗子", 23));

        ArrayList<Student> list2 = new ArrayList<>();
        list2.add(new Student("王麻子", 18));
        list2.add(new Student("二流子", 17));
        list2.add(new Student("大混子", 17));
        list2.add(new Student("大黑娃", 19));


        //Stream<T> limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据
        list1.stream().limit(2).forEach(s -> System.out.println(s));
        /*
       Student{name='张三', age=23}
        Student{name='李四', age=24}
         */


        //Stream<T> skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流
        list1.stream().skip(4).forEach(s -> System.out.println(s));
        /*
        Student{name='二狗子', age=23}
         */


        //在自定义类,要去重的话,需重写equals nad hashcode方法
        //Stream<T> distinct()去重,返回由该流的不同元素(根据Object.equals(Object) )组成的流
        list1.stream().distinct().forEach(s -> System.out.println(s));
        /*
        Student{name='张三', age=23}
        Student{name='李四', age=24}
        Student{name='王五', age=25}
        Student{name='二狗子', age=23}

         */

        //static <T> Stream<T> concat(Stream a, Stream b)合并a和b两个流为一个流
        Stream.concat(list1.stream(), list2.stream()).forEach(m -> System.out.println(m));
        /*
        Student{name='张三', age=23}
        Student{name='李四', age=24}
        Student{name='王五', age=25}
        Student{name='王五', age=25}
        Student{name='二狗子', age=23}
        Student{name='王麻子', age=18}
        Student{name='二流子', age=17}
        Student{name='大混子', age=17}
        Student{name='大黑娃', age=19}
         */
    }
}

class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Student{");
        sb.append("name='").append(name).append('\'');
        sb.append(", age=").append(age);
        sb.append('}');
        return sb.toString();
    }
}

2.3.4 Stream流的终结方法

终结方法
    void forEach(Consumer action)对此流的每个元素执行操作
    long count()返回此流中的元素数

 终结方法: 一个Stream流只能有一个终结方法, 该方法执行后就不能调用其他方法了
 

public class Demo {
    public static void main(String[] args) {
        Set<String>set = new TreeSet<>();
        set.add("123");
        set.add("456");
        set.add("456");
        set.add("789");
        set.add("000");

        //Set.of  不能添加重复元素,否则会报错
        Set<String>set1 = new TreeSet<>(Set.of("111","222","123"));

        //void forEach(Consumer action)对此流的每个元素执行操作
        set.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);000 123 456 789
            }
        });

        set1.stream().forEach((String s)-> System.out.println(s));//111 123 222

        //long count()返回此流中的元素数
        System.out.println(set.stream().count());//4
    }
}

2.3.5 Stream流的收集方法

思考
   流操作只能修改流中的数据, 不能直接修改数据源中的数据
   使用中间方法操作完毕后, 想将数据存储收集起来, 该怎么办呢?
收集方法
概念
    对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中

常用方法
    R collect(Collector collector)把结果收集到集合中

工具类Collectors提供了具体的收集方式
    public static <T> Collector toList()把元素收集到List集合中
    public static <T> Collector toSet()把元素收集到Set集合中
    public static  Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中

  

1.toSet  toList方法 

1. toSet  toList方法

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

        //添加方式1 List.of
        ArrayList<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));

        //添加方式2
        list.add(10);
        list.add(10);
        list.add(10);

        ArrayList<Integer> list1 = new ArrayList<>();
        //添加方式3
        for (int i = 1; i <= 10; i++) {
            list1.add(i);
        }

        //public static <T> Collector toList()把元素收集到List集合中
        //collect收集元素
        //(Collectors.toList()创建集合,存入数据
        List<Integer> collect = list.stream().collect(Collectors.toList());
        System.out.println(collect);
        //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]

        //public static <T> Collector toSet()把元素收集到Set集合中
        //Set集合中不能添加重复元素
        //Collectors.toSet()创建集合,存入数据
        Set<Integer> collect1 = list1.stream().collect(Collectors.toSet());
        System.out.println(collect1);
        //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    }
}

 2. toMap 方法

案例

需求
    创建ArrayList集合, 添加以下字符串数据, 键是姓名值是年龄
        "zhangsan,23"
        "lisi,24"
        "wangwu,25"
    筛选并保留大于等于24岁的人, 并将结果收集到Map集合中

public class Demo02 {
    public static void main(String[] args) {
        //创建ArrayList集合添加元素
        ArrayList<String> list = new ArrayList<>();
        list.add("张三,23");
        list.add("李四,24");
        list.add("王五,25");

        //将输入放入流中
        Map<String, Integer> map = list.stream().filter(
                s -> {
                    //参数s就是每一个字符串元素,根据逗号切合
                    String[] arr = s.split(",");
                    //获取返回数组中,第二个元素就是年龄,转为int类型
                    int age = Integer.parseInt(arr[1]);
                    //返回判断结果
                    return age >= 24;
                }
        ).collect(Collectors.toMap(
                    /*
                        List和Set是单列集合, 直接将数组整体存入即可, 所以toList和toSet都是是空参
                        Map集合是双列集合, 计算机不知道谁是键谁是值, 所以需要我们手动给出实现
                            Collectors.toMap(如果获取键 ,如果获取值); 将元素收集到Map集合中
                     */
                //参数1: s代表从流中依次获取的数据, 根据lambda表达式, 从s中切割出键即可
                (String s) -> {
                    String name = s.split(",")[0];
                    return name;
                },
                //参数2: s代表从流中依次获取的数据,  根据lambda表达式, 从s中切割出值即可
                (String s) -> {
                    int age = Integer.parseInt(s.split(",")[1]);
                    return age;
                }
        ));

        //打印map集合内容
        System.out.println(map); //{李四=24, 王五=25}
    }
}

2.4 Stream流的练习 

现在有两个ArrayList集合, 分别存储6名男演员和6名女演员, 完成如下操作:
    1. 男演员只要名字为三个字的前两人 -> filter name的长度==3 limit(2);
    2. 女演员只要姓杨的, 并且不要第一个 -> filter startsWith("杨"); skip(1)
    3. 将过滤后的男女演员合并到一起 -> concat(流1,流2);
    4. 设计Actor类, 提供一个成员变量name, 带参构造方法, 以及对应的getXxx,setXxx方法
    5. 将合并后流中的元素(字符串name), 作为构造参数创建演员对象并遍历(Actor对象只有一个属性name)
public class Demo {
    public static void main(String[] args) {
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("张国立");
        list1.add("张晋");
        list1.add("刘烨");
        list1.add("郑伊健");
        list1.add("徐峥");
        list1.add("王宝强");

        ArrayList<String> list2 = new ArrayList<>();
        list2.add("郑爽");
        list2.add("杨紫");
        list2.add("关晓彤");
        list2.add("张天爱");
        list2.add("杨幂");
        list2.add("赵丽颖");

        //1. 男演员只要名字为三个字的前两人 -> filter name的长度==3 limit(2);
        Stream<String> stream1 = list1.stream().filter(s -> s.length() == 3).limit(2);

        //2. 女演员只要姓杨的, 并且不要第一个 -> filter startsWith("杨"); skip(1)
        Stream<String> stream2 = list2.stream().filter(s -> s.startsWith("杨")).skip(1);

        //3. 将过滤后的男女演员合并到一起 -> concat(流1,流2);
        Stream<String> stream3 = Stream.concat(stream1, stream2);

        stream3.forEach(
                name -> {
                    //5. 将合并后流中的元素(字符串name), 作为构造参数创建演员对象并遍历(Actor对象只有一个属性name)
                    Actor ac = new Actor(name);
                    System.out.println(ac);
                    /*
                    Actor{name='张国立'}
                    Actor{name='郑伊健'}
                    Actor{name='杨幂'}
                     */
                }
        );
    }
}

//4. 设计Actor类, 提供一个成员变量name, 带参构造方法, 以及对应的getXxx,setXxx方法
class Actor {
    private String name;

    public Actor() {
    }

    public Actor(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

        Actor actor = (Actor) o;

        return name != null ? name.equals(actor.name) : actor.name == null;

    }

    @Override
    public int hashCode() {
        return name != null ? name.hashCode() : 0;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Actor{");
        sb.append("name='").append(name).append('\'');
        sb.append('}');
        return sb.toString();
    }
}

三、斗地主游戏

步骤:1.洗牌 2.发牌 3.看牌

洗牌是用Collections工具类中的shuffle方法,将集合中的元素打乱

发牌就是将每个玩家的牌和底牌找出来(利用索引)

看牌是打印玩家的牌和底牌

第一种方法: 发出来的牌是无序排列的

public class Demo02 {
    public static void main(String[] args) {
        //创建ArrayList集合
        ArrayList<String> list = new ArrayList<>();
        
        //创建放花色和数字的数组,
        String[] color = {"♠", "♥", "♣", "♦"};
        String[] number = {"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "6", "5", "4", "3"};

        //将大小王添加到集合的开头
        list.add("大王");
        list.add("小王");
        
        //外层循环遍历数字,内层循环遍历花色,将曙色和数字添加到list集合中
        for (String numbers : number) {
            for (String colors : color) {
                list.add(colors + numbers);
            }
        }


        //该方法将集合中的元素打乱顺序
        Collections.shuffle(list);
        
        //创建存放玩家和底牌的TreeSet集合
        TreeSet<String>play1 = new TreeSet<>();
        TreeSet<String>play2 = new TreeSet<>();
        TreeSet<String>play3 = new TreeSet<>();
        TreeSet<String>dipai = new TreeSet<>();

        //遍历装有花色和数字的list集合,分别将花色和数字添加到每个玩家和底牌的集合中
        for (int i = 0; i < list.size(); i++) {
            //最后三种牌放到底牌的集合中
            if(i>=50){
                dipai.add(list.get(i));
            }
           else if(i<50) {
                if (i % 3 == 0) {
                    play1.add(list.get(i));
                } else if (i % 3 == 1) {
                    play2.add(list.get(i));
                } else if (i % 3 == 2) {
                    play3.add(list.get(i));
                }
            }
        }
        //打印每个玩家和底牌的集合元素
        System.out.println(play1);
        System.out.println(play2);
        System.out.println(play3);
        System.out.println(dipai);
    }
}

第二种方法: 发出来的牌可有序排列

public class Demo {
    public static void main(String[] args) {
        //1.创建HashMap集合,里面存储索引值、牌的花色和数字
        HashMap<Integer, String> map = new HashMap<>();

        //2.创建ArrayList集合,里面存储索引值,类型为Integer
        ArrayList<Integer> list = new ArrayList<>();
        //3.创建两个数组分别存储牌的花色和数字
        String[] color = {"♠", "♥", "♣", "♦"};
        String[] number = {"2", "A", "K", "Q", "10", "J", "9", "8", "7", "6", "5", "4", "3"};

        //4.定义索引从2开始,存储牌的花色和数字
        int index = 2;
        for (String numbers : number) {
            for (String colors : color) {
                map.put(index, numbers + colors);
                list.add(index);
                index++;
            }
        }

        /*
        //如果color在外层循环,number在内层循环,,则打印的时候不会按照牌的数字进行升序排列
        //打印出来的牌会是无序的
            for (String colors : color) {
                for (String numbers : number) {
                map.put(index, numbers + colors);
                list.add(index);
                index++;
            }
        }

         */
        //将0索引和大王存在map集合中,将0和1索引添加到存储索引的list集合中
        //这样每次发牌大王小王都会在前面
        map.put(0, "大王");
        list.add(0);
        map.put(1, "小王");
        list.add(1);

        //利用Collections工具类中的shuffle方法,打乱list集合中的索引顺序
        Collections.shuffle(list);

        //创建四个存储玩家和底牌索引的TreeSet集合,类型为Integer
        //因为TreeSet集合底层是自动升序排列的,所以使用
        TreeSet<Integer> play01 = new TreeSet<>();
        TreeSet<Integer> play02 = new TreeSet<>();
        TreeSet<Integer> play03 = new TreeSet<>();
        TreeSet<Integer> dipai = new TreeSet<>();

        //遍历list索引集合,利用规律将索引添加到4个集合中
        for (int i = 0; i < list.size(); i++) {
            if (i <= 50) {
                //玩家1的发牌规则
                if (i % 3 == 0) {
                    //如果索引符合玩家1的发牌规则,则将这些索引添加到玩家1的集合中
                    play01.add(list.get(i));
                    //玩家2的发牌规则
                } else if (i % 3 == 1) {
                    //如果索引符合玩家2的发牌规则,则将这些索引添加到玩家2的集合中
                    play02.add(list.get(i));
                    //玩家3的发牌规则
                } else if (i % 3 == 2) {
                    //如果索引符合玩家3的发牌规则,则将这些索引添加到玩家3的集合中
                    play03.add(list.get(i));
                }
                //底牌的发牌规则
            } else {
                //剩余三张牌,将剩下的3个索引添加到底牌的集合中
                dipai.add(list.get(i));
            }
        }
        //将会打印每个玩家和底牌集合中的索引
        method("玩家1", play01, map);
        method("玩家2", play02, map);
        method("玩家3", play03, map);
        method("底牌", dipai, map);
    }

    //创建一个方法,将玩家姓名,玩家索引集合,存储所有花色和数字的map集合作为参数列表
    public static void method(String s, TreeSet<Integer> name, HashMap<Integer, String> map) {
        //遍历map集合
        Set<Map.Entry<Integer, String>> entries = map.entrySet();
        //打印玩家姓名
        System.out.print(s + ":");
        for (Map.Entry<Integer, String> entry : entries) {
            //如果玩家的索引集合中包含map集合中的键(索引值)集合中,则将这个值(花色和数字)打印出来
            if (name.contains(entry.getKey())) {
                System.out.print(entry.getValue() + " ");
            }
        }
        System.out.println();
    }
}

微信扫码订阅
UP更新不错过~
关注
  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页
评论

打赏作者

Java老湿机

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值