当当!更新笔记啦!
关键字和保留字
-
保留字(reserved word)
-
java保留字:现有Java版本尚未使用,但以后版本可能会作为关键字使用。自己命名标识符时要避免使用这些保留字。
-
goto const
-
标识符
注:如果不遵守标识符的命名规则,编译不通过!需严格遵守。
如果不遵守标识符的命名规范,编译通过!建议大家遵守。
变量
-
概念:
-
内存中的一个存储区域
-
该区域的数据可以在同一类型范围内不断变化
-
变量是程序中最基本的存储单元,包含变量类型、变量名和存储的值
-
-
定义变量的格式:
-
数据类型 变量名 = 变量值;
-
-
注意:
-
Java中每个变量必须先声明,后使用
-
使用变量名来访问这块区域的数据
-
变量的作用域:其定义所在的一对{}内
-
变量只有在其作用域内才有效
-
同一个作用域内,不能定义重名的变量
-
-
分类:
-
按数据类型:
-
基本数据类型:
- 整型:byte(1字节) \ short(2字节) \ int(4字节) \ long(8字节)
-
注:
-
byte 范围:-128 ~127
-
声明long型变量,必须以“l”或“L”结尾
-
通常,定义整型变量时,使用int型。
-
-
浮点型:float \ double
-
浮点型常量的表示类型:十进制数形式(如5.12)和科学计数法形式(如5.12e2)
-
说明:
-
float:单精度,尾数可以精确到7位有效数字,很多情况下,精度很难满足需求。
-
double:双精度,精度是float的两倍。通常采用此类型。
-
-
-
字符型:char
-
定义char型变量,通常使用一对‘ ’,内部只能写一个字符
-
表示方法:
-
声明一个字符
-
转义字符
-
直接使用Unicode值来表示字符型常量(少用)
-
-
-
布尔型:boolean
-
只能取两个值之一: true \ false
-
常常在条件判断、循环结构中使用
-
-
-
-
-
引用数据类型:
-
类(class)
-
接口(interface)
-
数组(array)
-
-
按在类中声明的位置:
-
成员变量
-
局部变量
-
成员变量与局部变量的区别
-
-
基本数据类型之间的运算规则
-
前提:这里讨论的只是7种基本数据类型变量间的运算,不包含boolean类型的。
-
自动类型提升:
-
结论:当容量小的数据类型的变量与容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型。
-
byte、char、short --> int --> long --> float --> double
-
特别地,当byte、char、short三种类型的变量做运算时,结果为int型
-
-
强制类型转换(自动类型提升的逆运算):
-
需要使用强转符:()
-
注意点:强制类型转换,可能导致精度损失(截断操作)
-
-
说明:此时的容量大小指的是,表示数的范围的大和小。比如,float容量要大于long的容量
-
特殊情况:
-
整型常量,默认类型为int型
-
浮点型常量,默认类型为double型
-
-
String类型变量的使用
-
String属于引用数据类型
-
声明String类型变量时,使用一对“ ”
-
String可以和8种基本数据类型变量做运算,且运算只能是连接运算:+(连接符号)
-
注:根据+号左右两边的数据的数据类型来决定+号是连接符号还是运算符号。
-
运算的结果仍然是String类型
-
作用:
-
用于在内存中保存数据
-
-
-
运算符
2.1.4 运算符(一种特殊的符号,用以表示数据的运算,赋值和比较等)
算术运算符
-
注:
-
%(取余运算):结果的符号与被模数的符号相同;开发中,经常使用%来判断能否被除尽的情况。
-
自增1不会改变本身变量的数据类型
赋值运算符
-
符号:=
-
当“=”两侧数据类型不一致时,可以使用自动类型转换或使用强制类型转换原则进行处理。
-
支持连续赋值。
-
-
扩展赋值运算符:+=,-=,*=,/=,%=
Int num1 = 10; num1=num1+2;//num1+=2;两种写法相同。 Short num2 = 10; num2=num2+2;//编译不通过 //num2+=2;//不会改变变量本身的数据类型 //此时两者不相同。 //注意:不能(num++)++;也不能num++++;
比较运算符(关系运算符)
逻辑运算符
-
说明:
-
逻辑运算符操作的都是boolean类型的变量
-
区分 & 与 &&
-
相同点1:& 与 && 的运算结果相同
-
相同点2:当符号左边是true时,二者都会执行符号右边的运算
-
不同点:当符号左边是false时,&继续执行符号右边的运算;&&不再执行符号右边的运算。
-
开发中,推荐使用&&
-
-
区分 | 与 ||
-
相同点1:| 与 || 的运算结果相同
-
相同点2:当符号左边是false时,二者都会执行符号右边的运算
-
不同点:当符号左边是true时,|继续执行符号右边的运算,而||不再执行符号右边的运算
-
开发中,推荐使用||
-
-
位运算符(少用)
-
结论:
-
位运算符操作的都是整型的数据
-
<<:在一定范围内,每向左移1位,相当于 * 2
-
>>:在一定范围内,每向右移1位,相当于 / 2
-
三元(目)运算符
-
格式:(条件表达式)?表达式1:表达式2;
-
说明:
如果表达式为true,则执行表达式1,
如果表达式为false,则执行表达式2.
-
条件表达式的结果为boolean类型
-
根据条件表达式真或假,决定执行表达式1,还是表达式2.
-
表达式1与表达式2要求是一致的。
-
三元运算符可以嵌套使用。
-
-
凡是可以使用三元运算符的地方,都可以改写为if-else。反之,不成立。
-
如果程序既可以使用三元运算符,又可以使用if-else结构,那么优先选择三元运算符。原因:简洁、执行效率高。
运算符的优先级
-
程序流程控制
-
流程控制语句是用来控制程序中各语句执行顺序的语句,可以把语句组合成能完成一定功能的小逻辑模块。
-
其流程控制方式采用结构化程序设计中规定的三种基本流程结构,即:
顺序结构
分支结构
if-else结构(条件判断结构):
switch-case结构
-
循环结构
for循环的结构
for(初始化部分;循环条件;迭代部分){ 循环体 }
while循环的使用:
① while(②){ ③; ④;(写while循环千万小心不要丢了迭代条件。一旦丢了,就可能导致死循环!) }
do-while循环的使用
① do{ ③; ④; }while(②);
方式1:循环条件部分返回false
方式2:在循环体中,执行break
嵌套循环的使用
特殊关键字break和continue的使用
带标签的break和continue的使用
-
-
程序从上到下逐行地执行,中间没有任何判断和跳转。
-
根据条件,选择性地执行某行代码。
-
有if...else和switch-case两种分支语句。
-
说明:
-
else结构是可选的。
-
针对于条件表达式:
-
如果多个条件表达式之间是“互斥”关系(或没有交集的关系),哪个判断和执行语句声明在上面还是下面,无所谓。
-
如果多个条件表达式之间有交集的关系,需要根据实际情况,考虑清楚应该将哪个结构声明在上面。举例如下:
-
如果多个条件表达式之间有包含的关系,通常情况下,需要将范围小的声明在范围大的上面,否则,范围小的就没机会执行了。
-
if-else结构是可以相互嵌套的。
-
如果if-else结构中的执行语句只有一行时,对应的{}可以省略。但是,不建议大家省略。
-
-
-
说明:
-
根据switch表达式中的值,依次匹配各个case中的常量,一旦匹配成功,则进入相应的case结构中,直到遇到break关键字或此switch-case结构末尾结束为止。
-
break,可以使用在switch-case结构中,表示一旦执行到此关键字,就跳出switch-case结构
-
switch结构中的表达式,只能是如下的6种数据类型之一:byte 、short 、char 、int 、枚举类型(JDK5.0新增)、String类型(JDK7.0新增)
-
case之后只能声明常量,不能声明范围。
-
break关键字是可选的
-
default:相当于if-else结构中的else,是可选的,而且位置是灵活的。
-
-
if-else与switch-case
-
凡是可以使用switch-case的结构,都可以转换为if-else,反之,不成立。
-
写分支结构时,当发现既可以使用switch-case,(同时,switch中表达式的取值情况不太多),又可以使用if-else时,我们优先选择使用switch-case。原因:switch-case执行效率稍高。
-
-
根据循环条件,重复性地执行某段代码。
-
有while、do...while、for三种循环语句。
-
循环结构的4个要素:
-
初始化部分
-
循环条件 -->是boolean类型
-
循环体
-
迭代部分
-
-
执行过程:① ~ ② ~ ③ ~ ④ ~ ② ~ ③ ~ ④ ~ ... ~②
-
注意break关键字的使用:一遇到break就跳出循环。
-
执行过程:① ~ ② ~ ③ ~ ④ ~ ② ~ ③ ~ ④ ~ ... ~②
-
注:
-
我们写程序时,要避免出现死循环。
-
for循环和while循环是可以相互转换的!
-
区别:for循环和while循环的初始化条件部分的作用范围不同。
-
-
执行过程:① ~③ ~ ④ ~ ② ~ ③ ~ ④ ~ ② ~ ③ ~ ④ ~ ... ~②
-
说明:
-
do-while循环至少会执行一次循环体!
-
开发中,使用for和while更多一些,较少使用do-while
-
-
不在循环条件部分限制次数的结构:for(;;)或while(true)
-
结束循环有几种方式?
-
嵌套循环:将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环。
-
外层循环:循环结构B
-
内层循环:循环结构A
-
说明:
-
内层循环结构遍历一遍,只相当于外层循环循环体执行了一次
-
假设外层循环需要执行m次,内层循环需要执行n次,此时内层循环的循环体一共执行了m*n次
-
-
技巧:外层循环控制行数,内层循环控制列数
-
使用范围:
-
break:switch-case;循环结构中(结束当前循环)(默认跳出包裹此关键字最近的一层循环)
-
continue:循环结构中(结束当次循环)(结束当前包裹此关键字最近的一层循环)
-
-
-
-
注:JDK1.5提供了foreach循环,方便的遍历集合、数组元素。
-
数组
数组(可以用来存储同种数据类型的多个值):
数组的静态初始化
-
初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。
-
数组定义格式:
-
格式1:数据类型[ ] 数组名
-
范例:int[ ] array;
-
格式2:数据类型 数组名[ ]
-
范例:int array[ ];
-
-
数组的静态初始化格式:
-
完整格式:数据类型[ ] 数组名 = new 数据类型[ ]{元素1,元素2,元素3...};
-
简化格式:数据类型[ ] 数组名 = {元素1,元素2,元素3...};
-
-
打印数组名:[I@1b6d3586
@ :分隔符
[ :当前空间,是数组类型的
I:当前数组类型,是int类型
1b6d3586:数组的十六进制内存地址
数组元素访问
-
格式:数组名[索引](索引:是数组容器中空间的编号,编号从0开始,逐个+1增长)
数组遍历操作
-
数组遍历:将数组中所有的内容取出来,取出来之后可以(打印,求和,判断..)
-
数组的属性之一:数组名.length:动态获取到数组的长度(元素的个数)
for(int i = 0;i < arr.lengthl;i++){ System.out.println(arr[i]); }//快捷键 :数组名.fori
-
数组遍历的场景:如果要完成的需求,是需要操作到数组中的【每一个】元素,就需要对数组进行遍历操作
数组动态初始化
-
动态初始化:初始化时只指定数组的长度,由系统为数组分配初始值(默认值)。
-
格式:数据类型[ ] 数组名 = new 数据类型[数组长度];
-
范例:int[ ] arr = new int[3];
-
默认值的分类:
-
整数:0
-
小数:0.0
-
布尔:false
-
字符:'\u0000' ---> Unicode字符 ---> 常见的体现是空白字符
-
引用数据类型(String属于类):null
-
两种初始化的对比和使用选择:
-
区别:
-
动态初始化:手动指定数组长度,由系统给出默认初始化值。
-
静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度。
-
-
两种初始化的使用选择:
-
静态初始化:如果要操作的数据,需求中已经明确给出了,直接静态初始化。
-
动态初始化:只明确元素个数,不明确具体数值
-
数组内存图
-
Java内存分配介绍:
-
Java虚拟机的内存可以分为三个区域:
-
栈stack
2. JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
3. 栈属于线程私有,不能实现线程间的共享!
4. 栈的存储特性是“先进后出,后进先出”
5. 栈是由系统自动分配,速度快!栈是一个连续的内存空间!
-
特点:
1.栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
-
-
堆heap
2. JVM只有一个堆,被所有线程共享
3. 堆是一个不连续的内存空间,分配灵活,速度慢!
-
特点:
1.堆用于存储创建好的对象和数组(数组也是对象)
-
-
方法区method area(又叫静态区)
-
特点:
1.JVM只有一个方法区,被所有线程共享!
2. 方法区实际也是堆,只是用于存储类、常量相关的信息!
3. 用来存放程序中永远是不变或唯一的内容。(类信息【Class对象】、静态变量、字符串常量等)
-
-
-
-
两个数组指向相同内存图
数组拷贝
-
System类里也包含了一个static void arraycopy(object src,int srcpos,object dest, int destpos,int length)方法,
-
该方法可以将src数组里的元素值赋给dest数组的元素,其中srcpos指定从src数组的第几个元素开始赋值,length参数指定将src数组的多少个元素赋给dest数组的元素。
java.util.Arrays类
-
说明:JDK提供的java.util.Arrays类,包含了常用的数组操作
-
包含:
-
排序
-
数组元素是基本数据类型:Arrays.sort(数组名)
-
数组元素是引用数据类型(Comparable接口的应用):
import java.util.Arrays; public class Test { public static void main(String[] args) { Man[] msMans = { new Man(3, "a"), new Man(60, "b"), new Man(2, "c") }; Arrays.sort(msMans); System.out.println(Arrays.toString(msMans)); } } class Man implements Comparable { int age; int id; String name; public Man(int age, String name) { super(); this.age = age; this.name = name; } public String toString() { return this.name; } public int compareTo(Object o) { Man man = (Man) o; if (this.age < man.age) { return -1; } if (this.age > man.age) { return 1; } return 0; } }
-
-
查找(二分法查找)
import java.util.Arrays; public class Test { public static void main(String[] args) { int[] a = {1,2,323,23,543,12,59}; System.out.println(Arrays.toString(a)); Arrays.sort(a); //使用二分法查找,必须先对数组进行排序; System.out.println(Arrays.toString(a)); //返回排序后新的索引位置,若未找到返回负数。 System.out.println("该元素的索引:"+Arrays.binarySearch(a, 12)); } }
-
填充
import java.util.Arrays; public class Test { public static void main(String[] args) { int[] a= {1,2,323,23,543,12,59}; System.out.println(Arrays.toString(a)); Arrays.fill(a, 2, 4, 100); //将2到4索引(即索引为2和3)的元素替换为100; System.out.println(Arrays.toString(a)); } }
-
打印内容(Arrays.toString(数组名))(注意:此处的Arrays.toString()方法是Arrays类的静态方法,不是前面讲的Object的toString()方法)
-
等常见的操作
-
数组常见问题
-
索引越界异常:ArrayIndexOutOfBoundsException
-
原因:访问了不存在的索引
-
-
空指针异常:NullPointerExceptionf
-
当引用数据类型变量被赋值为null之后,地址的指向被切断,还继续访问堆内存数据,就会引发空指针异常。
-
2.1.7 二维数组
二维数组介绍
-
二维数组是一种容器,该容器用于存储一维数组
-
使用思路:今后若要操作的多组数据,属于同一组数据,就可以考虑使用二维数组进行维护
二维数组静态初始化
-
完整格式:数据类型[ ][ ] 数组名 = new 数据类型[ ][ ] {{元素1,元素2},{元素1,元素2}};
-
范例:int[ ][ ] arr = new int[ ][ ]{{11,22},{33,44}};
-
简化格式:数据类型[ ][ ] 数组名 = {{元素1,元素2},{元素1,元素2}};
-
范例:int[ ][ ] arr = {{11,22},{33,44}};
-
打印数组名:
-
打印二维数组名:为二维数组的地址
-
打印 二维数组名[i] :为其存储的一维数组的地址
-
-
二维数组在存储一维数组的时候,具体存储的是一维数组的地址值
-
二维数组的元素访问格式:
-
数组名[m索引][n索引];
-
m索引:指定访问哪一个一维数组
-
n索引:访问一维数组中的哪一个元素
-
二维数组遍历
-
先遍历二维数组,获取到每一个一维数组;
-
继续遍历一维数组,获取具体的元素。
public static void printArray(int[][] arr){ //1、遍历二维数组,获取到每一个一维数组 for(int i = 0;i < arr.length;i++){ //arr[i]:每一个一维数组 //2、继续遍历一维数组,获取具体的元素 for(int j = 0;j < arr[i].length;j++){ System.out.println(arr[i][j]); } } }
二维数组动态初始化
-
格式:数据类型[ ][ ] 数组名 = new 数据类型[m][n];
m表示这个二维数组,可以存放多少个一维数组
n表示每一个一维数组,可以存放多少个元素
-
范例:int[ ][ ] arr = new int[2][3];
二维数组内存图
2.1.8 递归:
-
即:自己调用自己
-
递归结构包括两个部分:
-
定义递归头(即:什么时候不调用自身方法,也就是递归的结束条件。)
-
递归体(即:什么时候需要调用自身方法。)
-
-
举例如下:
-
递归的缺陷:
-
会占用大量的系统堆栈,内存耗用多,在递归调用层次多时速度要比循环慢的多(所以在使用递归时要慎重)。
-
-
注意事项:
-
任何能用递归解决的问题也能使用迭代解决。当递归方法可以更加自然地反映问题,并且易于理解和调试,并且不强调效率问题时,可以采用递归;
-
在要求高性能的情况下尽量避免使用递归,递归调用既花时间又耗内存。
-