Java语言基础

DogJay 2016-10-20 后端技术 69人已围观

Java语言基础

  • Java语言的组成:

语句;注释;关键字;标识符;常量;变量;运算符;流程控制(顺序,分支,循环);函数;数组;类;接口

  • 注释:
  • 几乎任何语言,都有注释:java,c#,c,c++,html,javascrip,jsp
  • 主要是解释程序的含义,帮助程序员阅读代码。
  • 调试,修改代码时,可以使用注释。
  • 在实际项目中,注释一般会占代码量的1/3到1/4
  • 在.java文件,注释的信息,将不会被编译。
  • 如何注释 - //———–单行注释
  • /*         */多行注释
  • /** */文档注释,一般,文档注释都是在类或方法或属性的前面。当通过javadoc命令将程序,生成一个文档,对类或方法等信息进行解释说明。

注意:

对代码注释,可以使用:
ctrl + /  对光标所在行或选中的多行进行单行注释,再操作一次,相反。
ctrl+shift+/  对选中的代码进行多行注释
ctrl+shift+\  对选中的已经被多行注释的代码取消注释。

  • 关键字: - keyword,Java中赋予了特殊含义的单词。因为具有了特殊含义,所以在后续命名中,不能使用。
  • 关键字有很多,比如public class  private  protected…..
    在eclipse中,默认显示为红色的,都是关键字。
  • goto const: 保留字
  • 特点: - 1-不是固定的,随着java的发展,关键字也在发展。
  • 2-关键字全部小写。
  • 标识符: - 主要用于为Java中的类名,包名,属性名,方法名,变量名…命名。
  • 标识符的组成: - 只能由数字(0-9),字母(a-zA-Z),$,_ 组成。且数字不能开头。
  • 以下哪些标识符合法 - abc123_a8; $23bdc.exe;  _123;  A;  1ab3;   wud&bc;
  • 注意点: - 1-标识符可以以$开头,但不建议使用。
  • 2-标示符可以使用中文,但禁止使用。
  • 3-标识符不能使用关键字。
  • 4-Java中,大小写敏感的。可以使用A和a分别表示不同的名称,但是,最好不要仅仅以大小写区分。
  • 命名建议: - 1-命名要有意义,最好做到见名知意。

int age = 20;  String name = “jack”;
int a = 10; String n = “rose”;

  • 2-类名,接口名的命名,单词首字母大写。HelloWorld, Student
  • 3-属性名和变量名:如果有一个单词,则该单词全部小写;如果有多个单词,第一个单词全部小写,第二个单词及以后,首字母大写。age, name, totalScore
  • 4-方法名:如果有一个单词,则单词全部小写;如果有多个单词,则第一个单词小写,第二个单词及以后,首字母大写。一般情况下,一个单词的方法,该单词是动词get;两个或多个单词,一般是动宾结构getName

  • Java中整数表示形式
  • 二进制:

0, 1
八位无符号二进制范围:00000000~11111111
八位有符号二进制范围:11111111~01111111
三位无符号二进制范围:000~111    转换成十进制:0~7

  • 八进制:

0~7                八进制的标志:0开头。023  八进制。
一位八进制相当于是3位二进制。
0271转换成二进制: 10111001
11011011000101010:0333052

  • 十进制:

0~9表示。

  • 十六进制:

0~9 A~F(a~f)     十六进制的标志: 0X或 0x
四位无符号的二进制范围:0000~1111    转换成十进制: 0~15
一位十六进制相当于4位二进制
0x9F: 10011111
0X3ABF:11101010111111
1101111011100010101:0X6F715
十六进制常常用于表示颜色:RGB(Red, Green, Blue)在表示颜色的时候,每一种颜色用两位的十六进制表示。表示形式#00FFAA     #FF0000  #00FF00  #0000FF   #000000  #FFFFFF

  • 进制转换

  • 整数在内存中的存储
  • 数据在内存中,以何种形式存储: - 数据存储是以补码的形式存储:

int类型用4个字节存储数据。也就是说32位。

正数:原码,反码,补码相同。

