Note/青空笔记/JavaSE 笔记(含新特性介绍)/JavaSE笔记(一).md
2023-08-31 11:30:31 +08:00

591 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Java语法规范
所有的Java语句必须以`;`结尾!
无论是`()`、`[]`还是`{}`,所有的括号必须一一匹配!
主方法的代码只能写在`{}`中!
# Java基础语法面向过程
在学习面向对象之前我们需要了解面向过程的编程思维如果你学习过C语言和Python就会很轻松
## 变量和关键字
### 变量
变量就是一个可变的量例如定义一个int类型的变量int就是整数类型
```java
int a = 10;
a = 20;
a = 30;
```
我们能够随意更改它的值,也就是说它的值是随时可变的,我们称为变量。变量可以是类的变量,也可以是方法内部的局部变量(我们现阶段主要用局部变量,类变量在面向对象再讲解)
变量和C语言中的变量不同Java中的变量是存放在JVM管理的内存中C语言的变量存放在内存某些情况下需要手动释放内存而Java会自动帮助我们清理变量占据的内存Java和C++很类似但是没有指针Java也叫C++--
Java是强类型语言只有明确定义了变量之后你才能使用一旦被指定某个数据类型那么它将始终被认为是对应的类型和JS不一样
定义一个变量的格式如下:
```java
[类型] [标识符(名字)] = [初始值(可选)]
int a = 10;
```
注意:标识符不能为以下内容:
* 标识符以由大小写字母、数字、下划线(_)和美元符号($)组成,但是不能以数字开头。
* 大小写敏感!
* 不能有空格、@、#、+、-、/ 等符号
* 应该使用有意义的名称,达到见名知意的目的,最好以小写字母开头
* 不可以是 true 和 false
* 不能与Java语言的关键字重名
### 关键字
![image-20210817150135886](/Users/nagocoler/Library/Application Support/typora-user-images/image-20210817150135886.png)
包括基本数据类型、流程控制语句等,了解就行,不用去记,后面我们会一点一点带大家认识!
### 常量
常量就是无法修改值的变量,常量的值,只能定义一次:
```java
final int a = 10;
a = 10; //报错!
```
常量前面必须添加final关键字C语言里面是const虽然Java也有但是不能使用
这只是final关键字的第一个用法后面还会有更多的用法。
### 注释
养成注释的好习惯,不然以后自己都看不懂自己的代码!注释包括单行注释和多行注释:
```java
//我是单行注释
/**
* 我是
* 多行注释
*/
//TODO 待做标记
```
***
## 基本数据类型
Java中的数据类型分为基本数据类型和引用类型两大类引用类型我们在面向对象时再提基本数据类型是重点中的重点首先我们需要了解有哪些类型。然后我们需要知道的并不是他们的精度如何能够表示的范围有多大而是为什么Java会给我们定义这些类型计算机是怎么表示这些类型的这样我们才能够更好的记忆他们的精度、表示的范围大小。所以我们从计算机原理的角度出发带领大家走进Java的基本数据类型。
这一部分稍微有点烧脑,但是是重中之重,如果你掌握了这些,任何相关的面试题都难不倒你!(如果你学习过计算机组成原理就很好理解了)
### 计算机中的二进制表示
在计算机中所有的内容都是二进制形式表示。十进制是以10为进位如9+1=10二进制则是满2进位因为我们的计算机是电子的电平信号只有高位和低位你也可以暂且理解为通电和不通电高电平代表1低电平代表0由于只有0和1因此只能使用2进制表示我们的数字比如1+1=10=2^1+0一个位也叫一个bit8个bit称为1字节16个bit称为一个字32个bit称为一个双字64个bit称为一个四字我们一般采用字节来描述数据大小。
十进制的7 -> 在二进制中为 111 = 2^2 + 2^1 + 2^0
现在有4个bit位最大能够表示多大的数字呢
* 最小0000 => 0
* 最大1111 => 2^3+2^2+2^1+2^0 => 8 + 4 + 2 + 1 = 15
在Java中无论是小数还是整数他们都要带有符号和C语言不同C语言有无符号数所以首位就作为我们的符号位还是以4个bit为例首位现在作为符号位1代表负数0代表正数
* 最小1111 => -(2^2+2^1+2^0) => -7
* 最大0111 => +(2^2+2^1+2^0) => +7 => 7
现在我们4bit能够表示的范围变为了-7~+7这样的表示方式称为原码。
### 计算机中的加减法
#### 原码
虽然原码表示简单但是原码在做加减法的时候很麻烦以4bit位为例
1+(-1) = 0001 + 1001 = 怎么让计算机去计算?(虽然我们知道该去怎么算,但是计算机不知道!)
我们得创造一种更好的表示方式!于是我们引入了反码:
#### 反码
- 正数的反码是其本身
- 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反
经过上面的定义,我们再来进行加减法:
1+(-1) = 0001 + 1110 = 1111 => -0 (直接相加,这样就简单多了!)
思考1111代表-00000代表+0在我们实数的范围内0有正负之分吗
* 0既不是正数也不是负数那么显然这样的表示依然不够合理
#### 补码
根据上面的问题,我们引入了最终的解决方案,那就是补码,定义如下:
- 正数的补码就是其本身 (不变!)
- 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
其实现在就已经能够想通了,-0其实已经被消除了我们再来看上面的运算
1+(-1) = 0001 + 1111 = (1)0000 => +0 (现在无论你怎么算,也不会有-0了
所以现在4bit位能够表示的范围是-8~+7Java使用的就是补码
`以上内容是重点, 是一定要掌握的知识,这些知识是你在面试中的最终防线!有了这些理论基础,无论面试题如何变换,都能够通过理论知识来破解`
***
### 整数类型
整数类型是最容易理解的类型!既然我们知道了计算机中的二进制数字是如何表示的,那么我们就可以很轻松的以二进制的形式来表达我们十进制的内容了。
在Java中整数类型包括以下几个
* byte 字节型 8个bit也就是1个字节范围-128~+127
* short 短整形16个bit也就是2个字节范围-32768~+32767
* int 整形32个bit也就是4个字节最常用的类型
* long 长整形64个bit也就是8个字节最后需要添加l或L
long都装不下怎么办BigInteger
数字已经达到byte的最大值了还能加吗为了便于理解以4bit为例
0111 + 0001 = 1000 => -8你没看错就是这样
整数还能使用8进制、16进制表示
* 十进制为15 = 八进制表示为017 = 十六进制表示为 0xF = 二进制表示 1111 (代码里面不能使用二进制!)
### 字符类型和字符串
在Java中存在字符类型它能够代表一个字符
* char 字符型16个bit也就是2字节它不带符号范围是0 ~ 65535
* 使用Unicode表示就是\u0000 ~ \uffff
字符要用单引号扩起来!比如 char c = '淦';
字符其实本质也是数字,但是这些数字通过编码表进行映射,代表了不同的字符,比如字符`'A'`的ASCII码就是数字`65`所以char类型其实可以转换为上面的整数类型。
Java的char采用Unicode编码表不是ASCII编码Unicode编码表包含ASCII的所有内容同时还包括了全世界的语言ASCII只有1字节而Unicode编码是2字节能够代表65536种文字足以包含全世界的文字了我们编译出来的字节码文件也是使用Unicode编码的所以利用这种特性其实Java支持中文变量名称、方法名称甚至是类名
既然char只能代表一个字符那怎么才能包含一句话呢关于数组我们这里先不了解数组我们放在面向对象章节讲解
String就是Java中的字符串类型注意它是一个类创建出来的字符串本质是一个对象不是我们的基本类型字符串就像它的名字一样代表一串字符也就是一句完整的话。
字符串用双引号括起来比如String str = "一日三餐没烦恼";
### 小数类型
小数类型比较难理解比较难理解指的是原理不是使用首先来看看Java中的小数类型包含哪些
* float 单精度浮点型 32bit4字节
* double 双精度浮点型64bit8字节
思考:小数的范围该怎么定义呢?我们首先要了解的是小数在计算机里面是如何存放的:
![image-20210817143234500](/Users/nagocoler/Library/Application Support/typora-user-images/image-20210817143234500.png)
根据国际标准 IEEE 754任意一个二进制浮点数 V 可以表示成下面的形式:
V = (-1)^S × M × 2^E
1(-1)^S 表示符号位,当 S=0V 为正数;当 S=1V 为负数。
2M 表示有效数字,大于等于 1小于 2但整数部分的 1 不变因此可以省略。例如尾数为1111010那么M实际上就是1.111010尾数首位必须是11后面紧跟小数点如果出现0001111这样的情况去掉前面的0移动1到首位题外话随着时间的发展IEEE 754标准默认第一位为1故为了能够存放更多数据就舍去了第一位比如保存1.0101 的时候, 只保存 0101这样能够多存储一位数据
32^E 表示指数位。(用于移动小数点)
比如: 对于十进制的 5.25 对应的二进制为101.01相当于1.0101*2^2。所以S 为 0M 为 1.0101E 为 2。所以对于浮点类型最大值和最小值不仅取决于符号和尾数还有它的阶码。我们在这里就不去计算了想了解的可以去搜索相关资料。
思考就算double有64bit位数但是依然存在精度限制如果我要进行高精度的计算怎么办BigDecimal
### 布尔类型
布尔类型boolean只有`true`和`false`两种值也就是要么为真要么为假布尔类型的变量通常用作流程控制判断语句。C语言一般使用0表示false除0以外的所有数都表示true布尔类型占据的空间大小并未明确定义而是根据不同的JVM会有不同的实现。
***
## 类型转换
### 隐式类型转换
隐式类型转换支持字节数小的类型自动转换为字节数大的类型,整数类型自动转换为小数类型,转换规则如下:
* byte→short(char)→int→long→float→double
问题为什么long比float大还能转换为float呢小数的存储规则让float的最大值比long还大只是可能会丢失某些位上的精度
所以,如下的代码就能够正常运行:
```java
byte b = 9;
short s = b;
int i = s;
long l = i;
float f = l;
double d = f;
System.out.println(d);
//输出 9.0
```
### 显示类型转换
显示类型转换也叫做强制类型转换,也就是说,违反隐式转换的规则,牺牲精度强行进行类型转换。
```java
int i = 128;
byte b = (byte)i;
System.out.println(b);
//输出 -128
```
为什么结果是-128精度丢失了
* int 类型的128表示00000000 00000000 00000000 10000000
* byte类型转换后表示xxxxxxxx xxxxxxxx xxxxxxxx 10000000 => -128
### 数据类型自动提升
在参与运算时也可以位于表达式中时自增自减除外所有的byte型、short型和char的值将被提升到int型
``` java
byte b = 105;
b = b + 1; //报错!
System.out.println(b);
```
这个特性是由 **Java虚拟机规范** 定义的,也是为了提高运行的效率。其他的特性还有:
* 如果一个操作数是long型计算结果就是long型
* 如果一个操作数是float型计算结果就是float型
* 如果一个操作数是double型计算结果就是double型
***
## 运算符
### 赋值和算术运算符
赋值运算符`=`是最常用的运算符,其实就是将我们等号右边的结果,传递给等号左边的变量,例如:
```java
int a = 10;
int b = 1 + 8;
int c = 5 * 5;
```
算术运算符也就是我们在小学阶段学习的`+` `-` `*` `/` `%`,分别代表加减乘除还有取余,例如:
```java
int a = 2;
int b = 3;
int c = a * b;
//结果为6
```
需要注意的是,`+`还可以用作字符串连接符使用:
```java
System.out.println("lbw" + "nb"); //lbwnb
```
当然,字符串可以直接连接其他类型,但是会全部当做字符串处理:
```java
int a = 7, b = 15;
System.out.println("lbw" + a + b); //lbw715
```
算术运算符还包括`++`和`--`也就是自增和自减,以自增为例:
```java
int a = 10;
a++;
System.out.println(a); //输出为11
```
自增自减运算符放在变量的前后的返回值是有区别的:
```java
int a = 10;
System.out.println(a++); //10 (先返回值,再自增)
System.out.println(a); //11
```
```java
int a = 10;
System.out.println(++a); //11 (先自增,再返回值)
System.out.println(a); //11
```
```java
int a = 10;
int b = 2;
System.out.println(b+++a++); //猜猜看结果是多少
```
为了使得代码更简洁,你还可以使用扩展的赋值运算符,包括`+=`、`-=`、`/=`、`*=`、`%=`,和自增自减类似,先执行运算,再返回结果,同时自身改变:
```java
int a = 10;
System.out.println(a += 2); //等价于 a = a + 2
```
### 关系运算符
关系运算符的结果只能是布尔类型,也就是要么为真要么为假,关系运算符包括:
```java
> < == //大于小于等于
>= <= != //大于等于,小于等于,不等于
```
关系运算符一般只用于基本类型的比较运算结果只能是boolean
```java
int a = 10;
int b = 2;
boolean x = a > b;
System.out.println(x);
//结果为 true
```
### 逻辑运算符
逻辑运算符两边只能是boolean类型或是关系/逻辑运算表达式返回值只能是boolean类型逻辑运算符包括
```java
&& //与运算要求两边同时为true才能返回true
|| //或运算要求两边至少要有一个为true才能返回true
! //非运算,一般放在表达式最前面,表达式用括号扩起来,表示对表达式的结果进行反转
```
实际案例来看看:
```java
int a = 10;
int b = 2;
boolean x = a > b && a < b; //怎么可能同时满足呢
System.out.println(x); //false
```
```java
int a = 10;
int b = 2;
boolean x = a > b || a <= b; //一定有一个满足!
System.out.println(x); //true
```
```java
int a = 10;
int b = 2;
boolean x = !(a > b); //对结果进行反转本来应该是true
System.out.println(x); //false
```
### 位运算符
```java
& //按位与注意返回的是运算后的同类型值不是boolean
| //按位或
^ //按位异或 0 ^ 0 = 0
~ //按位非
```
按位运算实际上是根据值的二进制编码来计算结果例如按位与以4bit为例
0101 & 0100 = 0100 只有同时为1对应位才得1
```java
int a = 7, b = 15;
System.out.println(a & b); //结果为7
```
### 三目运算符
三目运算符其实是为了简化代码而生,可以根据条件是否满足来决定返回值,格式如下:
```java
int a = 7, b = 15;
String str = a > b ? "行" : "不行"; // 判断条件(只能是boolean,或返回boolean的表达式) ? 满足的返回值 : 不满足的返回值
System.out.println("汉堡做的行不行?"+str); //汉堡做的行不行?不行
```
理解三目运算符就很容易理解后面的if-else语句了。
***
## 流程控制
我们的程序都是从上往下依次运行的但是仅仅是这样还不够我们需要更加高级的控制语句来帮我进行更灵活的控制。比如判断用户输入的数字大于1则输出ok小于1则输出no这时我们就需要用到选择结构来帮助我们完成条件的判断和程序的分支走向。学习过C语言就很轻松
### 选择结构
选择结构包含if和switch类型选择结构能够帮助我们根据条件判断再执行哪一块代码。
#### if语句
就像上面所说判断用户输入的数字大于1则输出ok小于1则输出no要实现这种效果我们首先可以采用if语句
```java
if(判断条件){
//判断成功执行的内容
}else{
//判断失败执行的内容
}
//if的内容执行完成后后面的内容正常执行
```
其中,`else`语句不是必须的。
现在又来了一个新的需求用户输入的是1打印ok输入2打印yes其他打印no那么这样就需要我们进行多种条件的判断了当然if能进行多分支判断
```java
if(判断条件1){
//判断成功执行的内容
}else if(判断条件2){
//再次判断,如果判断成功执行的内容
}else{
//上面的都没成功,只能走这里
}
```
同样,`else`语句不是必须的。
现在又来了一个新的需求用户输入1之后在判断用户下一次输入的是什么如果是1打印yes不是就打印no这样就可以用嵌套if了
```java
if(判断条件1){
//前提是判断条件1要成功才能进来
if(判断条件2){
//判断成功执行的内容
}else{
//判断失败执行的内容
}
}
```
#### switch语句
我们不难发现,虽然`else-if`能解决多分支判断的问题但是效率实在是太低了多分支if采用的是逐级向下判断显然费时费力那么有没有一直更专业的解决多分支判断问题的东西呢
```java
switch(判断主体){
case 值1:
//运行xxx
break; //break用于跳出switch语句不添加会导致程序继续向下运行
case 值2:
//运行xxx
break;
case 值3:
//运行xxx
break;
}
```
在上述语句中只有判断主体等于case后面的值时才会执行case中的语句同时需要使用break来跳出switch语句否则会继续向下运行
为什么switch效率更高呢因为switch采用二分思想进行查找这也是为什么switch只能判断值相等的原因能够更快地找到我们想要的结果
### 循环结构
小明想向小红表白于是他在屏幕上打印了520个 "我爱你"我们用Java该如何实现呢
#### for语句
for语句是比较灵活的循环控制语句一个for语句的定义如下
```java
for(初始条件;循环条件;更新){
//循环执行的内容
}
//循环结束后,继续执行
```
* 初始条件:循环开始时的条件,一般用于定义控制循环的变量。
* 循环条件每轮循环开始之前进行一次判断如果满足则继续不满足则结束要求为boolean变量或是boolean表达式。
* 更新:每轮循环结束后都会执行的内容,一般写增量表达式。
初始条件、循环条件、更新条件不是缺一不可,甚至可以都缺!
```java
for(int i = 0;i < 520;i++){
System.out.println("我爱你");
}
```
```java
for(;;){
//这里的内容将会永远地进行下去!
}
```
增强for循环在数组时再讲解
#### while循环
while循环和for循环类似但是它更加的简单只需要添加维持循环的判断条件即可
```java
while(循环条件){
//循环执行的内容
}
```
和for一样每次循环开始当循环条件不满足时自动退出那么有时候我们希望先执行了我们的代码再去判断怎么办呢我们可以使用do-while语句
```java
do{
//执行内容
}while(循环条件);
```
一定会先执行do里面的内容再做判断
思考:
```java
for(;;){
}
while(true){
}
//它们的性能谁更高?
```
***
## 面向过程编程实战(基础+算法)
### 打印九九乘法表
简单:将九九乘法表打印到控制台。
### 求1000以内的水仙花数
中等打印1000以内所有满足水仙花的数“水仙花数”是指一个三位数其各位数字的立方和等于该数本身例如153是“水仙花数”因为153 = 1^3 + 5^3 + 3^3
### 青蛙跳台阶问题
困难一共有n个台阶一只青蛙每次只能跳一阶或是两阶那么一共有多少种跳到顶端的方案例如n=2那么一共有两种方案一次性跳两阶或是每次跳一阶。
动态规划:其实,就是利用,上次得到的结果,给下一次作参考,下一次就能利用上次的结果快速得到结果,依次类推
***
不对啊,别的教程都讲了数组、方法,怎么我们还没讲就进入面向对象了呢?
* 数组在Java中并非基本类型数组是编程不可见的对象类型学习了面向对象再来理解会更加容易
* 方法在Java中是类具有的属性所以在了解了对象类型之后再来了解方法就更加简单了