Java 编程的逻辑笔记
Java 编程的逻辑
编程基础
程序:基本上就是告诉计算机要操作的数据和执行的指令序列,即对什么数据做什么操作
数据类型和变量
- 整数类型:byte/short/int/long(取值范围1/2/4/8)
- 小数类型:float/double(不同的取值范围和精度)
- -字符类型:char(单个字符)
- 真假类型:boolean(真假)
变量:给数据起名字,方便找不同的数据,它的值可以变,但含义不应变。
数组类型
三种赋值形式
1 | int[] arr = {1,2,3}; |
数组长度确定后不可变
默认值:数值类型的值为0, boolean为false, char为空字符
数组内存空间:一个基本类型变量,内存中只会有一块对应的内存空间。但数组有两块:一块用于存储数组内容本身,另一块用于存储内容的位置。
基本运算
算术运算
- 运算时要注意结果的范围,使用恰当的数据类型
- 小数计算结果不精确
比较运算
- (a++)是先用原来的值进行其他操作,然后再对自己做修改
- (++a)是先对自己做修改,再用修改后的值进行其他操作。
逻辑运算
-
与(&):两个都为true才是true,只要有一个是false就是false;
-
或(|):只要有一个为true就是true,都是false才是false;
-
非(!):针对一个变量,true会变成false,false会变成true;
-
异或(^):两个相同为false,两个不相同为true;
条件执行
if语句
1 | if(判断条件){ |
在if/else if/else中,判断的顺序是很重要的,后面的判断只有在前面的条件为false的时候才会执行
三元运算符
1 | 判断条件?表达式1:表达式2 |
switch
1 | switch(表达式){ |
表达式值的数据类型只能是byte、short、int、char、枚举和String(Java 7以后 ) break是指跳出switch语句
实现原理
程序最终都是一条条的指令,CPU有一个指令指示器,指向下一条要执行的指令.有一些特殊的指令,称为跳转指令,这些指令会修改指令指示器的值,让CPU跳到一个指定的地方执行。跳转有两种:一种是条件跳转;另一种是无条件跳转。条件跳转检查某个条件,满足则进行跳转,无条件跳转则是直接进行跳转。
if、if/else、if/else if/else、三元运算符都会转换为条件跳转和无条件跳转,
switch的转换和具体系统实现有关。
- 分支比较少:跳转指令
- 分支比较多:跳转表( key为条件值(编译器会自动排序,方便二分查找),value 为跳转地址)
跳转表中如果值是连续的,则优化为一个数组,连找都不用找了
因为需要排序所以switch类型需要支持排序(byte/short/int/string(通过hashCode))
不支持Long(跳转表值的存储空间一般为32位,容纳不下long)
条件执行的本质依赖于条件跳转、无条件跳转和跳转表。
循环
多次重复执行某些类似的操作
while
1 | while(条件语句){ |
do/while
1 | do{ |
条件语句是什么,代码块都会至少执行一次
for
1 | for(初始化语句;循环条件;步进操作){ |
循环条件必须返回一个boolean类型外,其他语句没有什么要求(甚至可以为空 for(;;))
执行的流程:
- 执行初始化指令;
- 检查循环条件是否为true,如果为false,则跳转到第6步;
- 循环条件为真,执行循环体;
- 执行步进操作;
- 步进操作执行完后,跳转到第2步,即继续检查循环条件;
- for循环后面的语句。
foreach
1 | for(int element :arr){ |
循环控制
break:提前结束循环
continue:跳过循环体中剩下的代码,然后执行步进操作
实现原理
和if一样,循环内部也是靠条件转移和无条件转移指令实现的,在if中,跳转只会往后面跳,而for会往前面跳,第6行就是无条件跳转指令。break/continue语句也都会转换为跳转指令。
解决复杂问题的基本策略是分而治之,将复杂问题分解为若干相对简单的子问题,然后子问题再分解为更小的子问题……
函数的用法
使用函数来减少重复代码和分解复杂操作。
1 | 修饰符 返回值类型 函数名字(参数类型 参数名字,...){ |
返回值:函数可以没有返回值,如果没有返回值则类型写成void,如果有则在函数代码中必须使用return语句返回一个值,这个值的类型需要和声明的返回值类型一致。
Main函数表示程序的入口;
在函数中修改数组元素内容和在调用者中修改是完全一样的。
return可以用于函数内的任意地方
需要的返回值是一种复合结果时可以使用对象;
同一个类里,函数可以重名,但参数不同(重载).Java编译器会自动进行类型转换,并寻找最匹配的函数
调用自己的函数就叫递归函数(递归层数过多会爆栈,栈溢出错误)
递归其实是有开销的,而且使用不当,可能会出现意外的结果,可以通过循环实现
通过函数来减少重复代码、分解复杂操作是计算机程序的一种重要思维方式。
基本原理
- 从main函数开始顺序执行
- 函数调用可以看作一个无条件跳转
- 跳转到对应函数的指令处开始执行
- 碰到return语句或者函数结尾的时候,再执行一次无条件跳转
- 跳转回调用方,执行调用函数后的下一条指令。
计算机系统主要使用内存中的栈来存放函数调用过程中需要的数据,包括参数、返回地址,以及函数内定义的局部变量。
使用CPU内的一个存储器存储返回值
代码及对于栈执行情况
数组和对象类型,实际的内容空间一般不是分配在栈上的,而是分配在堆。
递归调用
递归函数的执行过程,函数代码虽然只有一份,但在执行的过程中,每调用一次,就会有一次入栈,生成一份不同的参数、局部变量和返回地址。
每一次调用都需要分配额外的栈空间用于存储参数、局部变量以及返回地址,需要进行额外的入栈和出栈操作。
递归的次数比较多时,应该考虑其他方式。
个人思考
第一章整体看下来发现还是有一些比较基础的东西都遗忘了,比如说居然都忘记还有short这个数据类型,主要是平时用的比较少,像循环基本都是用for,其他两种真的很少用。蛮喜欢基本原理这一部分,即使是最基础的,一章看下来也能学到东西。
理解数据背后的二进制
字符的编码与乱码
常见非Unicode编码
ASCII:美国大概只需要128个字符,所以就规定了128个字符的二进制表示方法。这个方法是一个标准,称为ASCII编码
ISO 8859-1:它也是使用一个字节表示一个字符,其中0~127与ASCII一样,128~255规定了不同的含义。在128~255中,128~159表示一些控制字符,以及被Windows-1252取代。
Windows-1252:与ISO 8859-1基本是一样的,区别只在于数字128~159.
GB2312:GB2312标准主要针对的是简体中文常见字符,包括约7000个汉字和一些罕用词和繁体字。
GBK:在GB2312的基础上,向下兼容GB2312。GBK增加了14 000多个汉字。