.<_java入门基础知识笔记">
当前位置:   article > 正文

Java基础知识点总结笔记_java入门基础知识笔记

java入门基础知识笔记

Java基础

Java常用内存区域

  1. 栈内存空间:存储引用堆内存空间的地址
  2. 堆内存空间:保存每个对象的具体属性内容
  3. 全局数据区:保存static类型的属性
  4. 全局代码区:保存所有的方法定义

创建对象的过程

创建对象的过程:

  1. 遇到对象名时,进行类的加载(只加载一次)
  2. 创建对象,为这个对象在堆中开辟空间
  3. 为对象进行属性的初始化操作

JavaBean

JavaBean是Java写成的可重用组件

符合以下标准的Java类:称之为JavaBean:

  1. 类是公共的
  2. 有一个无参的公共的构造器
  3. 有属性,且有对应的get、set方法

修饰符

权限修饰符

修饰符同一个类中同一个包中子类无关类不同包的子类不同包的无关类
private
默认
protected
public

状态修饰符

static关键字
  1. 声明属性:使之独立于对象,成为全局属性(亦称静态属性)
  2. 声明方法:使之成为"类方法",可直接通过类名调用:<类名>.<方法名>()
  3. 静态成员方法只能访问静态的成员变量或方法
final关键字
  1. final声明的类不能有子类
  2. final声明的方法不能被子类覆写
  3. final修饰的变量
    1. 基本类型:修饰数据值,不能被改变
    2. 引用类型:修饰地址值,地址不可以被改变,地址指向的数据可以改变

其他关键字

this关键字

  1. 表示该类的属性变量:this.变量名

  2. 调用本类的构造方法:this()

  3. 表示当前类,可调用成员方法:this.成原方法名()

new关键字

调用类的构造器(构造方法)

关于构造器
  1. 调用构造器时,若未写空构造器,系统会默认分配一个空构造器。
  2. 构造器的重载
    1. 重载一般要保证写好空构造器:若未写,系统不会默认分配,调用就会报错
    2. 构造器重载便于为属性赋值(可因对象不同值不同)
  3. 调用构造器前,对象已创建好,并且各属性已有默认的初始化的值
  4. 构造器格式(无参)
<权限修饰符> 构造器名() {
    
}
  • 1
  • 2
  • 3
  1. 构造器和方法的区别:

    1. 没有方法的返回值类型
    2. 方法体内部不能有return语句
    3. 构造器名字 == 类名 (必须)
  2. 构造器的作用

    为类的属性赋值(无参构造器或构造器的重载)

instanceof关键字

  1. 格式:

    a instanceof A:判断对象a是否使A的实例。返回值为bool型(是返回true)

  2. 用法:

    可避免向下转型时出现ClassCastException的异常,即先判断返回true再进行转型。

    (换言之,可以对某个对象进行选择性的转型)

继承

  1. 访问父类的成员变量:super.变量名

    1. 关键字访问成员变量访问构造方法
      thisthis.成员变量
      访问本类成员变量
      this()
      访问本类构造方法
      supersuper.成员变量
      访问父类成员变量
      super()
      访问父类构造方法
    2. 通过子类对象访问一个方法

      1. 先在子类范围内寻找
      2. 再在父类范围寻找
  2. 子类中所有构造方法被调用时,默认都会先访问父类无参构造方法

    1. 因为子类会继承父类中的数据,可能还会使用父类中的数据。所以子类初始化之前,一定要先完成父类数据的初始化
    2. 每一个子类构造方法的第一条语句默认都是super()
    3. 若使用父类带参构造方法进行数据初始化,即super()
    4. 若父类中没有无参构造方法,只有带参构造方法
      1. 用super关键字去显示的调用父类带参构造方法
      2. 在父类中自己提供一个无参构造方法
  3. 方法重写

    1. 子类出现了和父类中一模一样的方法声明

    2. 应用

      1. 当子类需要父类的功能,而功能的主体子类又自己特有的内容时,可重写父类中的方法,这样即沿袭了父类的功能,又定义了子类特有的内容。

      2. 重写的方法中,可擅用super关键字沿袭父类的(基础)功能

      3. 课用@Override检测重写方法是否有误

      4. 注意事项

        1. 父类中的private方法无法被子类继承,则无法被重写

        2. 子类方法访问权限不能更低

          (public>默认>protected>private)

    3. Java继承的注意事项

      1. 一个子类只能单继承,不支持多继承
      2. 可实现多层继承