负数的原码,是它的绝对值的二进制的最高位为1,反码是原码符号位不变,其他位取反;补码是反码末尾+1。

  • 字面常量(值不能改变的)
  • 整型常量: 10, 100                             type:  int
  • 小数常量:0; 100.54;                   type:  double
  • 布尔型常量:true fasle;                   type:  boolean
  • 字符常量: java中,字符常量用’a’,单引号中只能有单个字符。 type:   char
  • null 只有一个值。
  • 字符串常量: “abcdefg”,””;  “  “; 由双引号括起来的0个或多个字符。

“”  “a”  “Aaaaaa”     type:  String类型

  • 变量: - 就是数值可以变化。变量是一块内存存储空间。
  • 如何定义和使用变量: - type name = value;
  • int age = 10;

  • 数据类型: - 就是为计算机中的数据进行分类。
  • Java中有哪些数据类型: - 基本数据类型 - byte 1B          -128~127
  • short 2B
  • int 4B
  • long 8B
  • char 2B
  • float 4B
  • double 8B
  • boolean 1B(1bit)
  • 引用数据类型 - 数组
  • 接口
  • 类—String
  • Java基本数据类型 - 数值型 - 定点型:byte short int long
  • 浮点型:float double
  • 字符型:char
  • 逻辑型 - boolean

  • Java基本数据类型-定点型
  • 定点型: - byte 1     -27~27-1 (-128~127)    较常用           0
  • short 2     -215~215-1                                        0
  • int 4     -231~231-1                   很常用           0
  • long 8     -263~263-1                   较常用           0L
  • 四种数值类型的区别? - 表示范围不同,视情况选择相应类型。
  • 整数类型中,整型常量默认的是int类型。
  • 一个数值表示long,该值必须后面加上l或L - long a = 10L;
  • 注意: - 整型常量默认为int,如果是为byte, short,char赋值,如果整型常量的范围在byte,short,char表示的范围,会自动向下转换成byte,short,char,并存储在byte,short变量表示的内存空间中。
  • 如果为long类型的变量赋值,则可以指定常量10L表示long型;如果使用整型常量,如long l = 100;,则int类型的100会自动向上转换为long类型。如果后面的常量值,超过了int表示的范围,则必须在常量后面加上L或

  • Java基本数据类型-浮点型 - float:单精度        4B   0f或0.0F
  • double:双精度 8B   0
  • 一个小数常量,默认是double类型。0
  • 浮点型表示形式: - 十进制形式表示:
  • 科学计数法: 小数E整数
  • //注意:精确的小数运算,使用BigDecimal类
  • out.println(2.0-1.1);//小数在计算机中,无法表示1/10数值。0.899…

  • Java基本数据类型-字符型 - 表示字符类型,长度2B。默认值 ‘\u0000’
  • 在java中,字符类型以unicode编码方式进行编码。以2个字节表示一个字符。 - java中的char类型能否存放中文?为什么? - 在java中,char类型是以unicode编码方式存放,unicode编码是以2个字节表示一个字符。中文,占用2个字节,所以,char能够存放汉字。
  • char常量是在’’内,且只能有一个字符。 - ‘’,必须有一个字符; ‘a’;  ‘中’;  ‘ab’;
  • char表示的范围:0~65535
  • 转义字符 - 在Java中,有些字符比较特殊。必须要经过转义才可以使用
  • 如何转义—- \字符
  • 常见的转义字符? - \n—换行
  • \t—-制表符
  • \r—–回车
  • \——-\
  • \’——-’
  • \”——-”

  • Java基本数据类型-逻辑性 - 仅表示两种状态。boolean的值只有true,false;
  • 布尔型默认值是false;

  • 特殊的引用类型- String类型 - 表示字符串。由“”括起来,且0个或多个字符。 - “”; “a”;  “aaa”;
  • String str = “”; String str = “a”;   String str = “aaa”;
  • 注意: - 1-String不是基本数据类型,是引用类型。
  • 2-String默认的值是null - String s1 = “”;
  • String s2 = null;

  • 类型转换规则
  • 1-boolean不能与任何基本数据类型转换。
  • 2-byte,short,char一般不互相转换。如果参与其他运算,会先自动转换成int类型,再运算.
  • 3-任何基本数据类型,都可以与String相加.基本类型会先转换成String,与String类型拼接.
  • 4-类型自动转换(隐式转换):字节数小的可以自动转换成字节数大。

  • 5-类型强制转换(显式转换),如果字节数大的转换成小的,必须强制转换。强制转换,有可能发生数据溢出,造成错误。 - type1 t = (type1)值;
  • 如果是浮点型的数据转换成整型,则会出现截尾操作。
  • 6-多种数据类型混合运算时,小类型自动转换成大类型。

  • 声明和赋值 - 1-可以声明的同时,对变量赋值:int x = 10;
  • 2-可以先声明,再赋值:int x; x = 10;
  • 3-可以一行声明多个变量: int x, y, z;由,分隔
  • 4-一行声明多个变量,且为所有变量或部分变量赋值:由,分隔

