01.Java基础
Java 基础
JDK 和 JRE
-
JDK 是什么?有哪些内容组成?
JDK 是 Java 开发工具包
-
JVM 虚拟机: Java 程序运行的地方
-
核心类库: Java 已经写好的东西,可以直接用
-
开发工具: Javac、Java、jdb、jhat…
-
-
JRE 是什么?有哪些内容组成?
- JRE 是 Java 运行环境
- JVM、核心类库、运行工具
-
JDK,JRE,JVM三者的包含关系
-
JDK 包含 JRE
-
JRE 包含 JVM
-
运算符
算术运算符
-
隐式转换(自动类型提升)
-
把一个取值范围小的数值,转成取值范围大的数据
-
取值范围: double > float > long > int > short > byte
-
取值范围小的,和取值范围大的进行运算,小的会先提升为大的,再进行运算
-
byte short char 三种类型的数据在运算时,都会直接先提升为 int ,然后再进行运算
1
2
3byte a = 10;
byte b = 20;
数据类型? c = a + b; // a 和 b 为 byte, 在运算时提升为 int, 故此时数据类型为 int.
-
-
强制转换
-
把一个取值范围大的数值,转成取值范围小的数据
-
目标数据类型 变量名 = (目标数据类型) 被强转的数据;
-
-
字符串的 “+” 操作
-
当 “+” 操作中出现字符串时, 这个 “+” 是字符串连接符, 而不是算术运算符了, 会将前后的数据进行拼接, 并产生一个新的字符串
-
连续进行 “+” 操作时, 从左到右逐个执行
-
System.out.println(1 + 2 + "abc" + 2 + 1); // "3abc21"
-
自增自减运算符
-
参与计算: 后缀(a++ 先用后加), 前缀(++a 先加后用)
逻辑运算符
-
普通逻辑运算符: &, |, ^, !
-
短路逻辑运算符: &&, ||
原码反码补码
-
原码
- 十进制数据的二进制表现形式, 最左边是符号位, 0为正, 1为负
- 弊端: 利用原码进行计算时, 如果是正数没有问题, 但如果是负数计算, 结果会出错, 实际运算方向跟正确的运算方向相反
-
反码
- 为了解决原码不能计算负数的问题而出现的
- 正数的反码不变, 负数的反码在原码的基础上, 符号位不变, 数值取反, 0变1, 1变0
- 弊端: 负数运算时, 如果结果不跨0, 没有问题, 但如果结果跨0, 跟实际结果会有1的偏差
-
补码
-
为了解决负数计算时跨0的问题而出现的
-
正数补码不变, 负数的补码在反码的基础上 +1, 另外补码还能多记录一个特殊的值 -128, 该数据在1个字节下, 没有原码和反码
-
计算机的存储和计算都是以补码的形式进行的
-
该知识可以解释类型转换
其他运算符
运算符 | 含义 | 运算规则 |
---|---|---|
& | 逻辑与 | 0为false, 1为true |
| | 逻辑或 | 0为false, 1为true |
<< | 左移 | 向左移动, 低位补0 |
>> | 右移 | 向右移动, 高位补0或1(看符号) |
>>> | 无符号右移 | 向右移动, 高位补1 |
判断和循环
switch
-
default不一定写在最下面, 可写在任意位置, 但仍是最后执行
-
case穿透: 首先会拿小括号中表达式的值跟下面每一个case进行匹配, 如果匹配上了, 就会执行对应的语句体, 如果此时发现了break, 那么结束整个switch语句, 如果没发现break, 那么程序会继续执行下一个case的语句体, 一直遇到break或右大括号为止
JDK12新特性:
1
2
3
4
5
6 switch (number) {
case 1 -> System.out.println("1");
case 2 -> System.out.println("2");
case 3 -> System.out.println("3");
default -> System.out.println("无");
}默认case语句体内有break
-
switch 和 if 的使用场景
- if: 一般用于对范围的判断
- switch: 把有限个数据一一列举出来选择
for 与 while 的区别
-
for 循环中, 控制循环的变量, 因为归属 for 循环的语法结构中, 在 for 循环结束后, 就不能再次被访问到了
-
while 循环中, 控制循环的变量, 对于 while 循环来说不归属其语法结构中, 在 while 循环结束后, 该变量还可以继续使用
数组
初始化
-
在内存中为数组容器开辟空间, 并将数据存入容器中的过程
-
静态初始化
- 数据类型[] 数组名 = new 数据类型[] { 元素1, 元素2, 元素3…}
- 简化后: 数据类型[] 数组名 = { 元素1, 元素2, 元素3…}
- 范例:
int[] array = new int[] {11, 22, 33};
- 简化后:
int[] array = {11, 22, 33};
-
动态初始化
- 数据类型[] 数组名 = new 数组类型[数组长度]
- 范例:
int[] array = new int[3];
- 数组默认初始化规律
- 整数类型: 默认为 0
- 小数类型: 默认为 0.0
- 字符类型: 默认为 ‘/u0000’ (空格)
- 布尔类型: 默认为 false
- 引用数据类型: 默认为 null
地址值
-
数组地址值表示数组在内存中的位置
-
以
[D@776ec8df
为例- [ : 表示当前是一个数组
- D: 表示当前数组里面的元素都是double类型的
- @: 表示一个间隔符号 (固定格式)
- 776ec8df: 数组真正的地址值 (十六进制)
遍历数组
-
在 IDEA 自动生成数组的遍历方式:
数组名.fori
内存图
-
栈: 方法运行时使用的内存, 比如 main 方法运行, 进入方法栈中执行
-
堆: 存储对象或者数组, new 来创建的, 都存储在堆内存中
-
方法区: 存储可以运行的 class 文件
-
本地方法栈: JVM 在使用操作系统功能的时候使用, 和我们开发无关
-
寄存器: 给 CPU 使用, 和我们开发无关
从JDK8开始, 取消方法区, 新增元空间, 把原来方法区的多种功能进行拆分, 有的功能放到了栈中, 有的功能放到了元空间中
-
当两个数组指向同一个小空间时, 其中一个数组对小空间中的值发生了改变, 那么其他数组再次访问的时候都是修改之后的结果了
拓展: 思考二维数组内存图 (静态初始化, 动态初始化, 动态初始化的两种特例)
方法
程序中最小的执行单元
形参与实参
-
形参: 形式参数, 方法定义中的参数
-
实参: 实际参数, 方法调用中的参数
注意事项
-
方法之间是平级关系, 不能相互嵌套定义
重载
-
在同一个类中, 定义了多个同名的方法, 这些同名的方法具有同种功能
-
每个方法具有不同的参数类型或参数个数, 这些同名的方法构成重载关系
-
同一个类中, 方法名相同, 参数不同的方法. 与返回值无关
- 参数不同: 个数不同, 类型不同, 顺序不同
1
2
3
4
5
6
7
8
9// 不构成重载关系, 因为未满足参数不同这个要求
public class MethodDemo {
public static void fn(int a) {
// 方法体
}
public static int fn(int a) {
// 方法体
}
} -
虚拟机通过参数的不同来区分同名的方法
方法的内存
-
基本数据类型: 整数类型, 浮点数类型, 布尔类型, 字符类型
- 数据值是存储在自己的空间中
- 赋值给其他变量, 也是赋值真实的值
-
引用数据类型: 需要
new
创造的- 数据值是存储在其他空间中, 自己空间中存储的是地址值
- 赋值给其他变量, 赋值的是地址值
方法的值传递
-
传递基本数据类型的内存原理
-
传递基本数据类型时, 传递的是真实的数据, 形参的改变, 不影响实参的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public class ArgsDemo01 {
public static void main(String[] args) {
int number = 100;
sout("调用change方法前: " + number);
change(number);
sout("调用change方法后: " + number);
}
public static void change(int number) {
number = 200;
}
}
/*
输出结果为:
调用change方法前: 100
调用change方法后: 100
*/
-
-
传递引用数据类型的内存原理
- 传递引用数据类型时, 传递的是地址值, 形参的改变, 影响实参的值
以上内容依据内存图来理解
键盘录入
-
第一套体系
-
nextInt()
: 接收整数 -
nextDouble()
: 接收小数 -
next()
: 接受字符串键盘录入的字符串是
new
创建的 -
遇到空格、制表符、回车就停止接收,这些符号后面的数据就不会接受了
-
-
第二套体系
nextLine()
: 接受字符串- 遇到空格、制表符可以接收,遇到回车才停止