多态

  1. 在Java中主要有两种体现形式:

    1. 方法的重载与覆写(重写)
    2. 对象的多态性
  2. 成员访问特点:(为何两种不一样:成员方法有重写)

    1. 成员变量:编译与执行均看左边
    2. 成员方法:编译看左边,执行看右边
  3. 优弊

    1. 优势:提高了程序的扩展性

      ​ 具体体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作

    2. 弊端:不能使用子类的特有功能

  4. 转型(实现使用子类特有功能)

    1. 向上转型:从子到父,父类引用指向对象

    2. 向下转型:从父到子,父类引用转为子类对象

      用强制类型转换实现执行子类特有方法(不占用新的堆内存)

抽象类

  1. 概述:

    在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象方法

  2. 特点

    1. 抽象类和抽象方法必须用abstract关键字修饰

    2. 抽象类中不一定有抽象方法,由抽象方法的类一定时抽象类

    3. 抽象类不能直接实例化

      如何实例化:参照多态的方法,通过子类对象实例化,这叫做抽象类多态

    4. 抽象类的子类

      要么重写抽象类中的所有抽象方法

      要么本身就是抽象类

  3. 抽象类成员特点

    1. 成员变量:变量/常量

    2. 构造方法:
      不可直接实例化。
      用于子类访问父类数据的初始化

    3. 成员方法:

      可以有抽象方法:限定子类必须完成某些动作

      也可以有非抽象方法:提高代码的复用性

  4. 抽象类名作为形参和返回值

    1. 方法的形参时抽象类名,其实需要的时该抽象类的子类对象
    2. 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象