int x, y = 10, z, w = 10;

  • 5-建议:一行只声明一个变量,且在声明的同时,为其初始化。
  • 6-变量在使用前一定要初始化。

int ii1;//局部变量,在使用前,必须为其赋初始值。

//ii1 = 100;

System.out.println(ii1);//如果不为局部变量赋初始值,则在使用时,编译错误。

  • 7-变量的命名规则: - 不能用关键字
  • 最好不要以$,_开头。
  • 一个单词时,单词小写,多个单词时,第一个单词全部小写,第二个单词首字母大写。

  • 字符串拼接

字符串拼接,要清楚哪些是可变的,哪些是不变的。可变的要放在“”之外。

ex:

**int** a = 100;**int** b = 5;

//a+b=15;

System.out.println(“a + b = ” + a + b);//a + b = 105

System.out.println(a + b + ” = a + b”);//15 = a + b

System.out.println(“a + b = ” + (a + b));//a + b = 15

//10 + 5 = 15

System.out.println(a + ” + ” + b + ” = ” + (a + b));

//字符串拼接,要清楚哪些是可变的,哪些是不变的。可变的要放在””之外。

//(a) + (b) = [reslut];

//”(” + a + “) + (” + b + “) = [” + (a + b) + “]”;

System.out.println(“(” + a + “) + (” + b + “) = [” + (a + b) + “]”);

 

  • 再说常量:
  • 常量定义的两种形式: - 常量的定义第一种形式:在声明常量时,直接为常量赋值。以后该常量不允许改变 final int AGE = 10;   建议使用此种方式。
  • //常量第二种形式:先声明,只允许赋值一次,不能再改变该常量的值。

final int SCORE;     SCORE = 90;

  • 常量的命名规则: - 常量的名称全部大写,如果有多个单词,则多个单词之间用_连接。

final int  SCORE = 10;  final  int  MY_SCORE = 100;

  • 注意: - 以后定义常量,一般是在类中定义。习惯加上static关键字

public   static    final   XXX_XXX_XXX =  value;

  • 运算符:
  • 赋值运算符
  • 算术运算符
  • 关系运算符(比较运算符)
  • 逻辑运算符
  • 位运算符
  • 位移运算符
  • 条件运算符(三目运算符)

  • 赋值运算符
  • = 将=号右边的值,赋值给=左边的变量。将value存放入变量指向的内存中。
  • 赋值运算符优先级很低。
  • int a = 10;

  • 算术运算符 - +, -,  *,   /,  %(取模), + , – - %:可以判断是否能够被整除;判断是某个数的倍数。
  • 两个整型算除法,结果整型
  • 自增和自减 ++  或  — - a = a + 1;相当于 a++或++a;
  • a = a – 1;相当于 a–或–a;
  • //++或–位于变量之前,变量先自增或自减,再参与运算
  • //++或–位于变量之后,先使用当前变量的值参与运算,变量再自增或自减
  • += -=  *=  /=  %= - a += b è a = a + b;
  • byte,short变量 b1 += b2==》b1 = (byte)(b1 + b2)

  • 关系运算符
  • , >=, <, <=, ==, !=,  instanceof

  • 比较之后,返回的结果true或false
  • == 与  =  区别?

  • 逻辑运算符 - 有短路的逻辑运算符: !      &&  || - ! 非:    !(10 > 5) – 取反;
  • &&   condition1 && condition2   –两个条件同时为true,结果为true
  • || condition1 || condition2 –两个条件同时为false,结果为false
  • 无短路的逻辑运算符: ^     &    | - ^:表示异或,两个条件相同为false,不同为true
  • &:逻辑与,两个条件,同时为true,结果为true
  • |:逻辑或,两个条件,同时为false,结果为false
  • 比较 - condition1 && condition2:如果1为false,则不再执行2的代码。
  • condition1 &  condition2:不管1是否为false,2照常执行。
  • condition1 || condition2:如果1为true,则不再执行2的代码。
  • condition1 |  condition2:不管1是否为true,2照常执行。
  • condition1 &&(||) condition2 &&(||)  condition3….

  • 位运算符 - ~,^,&,| - ~:按位取反
  • ^:按位异或
  • &:按位与
  • |:按位或
  • 位运算符过程
