• 201771010125王瑜《面向对象程序设计(Java)》第十周学习总结


    实验十  泛型程序设计技术

    一 理论部分

    1.泛型:参数化类型,在定义类、接口、方法时通过类型参数指示将要处理的对象类型

    2.泛型程序设计意味着编写的代码可以被许多不同类型的对象所重用

    3.定义简单泛型类:

      (1)一个泛型类就是具有一个或多个类型变量的类,即创建用类型作为参数的类

      (2)以Pair类为例:public class Pair<T>

                 {

                                                 ......

                  }

        Pair类引入了一个类型变量T,用尖括号(<>)括起来,并放在类名的后面

      (3)泛型类可以有多个类型变量。例如,可以定义Pair类,其中第一个域和第二个域使用不同的类型:public class Pair<T,U> { ... }

      (4)类定义中的类型变量指定方法的返回类型以及域和局部变量的类型

      (5)实例化泛型对象时,一定要在类名后面指定类型参数的值一共要有两次书写,例如:TestGeneric<String,String> t=new TestGeneric<String,String>();

    4.泛型方法:

      (1)定义泛型方法时注意,类型变量放在修饰符(public static)的后面,返回类型的前面

      (2)泛型方法可以定义在普通类中,也可以定义在泛型类中

      (3)当调用一个泛型方法时,在方法名前的尖括号中放入具体的类型

    5.泛型接口的定义与实现:

      (1)定义:public interface IPool<T>

                               {

             T get();

                int add(T t);

                               }

      (2)实现:public class GenericPool<T> implements IPool<T> { ... }

             public class GenericPool implements IPool<Account> { ... }

    6.类型变量的限定:

      (1)定义泛型变量的上界(用extends)

        <T extends BoundingType>表示T是绑定类型的子类型。T和绑定类型可以是类,也可以是接口

        一个类型变量或通配符可以有多个限定,例如:T extends Comparable & Serializable(限定类型用“&”分隔)

      (2)定义泛型变量的下界(用super)     例如:<? super T>

    7.泛型类的约束与局限:

      (1)不能用基本类型实例化类型参数

      (2)运行时类型查询只适用于原始类型

      (3)不能抛出也不能捕获泛型类实例

      (4)参数化类型的数组不合法

      (5)不能实例化类型变量

      (6)泛型类的静态上下文中类型变量无效

      (7)注意擦除后的冲突

    8.泛型类型的继承规则:Java中的数组是协变的,但泛型类不是协变的

    9.通配符类型(?,任何类型;T,某一种类型)

      (1)单独的?,用于表示任何类型

      (2)?extends type,表示带有上界

      (3)? super type,表示带有下界

    10.(1)通配符的类型限定: Pair<? extends Employee>

                 Pair<? super Manager>

     (2)无限定通配符:Pair<?>(Pair<?>与Pair的不同在于:可以用任意Object对象调用原始的Pair类的setObject方法)

    二 实验部分

    1、实验目的与要求:

     

    (1) 理解泛型概念;

     

    (2) 掌握泛型类的定义与使用;

     

    (3) 掌握泛型方法的声明与使用;

     

    (4) 掌握泛型接口的定义与实现;

     

    (5)了解泛型程序设计,理解其用途。

    2、实验内容和步骤

    实验1 导入第8章示例程序,测试程序并进行代码注释。

    测试程序1:

    编辑、调试、运行教材311312 代码,结合程序运行结果理解程序;

    在泛型类定义及使用代码处添加注释;

    掌握泛型类的定义及使用。

    package pair1;
    
    /**
     * @version 1.00 2004-05-10
     * @author Cay Horstmann
     */
    public class Pair<T> //引入类型变量T
    {
       private T first;
       private T second;
    
       public Pair() { first = null; second = null; }
       public Pair(T first, T second) { this.first = first;  this.second = second; }
    
       public T getFirst() { return first; }
       public T getSecond() { return second; }
    
       public void setFirst(T newValue) { first = newValue; }
       public void setSecond(T newValue) { second = newValue; }
    }
    复制代码
    复制代码
    package pair1;
    
    /**
     * @version 1.01 2012-01-26
     * @author Cay Horstmann
     */
    public class PairTest1
    {
       public static void main(String[] args)
       {
          String[] words = { "Mary", "had", "a", "little", "lamb" };
          Pair<String> mm = ArrayAlg.minmax(words);
          System.out.println("min = " + mm.getFirst());
          System.out.println("max = " + mm.getSecond());
       }
    }
    
    class ArrayAlg//泛型方法
    {
       /**
        * Gets the minimum and maximum of an array of strings.
        * @param a an array of strings
        * @return a pair with the min and max value, or null if a is null or empty
        */
       public static Pair<String> minmax(String[] a)
       {
          if (a == null || a.length == 0) return null;
          String min = a[0];
          String max = a[0];
          for (int i = 1; i < a.length; i++)
          {
             if (min.compareTo(a[i]) > 0) min = a[i];
             if (max.compareTo(a[i]) < 0) max = a[i];
          }
          return new Pair<>(min, max);
       }
    }
    复制代码

    测试程序2

    编辑、调试运行教材315 PairTest2,结合程序运行结果理解程序;

    在泛型程序设计代码处添加相关注释;

    掌握泛型方法、泛型变量限定的定义及用途。

    package pair2;

    import java.time.*;

    /**
    * @version 1.02 2015-06-21
    * @author Cay Horstmann
    */
    public class PairTest2
    {
       public static void main(String[] args)
       {
          LocalDate[] birthdays =
             {
                LocalDate.of(1906, 12, 9), // G. Hopper
                LocalDate.of(1815, 12, 10), // A. Lovelace
                LocalDate.of(1903, 12, 3), // J. von Neumann
                LocalDate.of(1910, 6, 22), // K. Zuse
             };
          Pair<LocalDate> mm = ArrayAlg.minmax(birthdays);
          System.out.println("min = " + mm.getFirst());
          System.out.println("max = " + mm.getSecond());
       }
    }

    class ArrayAlg
    {
       /**
          Gets the minimum and maximum of an array of objects of type T.
          @param a an array of objects of type T
          @return a pair with the min and max value, or null if a is
          null or empty
       */
       public static <T extends Comparable> Pair<T> minmax(T[] a) //泛型方法,有上界约束
       {
          if (a == null || a.length == 0) return null;
          T min = a[0];
          T max = a[0];
          for (int i = 1; i < a.length; i++)
          {
             if (min.compareTo(a[i]) > 0) min = a[i];
             if (max.compareTo(a[i]) < 0) max = a[i];
          }
          return new Pair<>(min, max);
       }
    }

    测试程序3

    用调试运行教材335 PairTest3,结合程序运行结果理解程序;

    了解通配符类型的定义及用途。

    package pair3;

    /**
    * @version 1.01 2012-01-26
    * @author Cay Horstmann
    */
    public class PairTest3
    {
       public static void main(String[] args)
       {
          Manager ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15);
          Manager cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15);
          Pair<Manager> buddies = new Pair<>(ceo, cfo);  //类型变量   
          printBuddies(buddies);

          ceo.setBonus(1000000);
          cfo.setBonus(500000);
          Manager[] managers = { ceo, cfo };

          Pair<Employee> result = new Pair<>();//也可以用Manager
          minmaxBonus(managers, result);
          System.out.println("first: " + result.getFirst().getName()
             + ", second: " + result.getSecond().getName());
          maxminBonus(managers, result);
          System.out.println("first: " + result.getFirst().getName()
             + ", second: " + result.getSecond().getName());
       }

       public static void printBuddies(Pair<? extends Employee> p)//上界约束
       {
          Employee first = p.getFirst();
          Employee second = p.getSecond();
          System.out.println(first.getName() + " and " + second.getName() + " are buddies.");
       }

       public static void minmaxBonus(Manager[] a, Pair<? super Manager> result)//采用通配符来定义第二个类型变量result
       {
          if (a.length == 0) return;
          Manager min = a[0];
          Manager max = a[0];
          for (int i = 1; i < a.length; i++)
          {
             if (min.getBonus() > a[i].getBonus()) min = a[i];
             if (max.getBonus() < a[i].getBonus()) max = a[i];
          }
          result.setFirst(min);
          result.setSecond(max);
       }

       public static void maxminBonus(Manager[] a, Pair<? super Manager> result)
       {
          minmaxBonus(a, result);
          PairAlg.swapHelper(result); // OK--swapHelper captures wildcard type
       }
       // Can't write public static <T super manager> ...
    }

    class PairAlg
    {
       public static boolean hasNulls(Pair<?> p)//?类型变量的通配符,单独的?表示任何一种类型,T表示一种未知类型
       //将hasNulls转换成泛型方法
       //测试一个pair是否包含一个null引用
       {
          return p.getFirst() == null || p.getSecond() == null;
       }
    //编写一个交换成对元素的方法
       public static void swap(Pair<?> p) { swapHelper(p); }

       public static <T> void swapHelper(Pair<T> p)//泛型方法
       {
          T t = p.getFirst();//保存第一个元素
          p.setFirst(p.getSecond());
          p.setSecond(t);
       }
    }

    实验2编程练习:

    编程练习1:实验九编程题总结

    实验九编程练习1总结(从程序总体结构说明、模块说明,目前程序设计存在的困难与问题三个方面阐述)。

    总体结构说明:

    主类main,子类card

    模块说明:

    main

    复制代码
    package shen;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Scanner;
    
    public class Main {
        /**
         * 1.文件读取模块 利用ArrayList构造studentlist存放文件内容2. 创建文件字符流,分类读取文件内容 3.try/catch语句捕获异常
         */
        private static ArrayList<Student> studentlist;
    
        public static void main(String[] args) {
            studentlist = new ArrayList<>();
            Scanner scanner = new Scanner(System.in);
            File file = new File("C:\Users\ASUS\Desktop\新建文件夹\身份证号.txt");
            try {
                FileInputStream fis = new FileInputStream(file);
                BufferedReader in = new BufferedReader(new InputStreamReader(fis));
                String temp = null;
                while ((temp = in.readLine()) != null) {
    
                    Scanner linescanner = new Scanner(temp);
    
                    linescanner.useDelimiter(" ");
                    String name = linescanner.next();
                    String number = linescanner.next();
                    String sex = linescanner.next();
                    String age = linescanner.next();
                    String province = linescanner.nextLine();
                    Student student = new Student();
                    student.setName(name);
                    student.setnumber(number);
                    student.setsex(sex);
                    int a = Integer.parseInt(age);
                    student.setage(a);
                    student.setprovince(province);
                    studentlist.add(student);
    
                }
            } catch (FileNotFoundException e) {
                System.out.println("学生信息文件找不到");
                e.printStackTrace();
                // 加入的捕获异常代码
            } catch (IOException e) {
                System.out.println("学生信息文件读取错误");
                e.printStackTrace();
                // 加入的捕获异常代码
            }
            /*
             * 1.根据实验要求,选择具体操作的模块 2.利用switch语句选择具体的操作
             */
            boolean isTrue = true;
            while (isTrue) {
                System.out.println("选择你的操作,输入正确格式的选项");
                System.out.println("A.字典排序");
                System.out.println("B.输出年龄最大和年龄最小的人");
                System.out.println("C.寻找老乡");
                System.out.println("D.寻找年龄相近的人");
                System.out.println("F.退出");
                String m = scanner.next();
                switch (m) {
                case "A":
                    Collections.sort(studentlist);
                    System.out.println(studentlist.toString());
                    break;
                case "B":
                    int max = 0, min = 100;
                    int j, k1 = 0, k2 = 0;
                    for (int i = 1; i < studentlist.size(); i++) {
                        j = studentlist.get(i).getage();
                        if (j > max) {
                            max = j;
                            k1 = i;
                        }
                        if (j < min) {
                            min = j;
                            k2 = i;
                        }
    
                    }
                    System.out.println("年龄最大:" + studentlist.get(k1));
                    System.out.println("年龄最小:" + studentlist.get(k2));
                    break;
                case "C":
                    System.out.println("老家?");
                    String find = scanner.next();
                    String place = find.substring(0, 3);
                    for (int i = 0; i < studentlist.size(); i++) {
                        if (studentlist.get(i).getprovince().substring(1, 4).equals(place))
                            System.out.println("老乡" + studentlist.get(i));
                    }
                    break;
    
                case "D":
                    System.out.println("年龄:");
                    int yourage = scanner.nextInt();
                    int near = agenear(yourage);
                    int value = yourage - studentlist.get(near).getage();
                    System.out.println("" + studentlist.get(near));
                    break;
                case "F":
                    isTrue = false;
                    System.out.println("退出程序!");
                    break;
                default:
                    System.out.println("输入有误");
    
                }
            }
        }
    
        /*
         * 对年龄数据进行相应的处理
         */
        public static int agenear(int age) {
            int j = 0, min = 53, value = 0, k = 0;
            for (int i = 0; i < studentlist.size(); i++) {
                value = studentlist.get(i).getage() - age;
                if (value < 0)
                    value = -value;
                if (value < min) {
                    min = value;
                    k = i;
                }
            }
            return k;
        }
    
    }
    
    Main
    复制代码

    card:

    复制代码
    package shen;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.Scanner;
    
    public class Main {
        /**
         * 1.文件读取模块 利用ArrayList构造studentlist存放文件内容2. 创建文件字符流,分类读取文件内容 3.try/catch语句捕获异常
         */
        private static ArrayList<Student> studentlist;
    
        public static void main(String[] args) {
            studentlist = new ArrayList<>();
            Scanner scanner = new Scanner(System.in);
            File file = new File("C:\Users\ASUS\Desktop\新建文件夹\身份证号.txt");
            try {
                FileInputStream fis = new FileInputStream(file);
                BufferedReader in = new BufferedReader(new InputStreamReader(fis));
                String temp = null;
                while ((temp = in.readLine()) != null) {
    
                    Scanner linescanner = new Scanner(temp);
    
                    linescanner.useDelimiter(" ");
                    String name = linescanner.next();
                    String number = linescanner.next();
                    String sex = linescanner.next();
                    String age = linescanner.next();
                    String province = linescanner.nextLine();
                    Student student = new Student();
                    student.setName(name);
                    student.setnumber(number);
                    student.setsex(sex);
                    int a = Integer.parseInt(age);
                    student.setage(a);
                    student.setprovince(province);
                    studentlist.add(student);
    
                }
            } catch (FileNotFoundException e) {
                System.out.println("学生信息文件找不到");
                e.printStackTrace();
                // 加入的捕获异常代码
            } catch (IOException e) {
                System.out.println("学生信息文件读取错误");
                e.printStackTrace();
                // 加入的捕获异常代码
            }
            /*
             * 1.根据实验要求,选择具体操作的模块 2.利用switch语句选择具体的操作
             */
            boolean isTrue = true;
            while (isTrue) {
                System.out.println("选择你的操作,输入正确格式的选项");
                System.out.println("A.字典排序");
                System.out.println("B.输出年龄最大和年龄最小的人");
                System.out.println("C.寻找老乡");
                System.out.println("D.寻找年龄相近的人");
                System.out.println("F.退出");
                String m = scanner.next();
                switch (m) {
                case "A":
                    Collections.sort(studentlist);
                    System.out.println(studentlist.toString());
                    break;
                case "B":
                    int max = 0, min = 100;
                    int j, k1 = 0, k2 = 0;
                    for (int i = 1; i < studentlist.size(); i++) {
                        j = studentlist.get(i).getage();
                        if (j > max) {
                            max = j;
                            k1 = i;
                        }
                        if (j < min) {
                            min = j;
                            k2 = i;
                        }
    
                    }
                    System.out.println("年龄最大:" + studentlist.get(k1));
                    System.out.println("年龄最小:" + studentlist.get(k2));
                    break;
                case "C":
                    System.out.println("老家?");
                    String find = scanner.next();
                    String place = find.substring(0, 3);
                    for (int i = 0; i < studentlist.size(); i++) {
                        if (studentlist.get(i).getprovince().substring(1, 4).equals(place))
                            System.out.println("老乡" + studentlist.get(i));
                    }
                    break;
    
                case "D":
                    System.out.println("年龄:");
                    int yourage = scanner.nextInt();
                    int near = agenear(yourage);
                    int value = yourage - studentlist.get(near).getage();
                    System.out.println("" + studentlist.get(near));
                    break;
                case "F":
                    isTrue = false;
                    System.out.println("退出程序!");
                    break;
                default:
                    System.out.println("输入有误");
    
                }
            }
        }
    
        /*
         * 对年龄数据进行相应的处理
         */
        public static int agenear(int age) {
            int j = 0, min = 53, value = 0, k = 0;
            for (int i = 0; i < studentlist.size(); i++) {
                value = studentlist.get(i).getage() - age;
                if (value < 0)
                    value = -value;
                if (value < min) {
                    min = value;
                    k = i;
                }
            }
            return k;
        }
    
    }
    
    Main
    复制代码

    问题:目前程序设计存在的困难与问题:读文件时,文件路径不正确,无法找到文件。

    实验九编程练习2总结(从程序总体结构说明、模块说明,目前程序设计存在的困难与问题三个方面阐述)。

    总体结构说明:

    主类test和子类yunsuan

    模块说明:

    复制代码
    package demo;
    
    import java.io.PrintWriter;
    import java.util.Scanner;
    
    public class Test {
        public static void main(String[] args) {
            //文件输出模块,调用构造函数
    
            @SuppressWarnings("resource")
            Scanner in = new Scanner(System.in);
            Demo demo=new Demo();
            //创建文件字符流,将output中的内容设为空(null)
            PrintWriter output = null;
            try {
                output = new PrintWriter("test.txt");//将out结果输出到test.txt中
            } catch (Exception e) {
                e.printStackTrace();
            }
            int sum = 0; //定义一个sum,计算成绩
            
            //四则运算生成模块,生成10道题目
            for (int i = 0; i < 10; i++) {
    
                int a = (int) Math.round(Math.random() * 100);
                int b = (int) Math.round(Math.random() * 100);
                int c = (int) Math.round(Math.random() * 3);
                switch (c) {
                case 0:
                    System.out.println(a + "+" + b + "=");
                    int d0 = in.nextInt();
                    output.println(a + "+" + b + "=" + d0);
                    if (d0 == demo.demo1(a, b)) {
                        sum += 10;
                        System.out.println("恭喜答案正确");
                    } else {
                        System.out.println("抱歉,答案错误");
                    }
                    break;
                case 1:
                    while (a < b) {
                        int x = a;
                        a = b;
                        b = x;
                    }
                    System.out.println(a + "-" + b + "=");
                    int d1 = in.nextInt();
                    output.println(a + "-" + b + "=" + d1);
                    if (d1 == demo.demo2(a, b)) {
                        sum += 10;
                        System.out.println("恭喜答案正确");
                    } else {
                        System.out.println("抱歉,答案错误");
                    }
                    break;
                case 2:
                    System.out.println(a + "*" + b + "=");
                    int d2 = in.nextInt();
                    output.println(a + "*" + b + "=" + d2);
                    if (d2 == demo.demo3(a, b)) {
                        sum += 10;
                        System.out.println("恭喜答案正确");
                    } else {
                        System.out.println("抱歉,答案错误");
                    }
                    break;
                case 3:
                    while (b == 0 || a % b != 0) {
                        a = (int) Math.round(Math.random() * 100);
                        b = (int) Math.round(Math.random() * 100);
                    }
                    System.out.println(a + "/" + b + "=");
                    int d3 = in.nextInt();
                    output.println(a + "/" + b + "=" + d3);
                    if (d3 == demo.demo4(a, b)) {
                        sum += 10;
                        System.out.println("恭喜答案正确");
                    } else {
                        System.out.println("抱歉,答案错误");
                    }
                    break;
    
                }
    
            }
    
            System.out.println("你的得分为" + sum);
            output.println("你的得分为" + sum); //将循环结果输出到test.txt中
            output.close();
        }
    }
    
    Test
    复制代码
    复制代码
    package demo;
    
    public class yunsuan {
           private int a;
           private int b;
            public int add(int a,int b)
            {
                return a+b;
            }
            public int reduce(int a,int b)
            {
                return a-b;
            }
            public int multiplication(int a,int b)
            {
                return a*b;
            }
            public int division(int a,int b)
            {
                if(b!=0) 
                    return a/b;
                else 
                    return 0;            
            }
    
    }
    
    yunsuan
    复制代码

    问题:对printwrite不太了解。

    编程练习2:采用泛型程序设计技术改进实验九编程练习2,使之可处理实数四则运算,其他要求不变。

    package demo;
    
    import java.io.PrintWriter;
    import java.util.Scanner;
    
    public class Test {
        public static void main(String[] args) {
    
            @SuppressWarnings("resource")
            Scanner in = new Scanner(System.in);
            Demo demo=new Demo();
    
            PrintWriter output = null;
            try {
                output = new PrintWriter("test.txt");
            } catch (Exception e) {
                e.printStackTrace();
            }
            int sum = 0;
    
            for (int i = 0; i < 10; i++) {
    
                int a = (int) Math.round(Math.random() * 100);
                int b = (int) Math.round(Math.random() * 100);
                int c = (int) Math.round(Math.random() * 3);
                switch (c) {
                case 0:
                    System.out.println(a + "+" + b + "=");
                    int d0 = in.nextInt();
                    output.println(a + "+" + b + "=" + d0);
                    if (d0 == demo.demo1(a, b)) {
                        sum += 10;
                        System.out.println("恭喜答案正确");
                    } else {
                        System.out.println("抱歉,答案错误");
                    }
                    break;
                case 1:
                    while (a < b) {
                        int x = a;
                        a = b;
                        b = x;
                    }
                    System.out.println(a + "-" + b + "=");
                    int d1 = in.nextInt();
                    output.println(a + "-" + b + "=" + d1);
                    if (d1 == demo.demo2(a, b)) {
                        sum += 10;
                        System.out.println("恭喜答案正确");
                    } else {
                        System.out.println("抱歉,答案错误");
                    }
                    break;
                case 2:
                    System.out.println(a + "*" + b + "=");
                    int d2 = in.nextInt();
                    output.println(a + "*" + b + "=" + d2);
                    if (d2 == demo.demo3(a, b)) {
                        sum += 10;
                        System.out.println("恭喜答案正确");
                    } else {
                        System.out.println("抱歉,答案错误");
                    }
                    break;
                case 3:
                    while (b == 0 || a % b != 0) {
                        a = (int) Math.round(Math.random() * 100);
                        b = (int) Math.round(Math.random() * 100);
                    }
                    System.out.println(a + "/" + b + "=");
                    int d3 = in.nextInt();
                    output.println(a + "/" + b + "=" + d3);
                    if (d3 == demo.demo4(a, b)) {
                        sum += 10;
                        System.out.println("恭喜答案正确");
                    } else {
                        System.out.println("抱歉,答案错误");
                    }
                    break;
    
                }
    
            }
    
            System.out.println("你的得分为" + sum);
            output.println("你的得分为" + sum);
            output.close();
        }
    }
    
    Test
    复制代码
    复制代码
    package demo;
    
    public class yunsuan {
           private int a;
           private int b;
            public int add(int a,int b)
            {
                return a+b;
            }
            public int reduce(int a,int b)
            {
                return a-b;
            }
            public int multiplication(int a,int b)
            {
                return a*b;
            }
            public int division(int a,int b)
            {
                if(b!=0) 
                    return a/b;
                else 
                    return 0;            
            }
    
    }
    
    yunsuan

    结果:

     三实验总结

    通过本周的学习,我对java的面向对象程序设计有了更深的理解,对泛型、泛型类的定义与使用、泛型方法的实现都有了基础的操作方法,也学习到了通配符的基本使用规则,对java整体上也有了更深层次的认识与掌握,继续加油。

  • 相关阅读:
    PHP xml_parser_create_ns() 函数
    PHP xml_parse_into_struct() 函数
    PHP xml_parse() 函数
    PHP xml_get_error_code() 函数
    PHP xml_get_current_line_number() 函数
    文本竖排组合 | text-combine-upright (Writing Modes)
    文本溢出 | text-overflow (Basic User Interface)
    文本渲染 | text-rendering (Scalable Vector Graphics)
    文本最终对齐 | text-align-last (Text)
    文本属性-风格 | text-emphasis-style (Text Decoration)
  • 原文地址:https://www.cnblogs.com/wy-201771010125/p/9903224.html
Copyright © 2020-2023  润新知