1 Java基础
1.1 变量
1.1.1 简介
变量是一个代词,指代在计算机的内存中的一块空间,用来存储程序在运行中所需要的数据。
1.1.2 命名规则
- 只能包含字母、数字、_和$,并且不能以数字开头;
- 不能使用关键字/保留字(是关键字的一种,但是占着不用);51+2
- 严格区分大小写(对大小写敏感);
- 可以是中文、日文、韩文等命名,但不建议,有可能乱码;
- 建议:英文的见名知意、驼峰命名法,不要使用拼音。
1.1.3 声明
变量的声明指的是在内存中开辟一块指定大小的内存空间,默认还没有存数据。
语法结构:数据类型 变量名;
// 声明了一个int类型变量num int num; // 声明了三个int类型变量a、b、c int a, b, c;
1.1.4 初始化
变量的初始化指的是对变量的第一次赋值。
语法结构:数据类型 变量名 = 值;
1.声明同时初始化 // 声明变量num,同时赋值为250 int num = 250; 2.先声明再初始化 // 声明变量num int num; // 给num赋值为250 num = 250; 3.同时声明多个变量(用得较少) // 同时声明变量a、b、c int a, b, c; // 同时声明变量a、b、c,并分别赋值为100、200、300 int a=100, b=200, c=300;
1.1.5 访问(操作)
- 变量在使用之前必须要声明并初始化;
- 变量的操作必须与类型匹配。
1.2 数据类型
1.2.1 简介
基本数据类型也叫原生数据类型,Java保留了C语言中的8个基本数据类型,为了计算方便,速度快,但是不能参与面向对象开发。
包装类S
1.2.2 整数相关
- byte : 字节型,1个字节(8位),-128 ~ 127,用得一般
- short : 短整型,2个字节(16位),-32768 ~ 32767,少到几乎不用
- int : 整型,4个字节(32位),-2^31 ~ 2^31-1,最常用
- Java中整数直接量默认为int类型,如: 123、250、10000
- 两个int类型的变量操作,结果还是int类型,小数位无条件舍弃
- long : 长整型,8个字节(64位),-2^63 ~ 2^63-1,用得一般
- long类型的直接量,要在整数后面加l或L,如: 123L、250L
- 如果要计算超出了long范围的时候,可以使用BigInteger类
1.2.3 小数相关
- float : 浮点型,4个字节(32位),-2^31 ~ 2^31-1,少到几乎不用
- float类型的直接量,要在小数后面加f或F,如: 3.14F
- double : 双精度浮点型,8个字节(64位),-2^63 ~ 2^63-1,最常用
- Java中小数直接量默认为double类型,如: 3.14、6.18
- 有可能会出现舍入误差,精确运算时要慎用,(因为10进制与2进制之间转换时有可能会损失精度)
- 要做小数的精确计算时,可以使用BigDecimal类
1.2.4 其他类型
- char : 字符型,2个字节(无符号16位),0 ~ 65535
- char类型的直接量,需要放在’’单引号中,单引号中有且仅有1个字符
- 使用Unicode编码格式,实质上是整数,即char对应的码,如: A->65,a->97
- ”Java程序员”在内存中占多少个字节?14
- boolean : 布尔型,1个字节(8位),false/true
1.2.5 附:面试题
- Java中的原生数据类型有哪些?各自的范围是多少?
1.3 基本数据类型的转换
1.3.1 自动类型转换,从小类型到大类型
byte --> short --> int --> long --> float --> double --> char
1.3.2 强制类型转换,从大类型到小类型强转,有可能发生精度丢失、溢出。向下造型
double d = 3.14; //float f = d; //编译错误,大类型不能直接赋值给小类型 float f = (float) d; //将d中的数据强转成float类型 int i = (int) d; //强制转换,i=3,精度丢失 long l = 200; byte b = (byte) l; //强制转换,溢出了
1.3.3 附:面试题
- 下面的代码编译是否正确?
short s1 = 10; short s2 = 20; s1 = s1 + s2; //编译错误,因为short类型的运算结果自动变成int类型
1.4 运算符
1.4.1 算术运算符 + - * / % ++ --
% : 取余/取模,两个数相除取余数,如: 4/3=商1余1+ 5/3求模
++ : 自增,变量自身加1
++a 先运算后赋值、 a++先赋值后运算
int a = 11; // 先赋值后加1:先把a变量的值10赋给a++表达式(a++=10),然后a变量自身再加1(a=11) int b = a++; Int b=++a; System.out.println(a); //11 System.out.println(b); //10 int x = 10; // 先加1后赋值:x变量先自身加1(x=11),然后再将x变量的值11赋给++x表达式(++x=11) int y = ++x; System.out.println(x); //11 System.out.println(y); //11 int c=5; int f=2;//3 int d=f++; System.out.println(f);//3
-- : 自减,变量自身减1
int a = 10; // 先赋值后减1:先把a变量的值赋给a--表达式(a--=10),然后a变量自身再减1(a=9) int b = a--;//先赋值再减减 System.out.println(a); //9 System.out.println(b); //10 int x = 10; // 先减1后赋值:x变量先自身减1(x=9),然后再将x变量的值9赋给--x表达式(--x=9) int y = --x;//先运算后赋值 System.out.println(x); //9 System.out.println(y); //9
1.4.2 关系运算符 > < >= <= == !=
System.out.println( 10 > 5 ); //true
System.out.println( 10 < 5 ); //false
System.out.println( 10 >= 10 ); //true
System.out.println( 10 <= 10 ); //true
System.out.println( 10 == 10 ); //true
System.out.println( 10 != 10 ); //false
- 关系运算符的结果为boolean类型
1.4.3 逻辑运算符 && || !
&& : 逻辑与/短路与,两边表达式都为true,结果才为true,若左边的表达式为false时会发生短路(右边的表达式不再执行了)。
|| : 逻辑或/短路或,只要一边表达式为true,结果就为true,若左边的表达式为true时会发生短路(右边的表达式不再执行了)。
! : 非/取反,非真true则假false,非假false则真true
// 判断是否为闰年:1.年份能被4整除并且不能被100整除,2.年份能直接被400整除 int year = 2020; 3200 boolean b = (year%4==0 && year%100!=0) || year%400==0; System.out.println(“是否为闰年?” + b);
- 逻辑运算符一般配合关系运算符来使用
- 逻辑运算符的结果为boolean类型
1.4.4 赋值运算符 = += -= *= /= %=
= : 普通赋值运算符
+= -= *= /= %= : 扩展赋值运算符
int a = 10;
a += 20; //相当于: a = a + 20;
- 扩展赋值运算符默认有类型转换的特点
short s1 = 10;
short s2 = 20;
s1 = s1 + s2; //编译错误,short类型运算后的结果是int类型,int不能直接赋给short
s1 += s2; //编译通过,相当于: s1 = (short) (s1 + s2);
1.4.5 三目运算符
三目运算符也叫三元运算符,因为它是由3个表达式组成的。
语法结构:boolean表达式1 ? 表达式2 : 表达式3;
- 三目运算符的执行过程:
- 先判断boolean表达式1
- 若boolean表达式1为true,执行:冒号左边的表达式2,否则执行:冒号右边的表达式3。 //不建议使用,使用if
// 求两个数中的最大值
int a = ?;
int b = ?;
int max = a > b ? a : b;
System.out.println(max);
- 三目运算符可以嵌套,嵌套之后使代码结构不清晰,但是一般不用。
1.4.6 字符串连接符
+ 即可以用来做算数加法运算,也可以用来做字符串的拼接运算。
- 若 + 左右两边都是数字类型时,默认做加法运算;
- 若 + 左右两边只要有字符串类型时,默认做字符串拼接运行;
- 字符串拼接后,结果还是字符串;
int a = 250;
String s1 = “hello”;
String s2 = s1 + a; // “hello”+250 => “hello250”
String str = 5 + 7 + “abc” + 7 + 5;
System.out.println(str); //”12abc75”
1.4.7 位运算符(扩展)
位运算符是针对二进制运算的,常见的位运算符有以下这些:
- & : 位与,两边都是1,结果才是1
- | : 位或,两边都是0,结果才是0
- ~ : 位反,~0=1,~1=0
- ^ : 位异或,一边为1一边为0时,结果才是1
- >> : 位有符号右移,将二进制整体向右边移动,前面补0,保留符号位(正/负)
- << : 位有符号左移,将二进制整体向左边移动,后面补0,保留符号位(正/负)
- >>> : 位无符号右移,将二进制整体向右边移动,前面补0,不保留符号位,移完后都是正数
1.4.8 附:面试题
- & 和 && 的区别?
& 和 && 都可以用来做逻辑运算
a)&是位与运算符,&&是逻辑与运算符
b)&不会发生短路,&&是会发生短路的
2. 使用最有效的方式计算 8/4 的结果?
8 >> 2
00001000 >> 2 = 00000010
1.5 分支结构
Java编程语言中有三种语法结构,分别是:顺序结构、分支结构、循环结构。
分支结构指的是根据条件的判断去决定是否执行某段代码,简单的说就是可以选择性的去执行某些代码。
1.5.1 单路分支
单路分支是指如果条件成立了就去执行指定的代码,否则就不执行。
语法结构:if(条件) { 条件成立时执行的代码... }
int price = ?; if (price >= 500) { System.out.println(“打8折!”); } //超市、 特殊写法: if(price >=500) System.out.println(“打8折!”); //不常用
1.5.2 双路分支
双路分支是指如果条件成立了就去执行指定的第一段代码,否则就去执行指定的第二段代码。场景:一个条件做两件事情
语法结构:
if(条件) { //true/false
第一段代码... true
}else{
第二段代码... flase
}
// 判断年份是否为闰年
int year = 2020;
if (year%4==0 && year%100!=0 || year%400==0) {
System.out.println(year + “是闰年!”);
} else {
System.out.println(year + “不是闰年!”);
}
1.5.3 多路分支(嵌套分支)
多路分支是指在多个条件的判断下,去执行其中条件成立指定的代码。场景:多个条件做多件事情,确定一个范围
语法结构:
if (条件1) {
代码块1
} else if(条件2) {
代码块2
} else if(条件n) {
代码块n
} else {
代码块else
}
// 其实,上面的代码是下面嵌套代码的简写!
if (条件1) {
代码块1
} else {
if(条件2) {
代码块2
} else {
if(条件n) {
代码块n
} else {
代码块else
}
}
}
// 成绩等级判断
int score = ?;
if (score >= 90) {
System.out.println(“A-优秀”);
} else if (score >= 80) {
System.out.println(“B-良好”);
} else if (score >= 70) {
System.out.println(“C-中等”);
} else if (score >= 60) {
System.out.println(“D-及格”);
} else {
System.out.println(“E-不及格”);
}
1.5.4 switch case
switch case 也是用来作为多路分支,优点是速度快,缺点是不够灵活。场景:确定值的时候(不是一个范围)
语法结构:
switch(表达式) {
case 值1:
代码块1;
break;
case 值2:
代码块2;
break;
case 值n:
代码块n;
break;
default:
代码块default;
}
- switch括号中的表达式结果只能是int和String类型。
- case 后面的值一定要是直接量或常量,不能是变量。
- break 用来中断switch语句,也就是不要再执行break后面的代码;注意:如果没有break的话,case将会出现穿透的效果(会一路执行到switch内部代码的最后,或是一路执行到后面遇到的break为止)。
// 模拟取款机程序
int cmd = ?;
switch (cmd) {
case 1:
System.out.println(“查询余额”);
break;
case 2:
System.out.println(“转账”);
break;
case 3:
System.out.println(“取款”);
break;
default:
System.out.println(“输入有误”);
}
1.6 循环结构
循环指的是反复/重复去执行一段相同或相似的代码。
1.6.1 while
语法结构:
while(条件) {
循环体代码块
}
执行流程:
当条件成立,就会循环执行循环体代码块,直到条件不成立为止。
应用场景:
当咱们不知道要循环多少次时,也就是说循环次数不确定时。
1.6.2 do while
语法结构:
do {
循环体代码块
} while(条件);
执行流程:
1、先执行一次循环体代码块
2、当条件成立,则继续循环执行循环体代码块,直到条件不成立为止。
应用场景:
当咱们要先执行一次循环体代码块,再进行循环条件的判断时。
在实际的开发中,do while循环用的较少。
1.6.3 for
语法结构:
for (表达式1; 表达式2; 表达式3) {
循环体代码块
}
说明:
- 表达式1 - 循环变量的初始化
- 表达式2 - 循环的条件
- 表达式3 - 循环变量的改变(注:应该要向着循环结束去改变)
执行流程:
- 先执行表达式1,进行循环变量的初始化操作,注:只执行一次
- 再执行表达式2,进行循环条件的判断
1) 若条件成立,则执行循环体代码块
2) 若条件不成立,则结束循环
- 再执行表达式3,进行循环变量的改变
- 依次第2.和第3.步循环执行
应用场景:
当循环次数固定时,建议使用for循环。
1.6.4 循环的关键字
break 是中断的意思,在循环中使用时,可以使当前循环结束。注:break只能结束一层循环。
continue 是继续的意思,用在循环中,跳过本次循环continue后面的代码,从而进入下一次循环。
int sum = 0;
for(int i = 0; i < 10; i++) {
if(i % 2 == 0){
continue;
}
sum += i;
}
int sum = 0;
for(int i = 0; i < 10; i++) {
if(i == 5){
break;
}
sum += i;
}
System.out.println(sum);
1.6.5 循环的嵌套
循环的嵌套指的是在循环中可以嵌套另一个循环,可以多层嵌套,但是开发中循环的嵌套最好不要超过3层。
// 九九乘法表
for(int i = 1; i <= 9; i++) { //循环9次,控制行数
for(int j = 1; j <= i; j++) { //控制列数,列数跟随行数底层而增加的
System.out.print( i + “*” + j + “=” + (i * j) );
}
System.out.println();
}
说明:
外层循环执行一次,它的内层循环要执行完一轮。
1.7 数组
1.7.1 数组的简介
- 数组是指一组数据的集合,数组中的每个数据称作为元素。
- 数组是一种线性表数据结构,它用一组连续的内存空间,来存储一组具有相同类型的数据。
- 同一个数组中存放的元素的类型必须要一致。
- 在Java中,数组是一种引用数据类型。
1.7.2 数组的声明
声明数组是指告诉Java数组的类型是什么。
// 1.中括号[]写在类型的后面,Java中推荐这种写法
int[] arr;
// 2.中括号[]写在变量名的后面
int arr[];
int[][] arr;
int arr[][];
int[] arr[];
1.7.3 数组的初始化
语法结构:
// 先声明数组
int[] arr;
// 对数组默认初始化
arr = new int[10];
上述代码相当于在内存中定义了10个int类型的变量,第1个变量表示为arr[0],第2个变量表示为arr[1],以此类推,第10个变量表示为arr[9]。其中的0,1,…,9称为数组的下标/索引,下标从0开始,到“数组的长度-1”结束。
当然,除了上面初始化数组的方式外,还可以像下面这样:
// 声明和初始化写在一起,数组中默认每个元素的初始化值为0
int[] arr = new int[10];
// 声明和初始化一起,但是手动指定初始化的值
int[] arr = {1, 2, 3};
// 声明和初始化一起,手动指定好初始化的值,注意:[]中括号中不能再指定长度
int[] arr = new int[]{1, 2, 3};
问题:int[] arr = {1,2,3} 与 int[] arr = new int[]{1,2,3} 的区别?
int[] arr = {1,2,3} 只能声明和初始化写在一起,不能分开写,如:
int[] arr;
arr = {1,2,3}; //编译错误的
int[] arr = new int[]{1,2,3} 可以声明和初始化写在一起,也可以分开,如:
int[] arr;
arr = new int[]{1,2,3}; //编译成功
1.7.4 数组的访问
通过下标/索引来访问元素,数组提供了一个length属性,来获取数组的长度(元素的个数)。
int[] arr = {1, 4, 7, 8};
System.out.println(arr.length); //打印数组的长度:4
arr[0] = 100; //给arr中的第1个数赋值为100,此时:[100, 4, 7, 8]
System.out.println(arr[3]); //输出arr中的最后一个数:8
System.out.println(arr[arr.length-1]); //灵活的输出arr中最后一个元素
arr[4] = 88; //错误的,下标越界/超范围,ArrayIndexOutOfBoundsException
1.7.5 数组的遍历
遍历是指对数组中所有元素的访问,依次对数组中每个元素访问一次。
- 顺序遍历
int[] arr = {1, 4, 7};
for(int i = 0; i < arr.length; i++){
int a = arr[i]; //arr[0], arr[1], arr[2]
System.out.println(a);
}
- 倒序遍历
int[] arr = {1, 4, 7};
for(int i = arr.length - 1; i >= 0; i--){
System.out.println(arr[i]); //arr[2], arr[1], arr[0]
}
- 增强版for循环遍历
int[] arr = {1, 4, 7};
// a表示每次循环从数组中取出的那个元素,arr表示要遍历的数组
for(int a : arr){
System.out.println(a);
}
1.7.6 数组的排序
- 自带排序
int[] arr = {3, 6, 9, 2, 5, 8, 1, 4, 7};
// Arrays.sort(T[] arr) 默认按照升序(从小到大)来排序的
java.util.Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); //打印排序后的数组,[1, 2, 3, 4, 5, 6, 7, 8, 9]
- 冒泡排序(笔试)
int[] arr = {3, 6, 9, 2, 5, 8, 1, 4, 7};
for(int i=0; i<arr.length-1; i++){ //控制趟数
for(int j=0; j<arr.length-1-i; j++){ //控制每趟的次数
//如果当前元素比后一个元素大,则交换位置
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
System.out.println(Arrays.toString(arr)); //打印排序后的数组
1.7.7 数组的工具类
Java中提供了java.util.Arrays工具类,可以对数组进行排序、检索、转换、输出等操作。
Arrays.sort(arr); //对数组进行排序
int index = Arrays.binarySearch(arr, key); //对数组进行二分查找,注:数组中的元素一定是升序的
String str = Arrays.toString(arr); //将数组转换为字符串
int[] newArr = Arrays.copyOf(arr, len); //扩容/缩容 数组
1.8 方法
1.8.1 方法的简介
方法也称为函数/过程,封装的一段特定的逻辑功能、有名字的代码块。
方法可以使程序结构清晰、便于代码的重复使用。
1.8.2 方法的定义
语法结构:
修饰符 返回值类型 方法名 ( [参数类型 参数名1, 参数类型 参数名2, ...] ) {
方法体
[return 返回值;]
}
上述代码的语法格式具体说明如下:
- 修饰符:用于限定方法的声明,常见的有访问控制修饰符、静态修饰符、最终修饰符 等等。
- 返回值类型:用于限定方法返回值的数据类型,为了告诉调用者知道要用什么类型来接收返回结果。
- 参数类型:用于限定调用方法时传入参数的数据类型。
- 参数名:是一个变量,用于接收调用方法时传入的数据。
- return 关键字:用于结束方法以及返回方法指定类型的值。
- 返回值:被return语句返回的数据,该值会返回给调用者。
方法中的“[参数类型 参数名1, 参数类型 参数名2, ...]”称为参数列表,表示方法在调用时需要接收的参数,如果方法不需要接收任何参数,则参数列表为空,即()括号内不写任何内容。
如果方法中没有返回值,那么返回值类型要声明为void,方法中的return语句可以省略。
例如:
//无返回值无参数的方法
public static void sayHi() {
System.out.println("Hi");
}
//有返回值有参数的方法
public static int sum(int a, int b) {
int result = a + b;
return result;
}
//封装冒泡排序算法,方便重复调用
public static void bubbleSort(int[] arr) {
for(int i=0; i<arr.length-1; i++){ //控制趟数
for(int j=0; j<arr.length-1-i; j++){ //控制每趟的次数
//如果当前元素比后一个元素大,则交换位置
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
- 什么时候方法要定义参数?
当方法中要使用到的数据,但是又不能在方法中写死,那么这时就可以把这些数据先定义为方法的参数,让调用者在调用方法时再具体传递过来,参数可以使得方法变得更加灵活。
- 什么时候方法要定义具体返回值类型?
当方法中逻辑计算完成之后,要返回计算的结果给调用者时,那么就得定义具体的返回值类型。
1.8.3 方法的调用
- 无参无返回值方法的调用
方法名();
System.out.println();
- 有参无返回值方法的调用
方法名(参数值..);
System.out.println(250);
- 无参有返回值方法的调用
数据类型 变量名 = 方法名();
double num = Math.random();
- 有参有返回值方法的调用
数据类型 变量名 = 方法名(参数值..);
double sqrt = Math.sqrt(4);
good luck!
- & 和 && 的区别?