~对a的值按位取反,5转换成32位的二进制,按位取反(将二进制位数0-1互换)

运算过程:5=00000000000000000000000000000101

~5=11111111111111111111111111111010//补码反码

=11111111111111111111111111111001

原码=10000000000000000000000000000110-> -6

&

  • 5=00000000000000000000000000000101

  • 7=00000000000000000000000000000111

*& =00000000000000000000000000000101

|

  • 5=00000000000000000000000000000101

  • 7=00000000000000000000000000000111

*| =00000000000000000000000000000111

^ —–加密和解密

如果两个数异或的结果,与其中任意一个数异或,则结果是另外一个数。 a = b ^ c, 则  a ^ b = c 或  a ^ c = b

5=00000000000000000000000000000101

7=00000000000000000000000000000111

^ =00000000000000000000000000000010

a ^ b = c;

c ^ a = b;

c ^ b = a;

 
  • 移位运算符 - <<, >>,  >>>
  • << 有符号的左移  x << n - 高位去掉n位,低位以0补n位,相当于x乘以n个2;
  • 有符号的右移 - 低位去掉n位,高位以符号位补n位,相当于x除以n个2;

  • 无符号右移 - 低位去掉n位,高位以0补n位,相当于x除以n个2;

面试题:  62 – 63 = 1

面试题: 使用最有效率的方式,将2变成64      2 << 5

  • 条件运算符(三目运算符)
  • 表达式?表达式1(返回值1):表达式2(返回值2);

表达式结果必须为boolean类型。true, false

表达式1和表达式2数据类型必须相同或兼容

如果表达式成立(true),会返回表达式1的值,否则(表达式为false),则返回表达式2的值。

  • 运算符优先级及总结

运算符的划分:

  • +,-,~, ! :单目运算符
  • 算术运算符,比较运算符… a  operator b;   双目运算符
  • 表达式?value1:value2: 三目运算符。

运算符优先级:

  • 优先级不同的,优先级高的先运算;优先级相同的,看结合性。
  • 以后在编写代码中,最好使用(),分隔执行的先后顺序。

  • 流程控制语句 - 顺序流程
  • 选择流程、分支流程
  • 循环流程

  • 顺序流程 - main开始,一行一行执行,main方法执行结束,程序退出。

  • 选择流程 - if(条件表达式)//表达式值为boolean类型
    {
    //语句…
    }
  • if(条件表达式)//条件成立,运行语句1;否则,运行语句2
    {
    //语句1
    }
    else
    {
    //语句2
    }                                    //    ?:
  • if(条件)
    {
    //语句1
    }
    else if(条件)
    {
    //语句2
    }
    else if(条件)
    {
    //语句3;
    }
    ….
    else
    {
    //语句n
    }
  • 选择流程语句注意点: - 1-if(条件表达式),条件返回true或false。
  • 2-if或else 后面,可以不使用{},但此时仅仅只对if或else下第一行语句有效。以后,哪怕只有一行语句,必须使用大括号。

  • 练习: - 1- 通过键盘输入学生的学号,根据学号打印输出名字。1,张三;2,李四;3,王五;其他,不存在。
  • 2- 获取键盘输入的分数,根据以下条件打印输出

[100, 90],输出A;

[70, 90), 输出B;

[60, 70), 输出C;

其他    输出D。

  • 分支结构(选择) - switch(表达式)//是一个byte,short,char,int类型的值
    {
    case  常量值1:
    语句;
    break;
    case  常量值2:
    语句;
    break;
    case  常量值3:
    语句;
    break;
    ……
    default:
    语句;
    [break;]//可有可无
    }
  • 语句使用注意: - 1-option类型只能是byte,short,char, int;在0后,enum可以;7.0后String
  • 2-case子句后面的常量值,必须是char,int类型,在0后,enum也可以;7.0后String
  • 3-case语句块中,根据实际情况,使用break。一般在每个case语句块中都会加上break。break语句用于跳出switch语句块。
  • 4-default子句,当表达式与case后的常量不匹配的时候,会执行default子句。一般default子句位于最后。default子句后,break语句可有可无。
  • 5-多个case子句,default子句没有顺序限制。如果default子句不在最末尾,则必须加上break语句。以后不能这么写。
  • 6-switch语句只能比较离散的数值。if(条件语句),条件语句可以表示一段范围。
  • 练习: - 1- 获取键盘输入的分数,根据以下条件打印输出

