2 Basic¶
说明
本文档仅涉及部分内容,仅可用于复习重点知识
1 Data Type and Wrapper Class¶
1.1 Primitive Type¶
基本数据类型存储在内存的什么地方,取决于其被声明的地方
- 局部变量:stack
- 成员变量:heap
- 静态变量:方法区
1.1.1 整数类型¶
| 类型 | 大小 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|---|
byte |
8 位 | -128 到 127 | 0 | 用于处理小范围整数或原始二进制数据(如文件流) |
short |
16 位 | -32,768 到 32,767 | 0 | 相对较少使用 |
int |
32 位 | -2³¹ 到 2³¹-1 | 0 | 最常用、默认的整数类型 |
long |
64 位 | -2⁶³ 到 2⁶³-1 | 0L | 用于需要非常大整数的情况,赋值时需加 L 或 l 后缀 |
1.1.2 浮点数类型¶
| 类型 | 大小 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|---|
float |
32 位 | 大约 ±3.4e+38F | 0.0f | 单精度浮点数,赋值时需加 F 或 f 后缀 |
double |
64 位 | 大约 ±1.7e+308 | 0.0 | 最常用、默认的浮点数类型,双精度浮点数 |
1.1.3 字符类型¶
| 类型 | 大小 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|---|
char |
16位 (2字节) | 0 到 65,535 (无符号) | \u0000 |
用于存储 Unicode 字符,用单引号赋值,如 'A' |
1.1.4 布尔类型¶
| 类型 | 取值范围 | 默认值 | 说明 |
|---|---|---|---|
boolean |
true 或 false |
false |
用于条件判断和逻辑运算,不能与数字类型转换 |
Java 规范没有明确规定。在大多数 JVM 实现中,一个单独的
boolean变量在栈上可能占用 4 字节;在boolean数组中,每个元素占用 1 字节;作为对象字段时,其占用会受到对象对齐和字段重排优化的影响,实际占用可能小于 4 字节
特殊格式:
- 可以使用下划线来分割位,便于阅读
0b开头表示二进制数
1.2 Wrapper Class¶
Wrapper Class 是 Java 为 8 种基本数据类型提供的相应的引用类型。它们的主要目的是将基本数据类型包装成 对象,从而让基本数据类型具备对象的特性,可以参与到面向对象的操作中
包装类位于 java.lang 包
| 基本数据类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
比较
由于是包装类的对象,所以比较值的时候,应该使用 .equals() 方法
1.2.1 创建包装类对象¶
推荐使用 valueOf() 方法创建包装类对象
| 创建包装类对象 | |
|---|---|
1.2.2 Autoboxing and Unboxing¶
JDK 5 引入的一个极其重要的 语法糖 (1),它极大地简化了包装类和基本类型之间的转换
-
指的是计算机语言中那些没有给语言添加新功能,但让代码更易写、更易读的语法
-
装箱:将基本数据类型转换为对应的包装类对象
- 拆箱:将包装类对象转换为对应的基本数据类型
| 自动转换 | |
|---|---|
1.3 预生成对象¶
预生成对象是 Java 在类加载时预先创建并缓存的对象实例,主要用于提高性能和减少内存开销
| 包装类 | 预生成对象 |
|---|---|
| Integer | -128 ~ 127 |
| Boolean | true, false |
| Character | 0 ~ 127 |
| Byte | 全部 256 个值 |
此外还有:字符串常量池(String Pool)等
字符串常量池
只有 s1 == s2 == s3,其他两两互不相等
String s1 = "Hello":在字符串常量池中创建字符串"Hello",s1指向常量池中的这个对象String s2 = "Hello":常量池中已经存在字符串"Hello",s2会指向与s1指向相同的那个"Hello"对象String s3 = "Hel" + "lo":"Hel"和"lo"都是字符串字面量,编译器在编译时就会进行优化,将它们直接拼接成"Hello"。这个"Hello"同样存在于常量池中,s3与s1和s2指向的是同一个对象String s4 = new String("Hello"):会在堆内存中创建一个新的字符串对象String s5 = "Hel":s5指向常量池中的"Hel"s5 = s5 + "lo":这种运行时拼接会通过StringBuilder在堆上创建一个新的字符串对象"Hello",然后让s5指向这个新对象。s5和s4也不是同一个对象,因为new了两次
2 String¶
String 是 Java 提供的字符串类,位于 java.lang 包中
- 不可变性(immutable):一旦一个
String对象被创建,它的值就不能被改变。任何看似修改字符串的操作(如拼接、替换、大小写转换),实际上都是创建了一个全新的String对象 - 字符串常量池:Java 会自动维护一个字符串常量池,相同内容的字符串字面量只会有一份
final类:不能被继承
空引用
此时,内存中还没有创建一个新的字符串对象,它只是在栈内存中创建了一个名为 s 的引用变量,这个引用变量 s 的初始值是 null,意味着它还没有指向任何有效的字符串对象
C++
这一行代码执行后,一个完整的 string 对象已经被构造出来了。内存已经分配,对象已经处于可用的状态
在创建对象 s 的同时,C++ 会自动调用 std::string 的默认构造函数,默认构造函数会将对象初始化为一个空字符串(即 "")
String block:起止各一行 """,单独占一行。具体内容自动去掉公共前缀空白,保留相对缩进
2.1 String 方法¶
| 方法 | 功能 | 说明 |
|---|---|---|
int length() |
获取字符串的长度 | |
char charAt(int index) |
获取指定位置的字符 | |
boolean isEmpty() |
判断字符串是否为空 | |
String substring(int beginIndex, int endIndex) |
截取子串 | 左闭右开 |
boolean equals(Object another) |
判断内容是否相等 | |
boolean equalsIgnoreCase(String another) |
忽略大小写判断内容是否相等 | |
int indexOf(String str) |
查找子串首次出现的位置 | 如果没有找到,返回 -1 |
int indexOf(String str, int index) |
查找指定子串在当前字符串中从指定位置开始首次出现的位置 | 如果没有找到,返回 -1 |
int lastIndexOf(String str) |
查找子串最后一次出现的位置 | |
String toUpperCase() |
转为大写 | |
String toLowerCase() |
转为小写 | |
String trim() |
去除首尾空白字符 | |
boolean startsWith(String prefix) |
判断是否以指定前缀开头 | |
boolean endsWith(String suffix) |
判断是否以指定后缀结尾 | |
String replace(CharSequence target, CharSequence replacement) |
替换子串 | |
String[] split(String regex) |
按指定规则分割字符串 | |
String join(CharSequence delimiter, CharSequence... elements) |
合并字符串 | |
boolean contains(CharSequence s) |
判断是否包含子串 | |
String concat(String str) |
拼接字符串 |
2.1.1 字符串拼接¶
多次拼接不建议使用 +,因为每次都会产生一个新的对象。建议使用 StringBuilder 或 StringBuffer,效率更高
2.1.2 字符串与基本类型转换¶
基本类型转字符串:
字符串转基本类型:
2.2 toString()¶
toString() 是 Java 中所有类(包括自定义类)都继承自 Object 类的一个方法
toString() 方法用于返回对象的字符串表示,常用于调试、打印对象信息等场景
默认实现:Object 类中的 toString() 返回的是“类名@哈希码”的字符串,不直观
通常会在自定义类中重写 toString(),让其输出更有意义的信息
当对象作为参数传递给 System.out.println()、字符串拼接等场景时,会自动调用 toString() 方法
3 StringBuilder and StringBuffer¶
StringBuffer 和 StringBuilder 都是可变的字符序列,它们提供了一系列方法来修改字符串内容(如追加、插入、删除等),而无需每次修改都创建新的对象
StringBuffer 与 StringBuilder
- StringBuffer:线程安全,适合多线程(同步),速度略慢
- StringBuilder:非线程安全,适合单线程(不同步),速度更快
3.1 StringBuilder 方法¶
StringBuffer 方法与之类似
| 方法 | 功能 | 说明 |
|---|---|---|
int length() |
获取字符串长度 | |
char charAt(int index) |
获取指定位置字符 | |
StringBuilder append(xxx) |
追加内容到末尾 | 支持多种类型,返回自身 |
StringBuilder insert(int offset, xxx) |
在指定位置插入内容 | 支持多种类型,返回自身 |
StringBuilder delete(int start, int end) |
删除指定区间内容 | 左闭右开,返回自身 |
StringBuilder replace(int start, int end, String str) |
替换指定区间内容 | 左闭右开,返回自身 |
StringBuilder reverse() |
反转字符串内容 | 返回自身 |
void setCharAt(int index, char ch) |
修改指定位置字符 | |
String toString() |
转为 String 类型 |
4 Class¶
- 最后的
}后面没有; - Java 的作用域修饰符和 C++ 不同
- 构造函数没有初始化列表
对象赋值
Java 中的对象赋值,实际上赋值的是对象的引用(内存地址),而不是对象本身的内容
示例
Java 中,如果定义 成员变量 时未手动初始化一个值,会自动初始化(0, false, null 等等)
成员变量初始化方法
| 直接初始化(显式初始化) | |
|---|---|
| 通过对象初始化 | |
|---|---|
this 可以作为 delegating constructor,必须作为第一条语句
当垃圾回收器准备释放对象使用的存储空间时,会首先调用其 finalize() 方法。但是 finalize() 与 C++ 的析构函数完全不同
- 垃圾回收不是销毁
- 你的对象可能不会被垃圾回收
- 垃圾回收只与内存有关
4.1 类加载¶
Class 类
一个名为
Class的类
在 Java 中,每个类在编译后都会生成一个对应的 Class 对象。这个 Class 对象包含了该类的元数据(如类名、方法、字段、父类等信息),这些信息被存储在磁盘上一个与类同名的 .class 文件中
当程序运行时,如果需要创建某个类的实例,Java 虚拟机首先会检查该类的 Class 对象是否已经被加载到内存中。如果还没有被加载,JVM 会通过类加载器找到对应的 .class 文件,将其加载到内存中,并创建这个 Class 对象
类加载是指 JVM 将类的 .class 文件中的二进制数据读入内存,并将其转换为 JVM 内部的 Class 对象的过程。这个 Class 对象作为该类的元数据模板,用于在运行时创建对象、调用方法等
类加载的时机:
- 创建第一个对象时
- 访问静态变量或静态方法时
Class.forName()显式加载时- 其子类被初始化时
- 虚拟机启动时,包含
main()方法的类会加载
特殊情况
- 如果静态变量是编译期常量,不会触发初始化
- 通过子类引用父类的静态字段,不会触发子类初始化
4.2 静态成员¶
4.2.1 静态成员变量¶
- 共享性:所有类的实例共享同一个静态变量。任何一个实例对该变量的修改,都会影响到其他所有实例
- 生命周期:随着类的加载而创建,随着类的卸载而销毁。其生命周期长于任何对象
- 存储位置:存储在 JVM 的方法区(Method Area)中
推荐使用类名访问 ClassName.variableName,这能清晰地表明它是一个类变量;不推荐使用对象访问 object.variableName,因为这容易让人误解为实例变量
4.2.2 静态成员函数¶
只能直接访问本类的其他静态成员,不能直接访问本类的实例成员
推荐使用类名调用
4.2.3 静态代码块¶
静态代码块是用 static 关键字修饰的代码块,它在类被加载到内存时执行,且只执行一次。它主要用于初始化静态变量或执行只需进行一次的类级别初始化操作
4.2.4 静态内部类¶
- 被
static修饰的内部类 - 它不持有外部类实例的引用
- 可以像普通类一样拥有自己的静态成员和实例成员
- 只能访问外部类的静态成员
4.3 初始化顺序¶
- 静态变量,静态块(类加载时,只一次)
- 实例变量,实例初始化块(每次创建对象时)
- 构造函数(每次创建对象时)
| output | |
|---|---|
5 Switch 表达式¶
箭头语法 ->:不需要 break
如果需要写复杂逻辑的返回值,使用 yield 关键字
当然也可以作为语句使用,无返回值
示例
6 Package¶
Package 是 Java 语言中用于组织和管理类与接口的核心机制
主要作用:
- 避免命名冲突:不同包中可以存在同名类
- 组织和管理类:将功能相似或相关的类/接口组织在一起,使项目结构更清晰
- 提供访问控制:配合访问权限修饰符(如
protected和默认包权限),可以控制类成员的可见性 - 便于部署和维护:良好的包结构是大型项目可维护性的基础
6.1 命名与声明¶
命名规则(必须遵守):
- 由小写字母、数字、
_、$和.组成 - 不能以数字或点开头
- 不能是 Java 的关键字或保留字
命名规范(约定俗成,强烈建议遵守):
- 全部使用小写字母
-
使用公司域名的倒序作为包的前缀,以确保全球唯一性
- 例如,公司域名为
google.com,包前缀应为com.google
- 例如,公司域名为
-
后续部分根据项目或模块命名
- 例如:
com.google.gson,org.springframework.boot
- 例如:
-
点(
.)表示层级关系,对应文件系统的目录结构- 包
com.example.util对应的目录路径是com/example/util/
- 包
在每个 Java 源文件(.java)的顶部,使用 package 关键字来声明该文件中所有类所属的包
| com/example/math/Calculator.java | |
|---|---|
- 一个
.java文件中最多只能有一条package语句(除注释外必须是第一行) - 如果没有
package语句,该类则属于默认包(default package)。在小型测试程序中可以这样做,但在正式项目中强烈不推荐使用默认包
6.2 import 语句¶
当需要在一个类中使用其他包中的类时,就需要使用 import 语句来引入该类
使用外部类的方法:
| 使用完全限定名 | |
|---|---|
| 使用 import 导入单个类(推荐) | |
|---|---|
| 使用 import 导入整个包(谨慎使用) | |
|---|---|
静态导入
用于导入类的静态成员(静态变量和静态方法),之后可以直接使用静态成员名,而无需通过类名调用
使用静态导入需谨慎,过度使用会降低代码可读性
无需 import 的包
- 同一个包中的类:互相使用无需导入
java.lang包:这是 Java 最核心的包,编译器会自动导入
与其他语言的区别:
| 编程语言 | 语法示例 | 实现方式 |
|---|---|---|
| C / C++ | #include <stdio.h> |
文本插入:预处理器直接将头文件内容插入源代码 编译时只检查函数/变量的 声明(原型),链接时再结合编译后的二进制代码 |
| Java | import java.util.Scanner; |
装载类:通过反射(RTTI)机制在运行时获取类的信息 编译和运行时都需要编译后的 .class 二进制文件,且会自动编译依赖项 |
| Python | import Pandas |
装载并运行模块文件:直接加载并执行 Pandas.py 文件需要源代码可见(或已编译的 .pyc 文件),依赖源码或字节码 |
RTTI
RTTI 代表运行时类型信息。它允许程序在运行时发现和使用类型信息
简单来说,RTTI 让你能够在程序运行期间:
- 识别对象的实际类型
- 检查类型的继承关系
- 动态调用方法、访问字段
- 在运行时做出基于类型的决策
CLASSPATH
CLASSPATH 是告诉 Java 虚拟机(JVM)和 Java 编译器(如 javac)去哪里查找用户自定义的类、包和资源文件的环境变量或参数
当 Java 需要加载一个类时,它就会去 CLASSPATH 指定的路径列表里寻找对应的 .class 文件或包含该类的 .jar 文件
7 Access Control¶
默认权限(包权限):如果一个类或成员没有指定任何修饰符,那么它对同一个包内的其他类是可见的,但对不同包的类是不可见的。这体现了包在封装性中的作用
| 修饰符 | 同一个类 | 同一个包 | 不同包的子类 | 不同包的非子类 |
|---|---|---|---|---|
public |
✅ | ✅ | ✅ | ✅ |
protected |
✅ | ✅ | ✅ | ❌ |
| 默认(无修饰符) | ✅ | ✅ | ❌ | ❌ |
private |
✅ | ❌ | ❌ | ❌ |
7.1 final 关键字¶
final 关键字用于表示“不可变性”
final字段:必须被初始化(可以在声明时或构造方法中)。一旦赋值,就不能再修改。对于基本类型,值不变;对于引用类型,引用指向的对象不变(但对象内部的状态可能可以改变)final方法:主要目的是防止子类重写该方法以改变其行为,保证父类的某些关键逻辑得以保留final类:通常出于安全或设计目的,防止他人通过继承来创建子类,从而可能破坏该类的完整性或设计意图。Java 标准库中的String、Integer等类都是final的