接口

  1. Java中的接口更多的体现在对行为的抽象

  2. 声明接口关键字:interface

    public interface <接口名>;

    调用接口关键字:implements

    public class A implements <接口名>;

    接口是abstract的,亦不可直接实例化

  3. 接口多态

    1. 多态的形式:具体类多态,抽象类多态接口多态
    2. 多态的前提:
      1. 有继承或者实现关系;
      2. 有方法的重写/覆写
      3. 有父类/父接口引用指向子/实现类对象
  4. 成员特点

    1. 成员变量:默认被public static final修饰
    2. 成员方法:public abstract
  5. 构造方法

    ​ 接口无构造方法,因为接口主要是行为进行抽象的

    一个类如果无父类,默认继承自Object类

  6. 类和接口的关系

    ​ 一个接口可以implements多个接口

  7. 抽象类和接口的关系

    1. 成员区别

      抽象类变量,常量;有构造方法;有抽象方法也有非抽象方法
      接口常量;抽象方法

      2.关系区别

      类与类只能extends一个父类
      类与接口可以implements多个接口
      接口与接口同上

      3.设计理念区别

      抽象类对象抽象(属性,行为)
      接口主要对行为抽象
  8. 接口名作为形参和返回值

    1. 方法的形参是接口名,其实需要的是该接口的实现类对象
    2. 方法的返回值是接口名,其实返回的是该接口的实现类对象
  9. JDK8接口的新特性

    1. JDK7及以前,只能定义全局常量和抽象方法(参见4.)

    2. JDK8以后,接口还可以定义静态(static)方法和默认(default)方法。

      1. 接口中定义的静态方法,只能通过接口调用

        interface IA() {
            public static method() {}
        }
        
        public SubClass implements IA {}
        
        public Class SubClassTest {
            public static void main(String[] args) {
                SubClass s = new SubClass();
                
                s.method();			//  ×
                SubClass.method();	//	×
                //上述两种调用方法,(编译时?)会完全无视method方法
                IA.method();		//	√
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
      2. 接口中的默认方法,可通过实现类的对象调用。

      3. 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参的方法(类优先原则)

      4. 如果实现类实现了多个含有同名同参的默认方法的接口,且实现类没有重写此方法的情况下,会报错(接口冲突)(必须重写此方法才可以使用)

      5. 在子类(实现类)调用接口中的方法

        class SuperClass() {
            public void method();
        }
        
        interface CompareA() {
            public static void staticMethod(){}
            public void method();
        }
        
        class SubClass extends SuperClass implements CompareA() {
            public void method();
            
            public void myMethod() {
                method();//调用自己定义的重写的方法
                
                super.method();//调用父类中声明的方法
                
                CompareA.staticMethod();//调用接口中的静态方法
             	CompareA.super.method();//调用接口中的默认类型方法
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21

内部类

  1. 访问特点

    1. 内部类可直接访问外部类的成员,包括private
    2. 外部类要访问内部类成员,必须创建对象调用
  2. 成员内部类

    1. 当内部类权限为public时:

      外界使用内部类格式(外部类名.内部类名):

      例:Outer.Inner oi = new Outer().new Inner();

    2. 当内部类权限为private时:

      类似于构建getAge和setAge方法。

  3. 局部内部类

    1. 定义在方法内,外界无法直接访问,需要在方法内部创建对象并使用

    2. 该类可直接访问外部类的成员,也可访问方法内的局部变量

    3. 匿名内部类

      1. 前提:存在一个类或接口,类可以时具体类也可抽象类

      2. 格式:

        new 类名或接口名() {
        	重写方法;
        }
        
        • 1
        • 2
        • 3
      3. 本质:

        是一个继承了该类或实现了该接口的子类匿名对象

      4. 用例:

        不用匿名内部类

        interface A {
            public void printlnfo();
        }
        
        class B implements A {				//定义接口实现类
            public void printlnfo() {		//重写抽象方法
                System.out.println("Hello World!");
            }
        }
        
        class X {
            public void fun1() {
                this.fun2(new B());
            }
            
            public void fun2(A a) {
                a.printlnfo();
            }
        }
        
        public class NoInnerClassDemo01 {
            public static void main(String[] args) {
                new X().fun1();
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25

        使用内部类改写:省去写新的实现接口的类

        interface A {
            public void printlnfo();
        }
        
        class X {
            public void fun1() {
                this.fun2(new A() {						//匿名内部类
                    public void printlnfo() {			//实现接口内中的抽象方法
                        System.out.printlnfo("Hello World!");
                    }
                })
            }
        }
        
        public class NoInnerClassDemo02 {
            public static void main(String[] args) {
                new X().fun1();
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19

MVC设计模式

  1. MVC将整个程序分为三个层次:视图模型层,控制器层,与数据模型层。

  2. 特点:

    将程序输入输出、数据处理,以及数据的展示分离

  3. 优势:

    使程序结构变的灵活而清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。

  4. 各层次:

    1. 模型层 model 主要处理数据

      >数据对象封装 model.bean/domain

      >数据库操作类 model.dao

      >数据库 model.db

    2. 控制层

      >应用界面相关 controller.activity

      >存放fragment controller.fragment

      >显示列表的适配器 controller.adapter

      >服务相关的 controller.service

      >抽取的基类 controller.base

    3. 视图层

      >相关工具类 view.utils

      >自定义 view.ui

==与equals()

  1. 对于==运算符(比较的表达式类型必须一致)

    1. 比较基本数据类型变量:比较两个变量包存的数据是否相等
    2. 比较引用数据类型变量:比较两个对象的地址值是否相同,即两个引用是否指向同一个对像实体
  2. 对于equals()方法

    1. 只用于引用数据类型

    2. 源自Object类,其中equals ()的定义:

      public boolean equals(Object obj) {
          return (this == obj);
      }
      
      • 1
      • 2
      • 3

      说明:和 == 的作用相同,比较两个对象的地址值是否相同。

    3. 其他类自带重写:如String, Data, File, 包装类等

      比较两个对象的实体内容是否相同

    4. String类中的equals()方法重写代码:

      (可用于重写Object类的equals()方法)

      public boolean equals(Object obj) {
          if (this == anObject) {
              return true;
          }
          if(anObject instanceof String) {
              String anotherString = (String)anObject;
              int n = value.length;
              if (n == anotherString.value.length) {
                  char v1[] = value;
                  char v2[] = anotherString.value;
                  int i = 0;
                  while(n-- != 0) {
                      if (v1[i] != v2[i])
                          return false;
                      i++;
                  }
                  return true;
              }
          }
          return false;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

toString()方法

  1. 源自Object类

    其中对toString()的定义:

        public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
    
    
    • 1
    • 2
    • 3
    • 4
  2. String, Data, File, 包装类等都重写了Object类中toString()方法

    返回实体内容信息

包装类

  1. 作用:将基本类型视为引用类型(对象)

  2. 基本类型对应的引用类型
    booleanjava.lang.Boolean
    bytejava.lang.Byte
    shortjava.lang.Short
    intjava.lang.Integer
    longjava.lang.Long
    floatjava.lang.Float
    doublejava.lang.Double
    charjava.lang.Char

    除java.lang.Boolean和java.lang.Char外,其余类的父类为Number

  3. 包装类,基本数据类型,String三者间的转换

    1. 基本数据类型---->包装类

      调用包装类的构造器:

      传入参数为代转换基本数据类型值

    2. 包装类---->基本数据类型

      调用包装类的xxxValue()方法,如:

      Integer in1 = new Integer(10);
      
      int i1 = in1.intValue();
      
      • 1
      • 2
      • 3
    3. 自动装箱与自动拆箱:

      省去调用构造器的过程

      1. 自动装箱如:
      int in1 = 10;
      Integer in2 = in1;//自动装箱
      
      • 1
      • 2
      1. 自动拆箱如:
      Integer in1 = new Integer(10);
      int in2 = in1;//自动拆箱
      
      • 1
      • 2
    4. 基本数据类型/包装类 ----> String类型

      如:

      	int num1 = 10;
      //方式1:连接运算
      String str1 = num1 + "";
      //方法2:调用String的valueof()方法
      float f1 = 12.3f;
      String str2 = String.valueof(f1);
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    5. String类型 ----> 基本数据类型、包装类

      1. 不能采用强制类型转换的方式(无子父类关系)

      2. 调用parsexxx()方法;

        如:

        String str = "string";
        int num = Integer.parseInt(str);//等号右边返回值即为int类型
        
        //但上述str会导致报错:NumberFormatException
        
        • 1
        • 2
        • 3
        • 4
  4. 关于包装类wrapper使用的面试题

    1. Object o1 = true ? new Integer(1) : new Double(2.0);
      
      System.out.println(o1);
      
      • 1
      • 2
      • 3

      思考输出结果。 1.0

      解释:三元运算符会在编译时统一左右两边的数据类型,故输出结果为double

    2. Integer m = 1;
      Integer n = 1;
      System.out.println(m == n);
      
      //输出结果为true
      
      • 1
      • 2
      • 3
      • 4
      • 5
      Integer m = 128;
      Integer n = 128;
      System.out.println(m == n);
      
      //输出结果为false
      
      • 1
      • 2
      • 3
      • 4
      • 5

      解释:自动装箱时会调用Integer类中的一个类叫IntegerCache,里面有个数组叫Integer cache[];默认存储 -128 到 127 int数值。

      而在该范围内比较数组中的地址是缓存里同一个数组Integer cache[]

      若超出范围则new新的,故地址是不同的

单例(Singleton)设计模式

采取某种方法,使某个类只能有一个实例对象

  1. 饿汉式

    class Demo01 {
        //1.私有化类的构造器
        private Demo01() {
        }
        
        //2.内部创建类的对象
        //静态方法只能调用静态对象
        private static Demo01 instance = new Demo();
        
        //3.提供公共的静态的方法(方便外部获取单例对象),返回类的对象
        public static Demo01 getInstance() {
            return instance;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  2. 懒汉式

    class Demo02 {
        1.私有化类的构造器
        private Demo02() {
        }
        
        //2.声明当前类对象(静态)(无初始化)
        private Demo02 instance = null;
        
        //3,声明公共的静态的返回当前类对象的方法
        public static Demo02 getInstance() {
            if (instance == null) {				//增加判断条件,保证instance严格只有一个
      			instance = new Demo02();     
            	return instance; 
        
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
  3. 对比

    1. 饿汉式:

      利:线程安全

      弊:对象一开始就创建,(加载时间长)

    2. 懒汉式:

      利:用的时候再创建对象

      弊:目前写法,线程不安全:如,在用户A进入if内,instance还未被new的时候发生线程堵塞,用户B可以在此时也进入if内,则两者分别new了一次。

  4. 单例模式的优点:

    由于单例模式只生成一个实例,减少了系统性能的开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。

    如java.lang.Runtime:

    public class Runtime {
        private static final Runtime currentRuntime = new Runtime();
    
        private static Version version;
    
        public static Runtime getRuntime() {
            return currentRuntime;
        }
    
        /* Don't let anyone else instantiate this class */
        private Runtime() {}
        ......
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  5. 其他应用场景

    1. 网站的计数器,一般也是单例模式实现,否则难以同步。
    2. 应用程序的日志应用,一般都使用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
    3. 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
    4. 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,都生成一个对象去读取。
    5. Application也是单例的典型应用
    6. Windows的Task Manager(任务管理器)就是很典型的单例模式
    7. Windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

异常处理

  1. 概述:

    规避一些非代码问题如,客户输入数据的格式,读取文件是否存在,网络是否始终保持通常等等

    语法错误和逻辑错误不是异常。

    分类:

    1. Error:JVM无法解决的严重问题,如JVM系统内部错误,资源耗尽等严重情况。如,StackOverflowError和OOM(堆溢出)。一般不编写针对性的代码进行处理。
    2. Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以用针对性的代码进行处理。如空指针访问,试图读取不存在的文件,网络连接中断,数组下标越界等。
  2. 常见异常,参见https://www.jianshu.com/p/a03c8807bbbc

  3. 异常处理模型:抓抛模型

    1. 过程一:“抛”,程序在正常执行过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。并将此对象抛出。一旦抛出对象,try内其后的代码就不再执行。

    2. 过程二:“抓”,可以理解为异常的处理方式:

      1. try-catch-finally

        1. 格式:
        try{
            //可能出现的代码
        }catch(异常类型1 变量名1){
            //处理异常的方式1
        }catch(异常类型2 变量名2){
            //...
        }//可多个catch
        ......
        //可选是否使用finally
        finally{
            //一定会执行的代码
        }    
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        1. 要点:

          1. finally可选

          2. try内代码出现异常,会生成一个对应异常类的对象,根据此对象的类型,去catch中匹配。

          3. 匹配到catch后进行异常处理,完成后寻找fianlly执行(也可能无),随后进行执行后面的代码。

          4. catch中的异常类型若无子父类关系,则上下顺序无所谓。

            若有子父类关系,要求子类一定声明在父类上面,否则会报错。

          5. 常用的异常对象处理方式:

            1. String getMessage()
            2. printStackTrace()
          6. 在try结构中声明的变量,等结束try的使用后,就不能再被调用!

          7. 可以嵌套

          8. 使用try-catch-finally处理编译时异常,相当于将一个编译时可能出现的异常,延迟到运行时出现。

          9. 由于运行时异常比较常见,所以我们通常不针对运行时异常编写try-catch-finally了。针对编译时异常,我们一定要考虑异常的处理。

      2. throws + 异常类型

        1. 写在方法声明处,指明此方法执行时,可能会抛出的异常类型。一旦方法执行时,出现异常,仍会在异常代码处生成一个异常类的对象。此对象满足throws后异常类型时,就会被抛出。异常后续的代码不再执行。

        2. throws的方式只是将异常抛给了方法的调用者,并没有真正将异常处理掉。

          真正处理掉的时try-catch-finally的方式

    3. 如何选择两种方式

      1. 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws。意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理。
      2. 执行的方法a中,先后又调用的另外的几个方法,这几个方法时递进关系执行的,则可以使用throws的方式进行处理,而执行的方法a可以使用try-catch-finally方式。
  4. 手动抛出异常(throw)

    1. 区别于系统自动生成的异常类型如FileNotFoundException等。

    2. 例子

      public class StudentTest {
          try {
              Student s = new Student();
              s.regist(-1001);
              System.out.println(s);
          } catch (Exception e) {
              //e.printStackTrace();
              System.out.println(e.getMessage));
          }
      }
      
      class Student {
          private int id;
          public void regist(int id) throws Exception {
              if (id > 0) {
                  this.id = id;
              }else{
                  //System.out.println("您输入的数据非法!");
                      //手动抛出异常:
                      //throw new RuntimeException("您输入的数据非法!")//不用在实现类里使用try-catch,因为类型为“运行时的错误“
                      throw new Exception("您输入的数据非法!")//需要在实现类里加try-catch,因为Exception类型考虑了编译时出现的问题。
              }
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
  5. 用户如何自定义异常

    1. 继承于现有的异常结构:RuntimeException, Exception。
    2. 提供全集变量类序号:serialVersionUID(static final long)
    3. 提供重载的构造器
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/678714
推荐阅读
相关标签
  

闽ICP备14008679号