[100, 90],输出A;

[70, 90), 输出B;

[60, 70), 输出C;

其他    输出D。

使用switch语句实现。

f / 10 = 10

[90,99] / 10 = 9

[80,89] / 10 = 8

  • 循环流程 - while

  • do…while

  • for

  • for增强(foreach)

  • for循环

1-先执行表达式1;一般表达式1是初始化变量。

2-再执行条件表达式2;判断循环条件是否成立

3-循环体执行后,执行表达式3;是控制循环变量的。

for循环注意点:

1-表达式1, 2, 3可有可无。for(;;){}表示死循环

2-表达式1, 3可以有多个语句,中间以,分隔。

for(int aa = 0, b = 10; aa < b ; b++, aa++)

{            }

3- 注意循环变量是否仅仅用于控制循环。

  • while循环和.while循环
  • while - while(条件表达式)//控制循环条件的,true,则继续循环,否则,退出
    {
    //循环体,循环的代码
    }
  • do…while - do
    {
    //循环体
    }while(条件表达式);
  • while循环和.while循环的区别? - while循环先判断条件,如果条件成立,则执行循环体,否则,不执行循环体;而do…while,先执行一次循环体,再判断条件。也就说,不管如何,do…while至少会执行一遍循环体。

三种循环语句:   for,   while,    do…while

1- 最常用的是for, while循环

2- 三种循环语句是相通。(同一需求,三种循环都可以实现)

3- while和do..while区别

while循环先判断循环条件,然后再执行循环体。可能一次循环体都不执行。

do..while循环,先执行一遍循环体,然后再判断循环条件。至少会执行一遍循环体。

  • 循环作业: - 使用while循环和for循环完成以下作业: - 1-打印输出1~100之间偶数的和
  • 2-打印输出1~100之间3的倍数的值。
  • 3-打印输出1~100之间7的倍数的和。
  • 4-打印输出1~1000之间6的倍数的个数。
  • 5-打印输出1~1000之间3的倍数和7的倍数的和
  • 6-打印输出1~1000既是3的倍数又是7的倍数的数值。
  • 7-打印输出1000~2050年中所有的闰年。 - 条件: 能被4整除但不能被100整除 或   能被400整除

  • break, continue

break:

在switch语句中,用于跳出switch语句块。

在循环语句中,用于跳出循环。

continue:

只在循环语句中,表示结束本次循环,进行下次循环。

练习:

求1~1000所有的7的倍数且不能是8的倍数的和,如果和大于200,则退出循环。如果不大于200,则继续循环,累加

分析:

1-使用循环,取得1~1000的数值;

2-判断取得值,是否是7的倍数,如果是,则累加。不是,则判断累加值是否已经超过200。超过200,终止循环;不超200,继续循环,判断。

  • 循环嵌套 - 循环里面,还有循环:
  • 规律:外循环循环一次,内循环循环一遍。
  • 通过如右图形式,解释循环嵌套

  • 循环嵌套练习:
  • 1- 输出一个长方形-宽10个*,五行。





  • 2- 打印输出一个直角三角形

**




  • 3- 打印9*9乘法表
  • 4- 输出以下图形。

  • 流程控制语句练习: - 声明一个double类型变量a,一个float类型变量b,给a赋值5,b赋值7.5,计算平方和
  • 编写程序,采用适当的循环和流控制语句实现下述功能:打印输出0~200之间能被7整除但不能被4整除的所有整数;要求每行显示6个数据
  • 将下列代数式写成Java表达式 - Ax2+bx+c AXX + B*X + C
  • (x+y)3
  • (a+b)/(a-b)
  • 编写一个商场用来计算优惠券的程序:创建一个变量totalCost表示消费金额,给totalCost赋值后,使用if-else计算用户可以获得的优惠券,计算规则为: - 当消费金额大于等于200,小于300,可以获20元优惠券
  • 当消费金额大于等于300,小于500,可以获50元
  • 当消费金额大于500,可获100元
  • 打印出100-1000范围内的所有水仙花数。所谓水仙花数是指一个3位数,其各位数字立方和等于该数本身。

例如 153    提示:先取出每位的值

111 + 555 + 333 = 153

  • 通过编写Java程序,求13-23+33- 43+…….+973-983+993-1003的值

提示:先求出13,33,…993相加总和,再求出23,43,1003总和,相减。

  • 求1-1000之间可以同时被3、5、7整除的数

  • 数组- 属于引用类型。String类就是引用类型。
  • 数组定义: - 具有相同数据类型的,定长的,有序的集合。
  • 特点:类型必须相同,长度固定,索引。查询快,增删慢。
  • 数组分类: - 一维数组,二维数组,….
  • 一维数组: - 数组声明:type[] name;  或   type  name[];  建议使用前者。
  • 数组的创建: - 1- type[] name = new type[length];  int[] arrs = new int[5];
  • 2-type[] name = new type[]{元素1, 元素2,…}; int[] arrs = new int[]{1, 2, 3} - 此种情况,创建数组的时候,为数组元素初始化。不能指定长度
  • 3-type[] name = {元素1, 元素2, …}; int[]  arrs = {1, 2, 3, 4}; - 此种形式,必须在声明的同时对其初始化。不能够先声明,再静态初始化

  • 内存结构分析: - 基本数据类型,只在栈上分配内存空间:
  • 引用数据类型:数组,接口,类。 - 数组:type[] name = new type[length];
  • 声明type[] name –会在栈上分配一块空间。且指定类型为type[];
  • 创建new type[length]—会在堆上开辟一块连续的length个内存空间。
  • = :将堆内存中分配的空间的首地址,存放入栈中。

  • 数组的说明:

  • 数组的说明: - 数组是引用类型,其真实值存放在堆内存中。如果不指定堆内存的地址,则值为null。int[] arr = null;

  • int[] arr = new int[5]; int[]  表示的是int数组类型,int表示该数组元素的值的类型。且声明数组时,不能指定数组个数int[不能有任何值]  arr。

  • 数组的三种定义方式: - 1- type[] name = new type[length];  int[] arrs = new int[5];

  • 2-type[] name = new type[]{元素1, 元素2,…}; int[] arrs = new int[]{1, 2, 3}

  • 3-type[] name = {元素1, 元素2, …}; int[]  arrs = {1, 2, 3, 4};

  • 一旦创建完成,都不可以如下操作: name = {值1, 值2,….};但可以通过动态的方式重新赋值:name = new int[10];

  • int[] arr = new int[5]; 创建数组,如果不为数组中的元素赋初始值,则会使用类型对应的默认值初始化。
    byte,short,int,long 0;
    float, double    0;
    boolean   false;
    char    ‘\u0000’
    引用类型     null

  • 数组是有序的,其有序的含义是数组有索引。数组的索引从0开始,数组最大的索引,是其数组长度-1。操作数组,可以通过索引对数组进行赋值和取值。

  • 使用索引操作数组元素的值时,一定要注意数值的范围[0, length-1],如果超过了数组索引的范围,则会报lang.ArrayIndexOutOfBoundsException异常。

  • 数组对象由一个属性,可以取得数组的长度。 对象.length;

  • 作业: - int[] arrs = {8, 7, 9, 3, 5, 6, 1, 2}:求数组中最大值,最小值,最大值索引,最小值索引,数组的和。

  • int[] arrs = {8, 7, 9, 3, 5, 6, 1, 2};查找数组中是否包含5这个元素,如果不包含,则程序结束。如果包含,则在第一次5所在位置的前面,插入一个值,该值为10。

  • int[] arrs = {8, 7, 9, 3, 5, 6, 1, 2};查找数组中是否包含5这个元素,如果不包含,则程序结束。如果包含,将第一个5删除。

  • int[] arrs = {8, 7, 9, 3, 5, 6, 1, 2};查找数组中是否包含5这个元素,如果不包含,则程序结束。如果包含,将数组中第一个5的位置修改成10

  • 数组的排序: - 冒泡排序

  • 选择排序

吐槽(0)

文章评论

    共有0条评论

    验证码:

文章目录