摘要: 本文系统梳理了Java编程语言的核心基础知识,涵盖语言特性、语法基础、数据类型、面向对象编程、常用API及异常处理等内容。文章结构清晰,代码示例丰富,适合Java初者系统学习,也适合开发者复习巩固。建议收藏,持续更新。
一、Java语言概述
1.1 什么是Java
Java是一种高级、面向对象、跨平台的编程语言,由Sun Microsystems公司于1995年推出,现由Oracle公司维护。Java的设计目标是"Write Once, Run Anywhere"(一次编写,到处运行),这一特性使其成为企业级应用开发的首选语言之一。
1.2 Java的核心特点
| 特性 | 说明 |
|---|---|
| 面向对象 | 支持封装、继承、多态,万物皆对象 |
| 跨平台性 | 通过JVM实现,编译后的字节码可在任何支持JVM的平台上运行 |
| 自动内存管理 | 垃圾回收机制(GC),无需手动释放内存 |
| 安全性 | 字节码验证、沙箱安全模型,防止恶意代码执行 |
| 多线程支持 | 内置多线程机制,提高程序并发性能 |
| 丰富的类库 | 提供大量标准API,涵盖IO、网络、集合、并发等 |
| 编译与解释并存 | 先编译为字节码,再由JVM解释执行(JIT优化后可达编译效率) |
1.3 Java技术体系
Java技术体系
├── Java SE(Standard Edition)标准版:桌面应用、基础核心
├── Java EE(Enterprise Edition)企业版:Web应用、分布式系统(现Jakarta EE)
└── Java ME(Micro Edition)微型版:嵌入式、移动设备开发
1.4 JDK、JRE、JVM的关系
JDK(Java Development Kit)Java开发工具包
├── JRE(Java Runtime Environment)Java运行时环境
│ └── JVM(Java Virtual Machine)Java虚拟机
│ └── Java核心类库
└── 开发工具(javac、java、javadoc等)
三者关系: JDK ⊃ JRE ⊃ JVM
二、Java程序基础
2.1 第一个Java程序
java
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
程序解析:
public:访问修饰符,表示公共的class:声明类的关键字HelloWorld:类名,必须与文件名一致(HelloWorld.java)static:静态修饰符,main方法必须声明为staticvoid:返回值类型,表示无返回值main:程序入口方法,JVM从这里开始执行String[] args:命令行参数数组System.out.println():向控制台输出内容并换行
2.2 编译与运行流程
bash
# 1. 编译:将.java源文件编译为.class字节码文件
javac HelloWorld.java
# 2. 运行:JVM加载并执行字节码
java HelloWorld
执行流程图:
HelloWorld.java --(javac编译)--> HelloWorld.class --(java运行/JVM解释)--> 输出结果
2.3 注释规范
Java提供三种注释方式,良好的注释习惯是专业开发的必备素养:
java
// 1. 单行注释:用于简短说明
int age = 20; // 用户年龄
/*
* 2. 多行注释:用于较长说明
* 这段代码用于计算用户年龄
* 输入参数为出生年份
*/
int calculateAge(int birthYear) {
return 2024 - birthYear;
}
/**
* 3. 文档注释:用于生成API文档
* 计算两个整数的和
* @param a 第一个整数
* @param b 第二个整数
* @return 两数之和
*/
public int add(int a, int b) {
return a + b;
}
三、Java语法基础
3.1 标识符与关键字
标识符命名规则:
- 由字母、数字、下划线
_、美元符号$组成 - 不能以数字开头
- 不能使用Java关键字和保留字
- 区分大小写
- 建议使用有意义的名称(见名知意)
命名规范(阿里巴巴Java开发规范):
| 类型 | 规范 | 示例 |
|---|---|---|
| 类名 | 大驼峰(UpperCamelCase) | UserInfo、OrderService |
| 方法名/变量名 | 小驼峰(lowerCamelCase) | getUserName、userAge |
| 常量名 | 全大写,下划线分隔 | MAX_VALUE、PI |
| 包名 | 全小写,点号分隔 | com.company.project |
Java关键字(48个):
| 类别 | 关键字 |
|---|---|
| 访问控制 | private、protected、public |
| 类/方法/变量修饰 | abstract、class、extends、final、implements、interface、native、new、static、strictfp、synchronized、transient、volatile |
| 程序控制 | break、case、continue、default、do、else、for、if、instanceof、return、switch、while |
| 错误处理 | assert、catch、finally、throw、throws、try |
| 包相关 | import、package |
| 基本类型 | boolean、byte、char、double、float、int、long、short |
| 变量引用 | super、this、void |
| 保留字 | goto、const(尚未使用,但保留) |
3.2 变量与常量
变量的本质: 变量是内存中的一块存储空间,用于存放数据。每个变量都有数据类型 、变量名 和值三要素。
java
// 变量声明的三种方式
// 方式1:声明并赋值
int age = 20;
// 方式2:先声明,后赋值
String name;
name = "张三";
// 方式3:同时声明多个同类型变量
int a = 1, b = 2, c = 3;
// 常量声明:使用final关键字
final double PI = 3.14159;
// PI = 3.14; // 编译错误!常量一旦赋值不可修改
成员变量 vs 局部变量:
| 特性 | 成员变量 | 局部变量 |
|---|---|---|
| 声明位置 | 类中,方法外 | 方法内或代码块内 |
| 作用域 | 整个类 | 当前方法或代码块 |
| 默认值 | 有(数值型为0,布尔型为false,引用型为null) | 无,必须显式初始化 |
| 修饰符 | 可以使用访问修饰符 | 只能使用final |
| 内存位置 | 堆内存(对象)或方法区(静态) | 栈内存 |
四、数据类型详解
4.1 数据类型分类
Java是强类型语言,所有变量必须先声明类型。数据类型分为两大类:
数据类型
├── 基本数据类型(Primitive Types)8种
│ ├── 整数类型:byte、short、int、long
│ ├── 浮点类型:float、double
│ ├── 字符类型:char
│ └── 布尔类型:boolean
└── 引用数据类型(Reference Types)3种
├── 类(Class):如String、自定义类
├── 接口(Interface)
└── 数组(Array)
4.2 基本数据类型详解
| 类型 | 大小 | 默认值 | 取值范围 | 包装类 | 说明 |
|---|---|---|---|---|---|
byte |
1字节(8位) | 0 | -128 ~ 127 | Byte |
节省空间,用于大型数组 |
short |
2字节(16位) | 0 | -32768 ~ 32767 | Short |
兼容性保留,较少使用 |
int |
4字节(32位) | 0 | -2³¹ ~ 2³¹-1 | Integer |
整数默认类型,最常用 |
long |
8字节(64位) | 0L | -2⁶³ ~ 2⁶³-1 | Long |
大整数,后缀加L |
float |
4字节(32位) | 0.0f | IEEE 754标准 | Float |
单精度浮点,后缀加f |
double |
8字节(64位) | 0.0d | IEEE 754标准 | Double |
浮点默认类型,双精度 |
char |
2字节(16位) | '\u0000' | 0 ~ 65535 | Character |
Unicode字符 |
boolean |
1位(JVM规范未明确规定) | false | true/false | Boolean |
逻辑判断 |
重要说明:
String不是基本数据类型,而是引用数据类型(类)- 整数字面量默认是
int类型,超出范围需加L转为long - 浮点数字面量默认是
double类型,赋值给float需加f或强制转换
java
// 正确示例
int i = 100;
long l = 10000000000L; // 超出int范围,必须加L
float f = 3.14f; // 必须加f,否则3.14默认是double
double d = 3.14159;
// 错误示例
// int big = 10000000000; // 编译错误:整数太大
// float f2 = 3.14; // 编译错误:double不能自动转为float
4.3 类型转换
Java中类型转换分为自动类型转换(隐式)和强制类型转换(显式)。
自动类型转换(小范围 → 大范围):
byte → short → int → long → float → double
↑
char
java
// 自动转换示例
byte b = 10;
int i = b; // byte自动转为int
long l = i; // int自动转为long
double d = l; // long自动转为double
char c = 'A';
int charCode = c; // char自动转为int(ASCII码值65)
强制类型转换(大范围 → 小范围):
java
// 强制转换语法:(目标类型)值
double d = 3.99;
int i = (int)d; // i = 3,小数部分直接截断(非四舍五入)
int num = 130;
byte b = (byte)num; // b = -126,溢出导致数据失真
// 注意事项:强制转换可能导致精度丢失或数据溢出
类型转换注意事项:
- 布尔类型不能与其他类型转换
- 浮点型转整数型时,小数部分直接截断
- 大范围转小范围时,可能发生溢出(高位截断)
- 表达式中自动提升:byte/short/char参与运算时自动提升为int
java
byte a = 10;
byte b = 20;
// byte c = a + b; // 编译错误!a+b自动提升为int
int c = a + b; // 正确
五、运算符全解析
5.1 算术运算符
| 运算符 | 名称 | 示例 | 结果 | 说明 |
|---|---|---|---|---|
+ |
加法/正号/字符串连接 | 5 + 3 |
8 |
字符串连接:"a" + 1 → "a1" |
- |
减法/负号 | 5 - 3 |
2 |
|
* |
乘法 | 5 * 3 |
15 |
|
/ |
除法 | 5 / 2 |
2 |
整数相除结果取整 |
% |
取模(求余) | 5 % 2 |
1 |
结果符号与被除数相同 |
++ |
自增 | ++a / a++ |
前缀先增后用,后缀先用后增 | |
-- |
自减 | --a / a-- |
前缀先减后用,后缀先用后减 |
java
// 自增自减详解
int a = 5;
int b = ++a; // a先变为6,再赋值给b。结果:a=6, b=6
int c = 5;
int d = c++; // 先将c=5赋值给d,c再变为6。结果:c=6, d=5
// 除法陷阱
int x = 5 / 2; // x = 2(整数除法截断小数)
double y = 5 / 2; // y = 2.0(先整数除法得2,再转double)
double z = 5.0 / 2; // z = 2.5(浮点运算)
5.2 赋值运算符
| 运算符 | 示例 | 等价于 | 说明 |
|---|---|---|---|
= |
a = 5 |
基本赋值 | |
+= |
a += 3 |
a = a + 3 |
加法赋值 |
-= |
a -= 3 |
a = a - 3 |
减法赋值 |
*= |
a *= 3 |
a = a * 3 |
乘法赋值 |
/= |
a /= 3 |
a = a / 3 |
除法赋值 |
%= |
a %= 3 |
a = a % 3 |
取模赋值 |
复合赋值运算符的隐式类型转换:
java
byte b = 10;
// b = b + 5; // 编译错误!b+5结果为int
b += 5; // 正确!复合赋值运算符自动强制转换
// 等价于:b = (byte)(b + 5);
5.3 比较运算符
| 运算符 | 名称 | 示例 | 结果 |
|---|---|---|---|
== |
等于 | 5 == 5 |
true |
!= |
不等于 | 5 != 3 |
true |
> |
大于 | 5 > 3 |
true |
< |
小于 | 5 < 3 |
false |
>= |
大于等于 | 5 >= 5 |
true |
<= |
小于等于 | 5 <= 3 |
false |
⚠️ 重要区别:== vs equals()
java
// 基本数据类型:==比较的是值
int a = 10, b = 10;
System.out.println(a == b); // true
// 引用数据类型:==比较的是内存地址(引用)
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false(不同对象,地址不同)
System.out.println(s1.equals(s2)); // true(内容相同)
// 字符串常量池特例
String s3 = "hello";
String s4 = "hello";
System.out.println(s3 == s4); // true(常量池复用)
5.4 逻辑运算符
| 运算符 | 名称 | 示例 | 说明 |
|---|---|---|---|
& |
逻辑与 | A & B |
两边都true才true,两边都执行 |
| ` | ` | 逻辑或 | `A |
! |
逻辑非 | !A |
取反 |
^ |
逻辑异或 | A ^ B |
两边不同为true,相同为false |
&& |
短路与 | A && B |
左边false右边不执行 |
| ` | ` | 短路或 |
短路特性详解(开发中推荐使用&&和||):
java
int a = 5, b = 0;
// 短路或:左边为true,右边不执行(不会报除零错误)
if (a > 0 || (b / 0 > 0)) {
System.out.println("短路或:右边未执行");
}
// 非短路或:两边都执行(会报ArithmeticException)
// if (a > 0 | (b / 0 > 0)) { } // 运行时错误!
// 经典应用:防止空指针异常
String str = null;
if (str != null && str.length() > 0) { // 安全!str为null时不会调用length()
System.out.println("字符串非空");
}
5.5 位运算符(了解)
| 运算符 | 名称 | 示例 | 说明 |
|---|---|---|---|
& |
按位与 | 5 & 3 |
对应位都为1才为1 |
| ` | ` | 按位或 | `5 |
^ |
按位异或 | 5 ^ 3 |
对应位不同为1 |
~ |
按位取反 | ~5 |
0变1,1变0 |
<< |
左移 | 5 << 2 |
左移n位,相当于乘以2ⁿ |
>> |
右移 | 5 >> 2 |
右移n位,相当于除以2ⁿ(带符号) |
>>> |
无符号右移 | 5 >>> 2 |
高位补0 |
java
// 位运算经典应用:交换两个数(无需临时变量)
int a = 5, b = 3;
a = a ^ b;
b = a ^ b; // b = (a^b)^b = a
a = a ^ b; // a = (a^b)^a = b
System.out.println("a=" + a + ", b=" + b); // a=3, b=5
// 高效判断奇偶(位运算比取模快)
int num = 7;
if ((num & 1) == 1) {
System.out.println(num + "是奇数");
}
5.6 三元运算符
java
// 语法:条件表达式 ? 表达式1 : 表达式2
// 条件为true返回表达式1,否则返回表达式2
int a = 10, b = 20;
int max = (a > b) ? a : b; // max = 20
// 嵌套三元运算符(不建议过多嵌套,可读性差)
int score = 85;
String grade = (score >= 90) ? "A" : (score >= 80) ? "B" : (score >= 60) ? "C" : "D";
5.7 运算符优先级
| 优先级 | 运算符 | 结合性 |
|---|---|---|
| 1 | ()、[]、· |
从左到右 |
| 2 | !、~、++、--、+(正)、-(负) |
从右到左 |
| 3 | *、/、% |
从左到右 |
| 4 | +、- |
从左到右 |
| 5 | <<、>>、>>> |
从左到右 |
| 6 | <、<=、>、>=、instanceof |
从左到右 |
| 7 | ==、!= |
从左到右 |
| 8 | & |
从左到右 |
| 9 | ^ |
从左到右 |
| 10 | ` | ` |
| 11 | && |
从左到右 |
| 12 | ` | |
| 13 | ?: |
从右到左 |
| 14 | =、+=、-=、*=、/=、%=等 |
从右到左 |
建议: 不确定优先级时,使用括号()明确运算顺序,提高代码可读性。
六、流程控制语句
6.1 选择结构
6.1.1 if-else语句
java
// 单分支
if (条件) {
// 条件为true时执行
}
// 双分支
if (条件) {
// 条件为true时执行
} else {
// 条件为false时执行
}
// 多分支
if (条件1) {
// 条件1为true
} else if (条件2) {
// 条件2为true
} else if (条件3) {
// 条件3为true
} else {
// 以上都不满足
}
// 嵌套if
if (外层条件) {
if (内层条件) {
// 两层都满足
}
}
实际应用示例:
java
// 根据成绩评定等级
int score = 85;
if (score < 0 || score > 100) {
System.out.println("成绩输入有误");
} else if (score >= 90) {
System.out.println("优秀");
} else if (score >= 80) {
System.out.println("良好");
} else if (score >= 70) {
System.out.println("中等");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
6.1.2 switch语句
java
// 传统语法(Java 12之前)
switch (表达式) {
case 常量1:
// 语句
break; // 必须有break,否则穿透执行
case 常量2:
// 语句
break;
default:
// 默认语句
break;
}
// 增强语法(Java 12+):箭头语法,自动break
switch (表达式) {
case 常量1 -> // 单条语句;
case 常量2 -> {
// 多条语句
}
default -> // 默认处理;
}
switch表达式类型限制: JDK 5之前只能是byte、short、char、int;JDK 5加入枚举;JDK 7加入String。
java
// 示例:根据月份判断季节(Java 14+ switch表达式)
String season = switch (month) {
case 3, 4, 5 -> "春季";
case 6, 7, 8 -> "夏季";
case 9, 10, 11 -> "秋季";
case 12, 1, 2 -> "冬季";
default -> "未知";
};
6.2 循环结构
6.2.1 for循环
java
// 标准for循环
for (初始化; 条件判断; 迭代操作) {
// 循环体
}
// 示例:计算1~100的和
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
// 增强for循环(foreach):用于遍历数组或集合
int[] arr = {1, 2, 3, 4, 5};
for (int num : arr) {
System.out.println(num);
}
6.2.2 while循环
java
// 先判断,后执行(可能一次都不执行)
while (条件) {
// 循环体
}
// 示例:猜数字游戏
int target = 50;
int guess;
Scanner scanner = new Scanner(System.in);
while ((guess = scanner.nextInt()) != target) {
System.out.println(guess > target ? "太大了" : "太小了");
}
System.out.println("猜对了!");
6.2.3 do-while循环
java
// 先执行,后判断(至少执行一次)
do {
// 循环体
} while (条件);
// 示例:菜单选择(至少显示一次)
int choice;
do {
System.out.println("1. 查询 2. 添加 3. 退出");
choice = scanner.nextInt();
// 处理选择...
} while (choice != 3);
三种循环对比:
| 循环类型 | 适用场景 | 特点 |
|---|---|---|
for |
已知循环次数 | 结构紧凑,计数器作用域在循环内 |
while |
未知循环次数,可能不执行 | 先判断后执行 |
do-while |
至少执行一次 | 先执行后判断 |
6.3 跳转语句
| 语句 | 作用 | 使用场景 |
|---|---|---|
break |
跳出当前循环或switch | 结束循环、跳出case |
continue |
跳过本次循环,进入下一次 | 过滤某些情况 |
return |
结束方法,返回结果 | 方法退出 |
label(标签) |
标识循环,配合break/continue使用 | 跳出多层循环 |
java
// break跳出多层循环
outer: for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (i * j > 50) {
break outer; // 跳出外层循环
}
}
}
// continue跳过本次
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // 跳过偶数,只打印奇数
}
System.out.println(i);
}
七、数组
7.1 数组概述
数组是相同数据类型元素的集合,属于引用数据类型。数组一旦创建,长度不可改变。
7.2 数组声明与初始化
java
// 方式1:声明并分配空间(动态初始化)
int[] arr1 = new int[5]; // 5个元素,默认值0
// 方式2:声明并赋值(静态初始化)
int[] arr2 = new int[]{1, 2, 3, 4, 5};
// 简写形式
int[] arr3 = {1, 2, 3, 4, 5};
// 方式3:先声明,后创建
int[] arr4;
arr4 = new int[10];
// 注意:以下写法错误
// int[] arr = new int[5]{1,2,3,4,5}; // 编译错误!不能同时指定长度和元素
7.3 数组操作
java
int[] arr = {10, 20, 30, 40, 50};
// 访问元素(索引从0开始)
int first = arr[0]; // 10
int last = arr[4]; // 50
// arr[5]; // ArrayIndexOutOfBoundsException!数组越界
// 获取长度
int len = arr.length; // 5(注意不是方法,是属性)
// 遍历数组
// 方式1:for循环
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 方式2:增强for循环
for (int num : arr) {
System.out.println(num);
}
// 方式3:Arrays工具类
System.out.println(Arrays.toString(arr)); // [10, 20, 30, 40, 50]
// 排序
Arrays.sort(arr); // 快速排序/归并排序(Dual-Pivot Quicksort)
// 查找(先排序后二分查找)
int index = Arrays.binarySearch(arr, 30); // 返回索引,不存在返回负数
// 填充
Arrays.fill(arr, 0); // 所有元素置为0
// 复制
int[] copy = Arrays.copyOf(arr, arr.length); // 完整复制
int[] part = Arrays.copyOfRange(arr, 1, 4); // 复制索引[1,4)的元素
7.4 二维数组
java
// 声明与初始化
int[][] matrix = new int[3][4]; // 3行4列
int[][] matrix2 = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 不规则数组(每行长度不同)
int[][] jagged = new int[3][];
jagged[0] = new int[2];
jagged[1] = new int[4];
jagged[2] = new int[3];
// 遍历二维数组
for (int i = 0; i < matrix2.length; i++) { // 行
for (int j = 0; j < matrix2[i].length; j++) { // 列
System.out.print(matrix2[i][j] + " ");
}
System.out.println();
}
八、面向对象编程(OOP)
面向对象编程是Java的核心思想,三大特性:封装、继承、多态。
8.1 类与对象
类(Class): 对一类事物的抽象描述,是创建对象的模板。
对象(Object): 类的实例,是客观存在的具体个体。
java
// 定义类
public class Student {
// 成员变量(属性)
private String name; // 姓名
private int age; // 年龄
private String studentId; // 学号
// 构造方法(Constructor)
public Student() {} // 无参构造
public Student(String name, int age, String studentId) {
this.name = name;
this.age = age;
this.studentId = studentId;
}
// 成员方法(行为)
public void study() {
System.out.println(name + "正在学习Java...");
}
// Getter和Setter方法(封装的体现)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// ...其他getter/setter
}
// 创建对象
Student stu = new Student("张三", 20, "2024001");
stu.study(); // 调用方法
8.2 构造方法详解
java
public class Person {
private String name;
private int age;
// 无参构造(默认提供,一旦显式定义有参构造,默认不再提供)
public Person() {
System.out.println("无参构造被调用");
}
// 有参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 构造方法重载
public Person(String name) {
this(name, 0); // 调用同类其他构造(必须放在第一行)
}
// this()和super()不能同时出现在一个构造方法中
}
构造方法特点:
- 方法名与类名相同
- 没有返回值类型(连void都没有)
- 可以重载
- 不能递归调用
8.3 三大特性之------封装(Encapsulation)
封装的目的: 隐藏对象的内部实现细节,仅对外暴露有限的访问接口,保证数据安全性。
java
public class BankAccount {
// 1. 成员变量私有化(private)
private String accountNo; // 账号
private double balance; // 余额(敏感数据)
private String password; // 密码
// 2. 提供公共的getter/setter方法
public double getBalance() {
return balance; // 只允许查看余额
}
// 3. 对敏感操作进行控制
public void withdraw(double amount, String pwd) {
// 验证密码
if (!this.password.equals(pwd)) {
System.out.println("密码错误");
return;
}
// 验证余额
if (amount > balance) {
System.out.println("余额不足");
return;
}
// 执行取款
this.balance -= amount;
System.out.println("取款成功,余额:" + balance);
}
// 4. 不提供直接修改余额的方法(防止随意篡改)
// 没有setBalance()方法!
}
封装的好处:
- 提高安全性:防止外部随意修改内部数据
- 提高灵活性:内部实现可以改变,不影响外部调用
- 提高可维护性:结构清晰,便于调试和修改
- 提高复用性:封装好的类可以在多个项目中使用
8.4 三大特性之------继承(Inheritance)
继承的本质: 子类继承父类的属性和方法,实现代码复用,并可以扩展新功能。
java
// 父类
public class Animal {
protected String name; // protected:子类可访问
protected int age;
public void eat() {
System.out.println(name + "在吃东西");
}
public void sleep() {
System.out.println(name + "在睡觉");
}
}
// 子类
public class Dog extends Animal { // extends关键字继承
private String breed; // 品种(子类特有属性)
// 构造方法
public Dog(String name, int age, String breed) {
this.name = name; // 继承自父类
this.age = age;
this.breed = breed;
}
// 子类特有方法
public void bark() {
System.out.println(name + ":汪汪汪!");
}
// 方法重写(Override)
@Override
public void eat() {
System.out.println(name + "在吃骨头"); // 子类自定义行为
}
}
// 使用
Dog dog = new Dog("旺财", 3, "金毛");
dog.eat(); // 调用重写后的方法:旺财在吃骨头
dog.sleep(); // 调用继承的方法:旺财在睡觉
dog.bark(); // 调用子类特有方法:旺财:汪汪汪!
继承的重要规则:
- Java只支持单继承(一个类只能有一个直接父类)
- 子类继承父类所有非私有成员
- 子类不能继承父类的构造方法 (但可以通过
super()调用) - 可以使用
super关键字访问父类成员 - 继承关系要符合"is-a"原则(狗是动物)
方法重写(Override)规则:
- 方法名、参数列表、返回值类型必须相同
- 访问权限不能比父类更严格(可以相同或更宽松)
- 抛出的异常不能比父类更宽泛
- 使用
@Override注解进行校验
8.5 三大特性之------多态(Polymorphism)
多态的前提: 继承 + 方法重写 + 向上转型
多态的体现: 父类引用指向子类对象,调用方法时执行子类重写的方法。
java
// 父类引用指向子类对象(向上转型)
Animal animal = new Dog("旺财", 3, "金毛");
animal.eat(); // 实际执行Dog的eat()方法:旺财在吃骨头
// 多态数组
Animal[] animals = new Animal[3];
animals[0] = new Dog("旺财", 3, "金毛");
animals[1] = new Cat("咪咪", 2, "橘猫");
animals[2] = new Bird("小白", 1, "鹦鹉");
// 统一遍历,不同表现
for (Animal a : animals) {
a.eat(); // 每个对象执行各自重写的方法
}
// 向下转型(需谨慎,可能ClassCastException)
if (animal instanceof Dog) { // 先判断类型
Dog dog = (Dog) animal; // 安全转型
dog.bark();
}
多态的好处:
- 可扩展性: 新增子类不影响原有代码
- 可替换性: 子类对象可以随时替换父类对象
- 接口性: 通过父类引用操作不同子类对象
- 灵活性: 简化代码,提高复用
8.6 关键字详解
8.6.1 this关键字
this代表当前对象的引用。
java
public class ThisDemo {
private int num;
// 1. 区分成员变量和局部变量
public void setNum(int num) {
this.num = num; // this.num是成员变量,num是参数
}
// 2. 调用当前类的其他构造方法
public ThisDemo() {
this(0); // 调用有参构造,必须放在第一行
}
public ThisDemo(int num) {
this.num = num;
}
// 3. 返回当前对象(链式调用)
public ThisDemo increment() {
num++;
return this;
}
}
8.6.2 super关键字
super代表父类对象的引用。
java
public class SuperDemo extends Parent {
private int value;
public SuperDemo(int value, int parentValue) {
super(parentValue); // 调用父类构造,必须放在第一行
this.value = value;
}
public void show() {
System.out.println(super.value); // 访问父类成员
super.display(); // 调用父类方法
}
}
8.6.3 static关键字
static修饰的成员属于类,而非某个对象。
java
public class StaticDemo {
// 静态变量(类变量):所有对象共享一份
public static int count = 0;
// 实例变量:每个对象独立一份
private int id;
// 静态代码块:类加载时执行,只执行一次
static {
System.out.println("静态代码块执行");
count = 100;
}
// 实例代码块:每次创建对象时执行
{
System.out.println("实例代码块执行");
id = ++count;
}
// 静态方法:属于类,可直接通过类名调用
public static void showCount() {
System.out.println("当前count:" + count);
// System.out.println(id); // 错误!静态方法不能访问非静态成员
}
// 静态内部类
public static class Inner {
public void test() {
System.out.println(count); // 可以访问外部静态成员
}
}
}
// 使用
StaticDemo.showCount(); // 类名.静态方法
StaticDemo.Inner inner = new StaticDemo.Inner(); // 直接创建,不依赖外部对象
静态成员加载顺序: 静态变量/代码块按代码顺序加载 → main方法 → 实例变量/代码块 → 构造方法
8.6.4 final关键字
final表示"最终的、不可改变的"。
| 修饰目标 | 作用 |
|---|---|
| 类 | 该类不能被继承(如String、Math) |
| 方法 | 该方法不能被重写 |
| 变量 | 变量只能赋值一次,成为常量 |
java
// final类
public final class FinalClass {
// 不能被继承
}
// final方法
public class Parent {
public final void finalMethod() {
// 子类不能重写
}
}
// final变量
public class FinalVar {
// 1. 成员常量:声明时或构造方法中初始化
private final int MAX_SIZE = 100;
// 2. 静态常量:声明时或静态代码块中初始化
public static final double PI = 3.14159;
// 3. 引用类型常量:引用不可变,但对象内容可变
private final StringBuilder sb = new StringBuilder("Hello");
public void modify() {
// sb = new StringBuilder(); // 错误!不能改变引用
sb.append(" World"); // 正确!可以修改对象内容
}
}
8.7 访问修饰符
| 修饰符 | 同类 | 同包 | 子类 | 任何地方 |
|---|---|---|---|---|
private |
✓ | ✗ | ✗ | ✗ |
default(缺省) |
✓ | ✓ | ✗(不同包) | ✗ |
protected |
✓ | ✓ | ✓ | ✗ |
public |
✓ | ✓ | ✓ | ✓ |
使用原则: 尽量私有化,按需开放。
九、抽象类与接口
9.1 抽象类(Abstract Class)
抽象类是不能被实例化的类,用于定义子类的通用模板。
java
// 抽象类
public abstract class Shape {
// 可以有成员变量
protected String color;
// 可以有构造方法(供子类调用)
public Shape(String color) {
this.color = color;
}
// 可以有普通方法
public void showColor() {
System.out.println("颜色:" + color);
}
// 抽象方法:没有方法体,子类必须实现
public abstract double getArea();
public abstract double getPerimeter();
}
// 具体子类
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double getArea() {
return Math.PI * radius * radius;
}
@Override
public double getPerimeter() {
return 2 * Math.PI * radius;
}
}
抽象类特点:
- 使用
abstract关键字修饰 - 可以包含抽象方法和普通方法
- 可以有成员变量和构造方法
- 子类必须实现所有抽象方法(除非子类也是抽象类)
- 不能创建对象,但可以声明引用变量
9.2 接口(Interface)
接口是更纯粹的抽象,JDK 8之前只能包含常量和抽象方法;JDK 8+支持默认方法和静态方法;JDK 9+支持私有方法。
java
// 接口定义
public interface Flyable {
// 隐式:public static final
int MAX_HEIGHT = 10000;
// 抽象方法(JDK 7及以前唯一形式)
void fly();
// 默认方法(JDK 8+):有方法体,子类可选择性重写
default void land() {
System.out.println("安全着陆");
}
// 静态方法(JDK 8+):属于接口,通过接口名调用
static void checkEngine() {
System.out.println("检查引擎状态");
}
// 私有方法(JDK 9+):接口内部复用
private void log(String msg) {
System.out.println("[LOG] " + msg);
}
}
// 实现接口
public class Bird implements Flyable {
@Override
public void fly() {
System.out.println("用翅膀飞行");
}
// 可以选择重写默认方法
@Override
public void land() {
System.out.println("Bird:轻盈着陆");
}
}
// 一个类可以实现多个接口
public class Superman implements Flyable, Runnable, Fightable {
// 必须实现所有抽象方法
}
接口与抽象类的区别:
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 继承/实现 | 单继承(extends) | 多实现(implements) |
| 构造方法 | 有 | 无 |
| 成员变量 | 可以有各种类型 | 只能是public static final常量 |
| 方法 | 抽象+普通 | JDK8前只能抽象;JDK8+可有默认/静态方法 |
| 设计目的 | "is-a"关系,代码复用 | "has-a"能力,定义规范 |
| 使用场景 | 共性提取 | 能力定义 |
十、常用类与API
10.1 String类(重点)
String是不可变字符序列,所有修改操作都会创建新对象。
java
// 创建方式
String s1 = "hello"; // 常量池
String s2 = new String("hello"); // 堆内存
String s3 = "hello"; // 常量池复用
System.out.println(s1 == s2); // false(地址不同)
System.out.println(s1 == s3); // true(常量池复用)
System.out.println(s1.equals(s2)); // true(内容相同)
// 常用方法
String str = " Hello World ";
str.length(); // 13
str.trim(); // "Hello World"(去首尾空格)
str.toLowerCase(); // " hello world "
str.toUpperCase(); // " HELLO WORLD "
str.substring(2, 7); // "Hello"(含头不含尾)
str.indexOf("World"); // 8
str.replace("World", "Java"); // " Hello Java "
str.split(" "); // 按空格分割为数组
str.contains("Hello"); // true
str.startsWith(" H"); // true
str.charAt(2); // 'H'
// StringBuilder/StringBuffer:可变字符串
// StringBuilder:线程不安全,效率高(单线程推荐)
// StringBuffer:线程安全,效率略低(多线程推荐)
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // Hello World
sb.insert(5, ","); // Hello, World
sb.delete(5, 6); // Hello World
sb.reverse(); // dlroW olleH
String不可变性的好处:
- 字符串常量池的实现基础,节省内存
- 多线程安全,无需同步
- 适合作为Map的键(hashCode不变)
- 防止恶意修改(如网络连接参数)
10.2 包装类
基本数据类型与对应包装类:
| 基本类型 | 包装类 |
|---|---|
byte |
Byte |
short |
Short |
int |
Integer |
long |
Long |
float |
Float |
double |
Double |
char |
Character |
boolean |
Boolean |
java
// 装箱:基本类型 → 包装类
Integer i1 = Integer.valueOf(100); // 手动装箱
Integer i2 = 100; // 自动装箱(JDK 5+)
// 拆箱:包装类 → 基本类型
int num1 = i1.intValue(); // 手动拆箱
int num2 = i2; // 自动拆箱
// 包装类常用方法
Integer.parseInt("123"); // 字符串转int
Integer.toString(123); // int转字符串
Integer.MAX_VALUE; // 最大值
Integer.MIN_VALUE; // 最小值
// 注意:缓存机制(-128 ~ 127)
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(缓存复用)
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false(超出缓存,新建对象)
10.3 Math类
java
Math.abs(-10); // 10(绝对值)
Math.max(10, 20); // 20(最大值)
Math.min(10, 20); // 10(最小值)
Math.ceil(3.14); // 4.0(向上取整)
Math.floor(3.14); // 3.0(向下取整)
Math.round(3.14); // 3(四舍五入)
Math.pow(2, 3); // 8.0(2的3次方)
Math.sqrt(16); // 4.0(平方根)
Math.random(); // [0.0, 1.0)随机数
// 生成[1, 100]随机整数
int random = (int)(Math.random() * 100) + 1;
10.4 日期时间类(JDK 8新API推荐)
java
// JDK 8之前(不推荐,线程不安全,设计混乱)
Date date = new Date();
Calendar calendar = Calendar.getInstance();
// JDK 8+ 新日期时间API(java.time包,推荐)
import java.time.*;
import java.time.format.DateTimeFormatter;
// 当前日期
LocalDate today = LocalDate.now(); // 2024-05-11
LocalTime now = LocalTime.now(); // 14:30:25.123
LocalDateTime dateTime = LocalDateTime.now();
// 指定日期
LocalDate birth = LocalDate.of(2000, 1, 1);
// 日期计算
LocalDate nextWeek = today.plusWeeks(1);
LocalDate lastMonth = today.minusMonths(1);
// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String str = dateTime.format(formatter);
// 解析
LocalDate parsed = LocalDate.parse("2024-05-11");
十一、异常处理
11.1 异常体系
Throwable(所有异常的根类)
├── Error(错误):严重问题,程序无法处理
│ ├── OutOfMemoryError(内存溢出)
│ ├── StackOverflowError(栈溢出)
│ └── ...
└── Exception(异常):可以处理的问题
├── RuntimeException(运行时异常/非受检异常)
│ ├── NullPointerException(空指针)
│ ├── ArrayIndexOutOfBoundsException(数组越界)
│ ├── ClassCastException(类型转换异常)
│ ├── ArithmeticException(算术异常,如除零)
│ └── ...
└── 其他Exception(编译时异常/受检异常)
├── IOException
├── SQLException
├── ClassNotFoundException
└── ...
11.2 异常处理机制
java
// 基本语法
try {
// 可能抛出异常的代码
int result = 10 / 0;
} catch (ArithmeticException e) {
// 捕获并处理特定异常
System.out.println("除数不能为0:" + e.getMessage());
} catch (Exception e) {
// 捕获其他异常(子类在前,父类在后)
System.out.println("发生异常:" + e.getMessage());
} finally {
// 无论是否异常,最终都会执行
System.out.println("清理资源...");
}
// 多异常合并(JDK 7+)
catch (IOException | SQLException e) {
// 处理多种异常
}
// try-with-resources(自动关闭资源,JDK 7+)
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
// br会自动关闭,无需finally中手动关闭
// 抛出异常
public void method() throws IOException, SQLException {
// 方法声明可能抛出的异常
if (error) {
throw new IOException("文件读取失败");
}
}
// 自定义异常
public class BusinessException extends RuntimeException {
private int code;
public BusinessException(int code, String message) {
super(message);
this.code = code;
}
public int getCode() {
return code;
}
}
异常处理原则:
- 不要捕获Throwable或Exception,应捕获具体异常
- 不要吞掉异常,至少打印日志
- 不要在finally中return,会覆盖try中的return
- 优先使用标准异常,自定义异常用于业务场景
- 异常信息要具体,便于定位问题
十二、总结与学习建议
12.1 知识图谱
Java基础知识
├── 语言基础
│ ├── 数据类型(8种基本 + 引用)
│ ├── 运算符(算术、比较、逻辑、位运算)
│ └── 流程控制(if、switch、for、while)
├── 数组
│ ├── 一维数组
│ └── 二维数组
├── 面向对象
│ ├── 类与对象
│ ├── 三大特性(封装、继承、多态)
│ ├── 关键字(this、super、static、final)
│ ├── 抽象类与接口
│ └── 访问控制
├── 常用API
│ ├── String/StringBuilder
│ ├── 包装类
│ ├── Math
│ └── 日期时间
└── 异常处理
├── 异常体系
└── try-catch-finally
12.2 学习建议
- 多敲代码:编程是实践学科,看十遍不如写一遍
- 理解原理:不要死记API,理解底层机制(如String不可变性)
- 阅读源码:从JDK源码中学习优秀的设计(如ArrayList、HashMap)
- 做项目:通过实际项目巩固知识,发现问题
- 持续更新:Java版本迭代快,关注新特性(如Record、Pattern Matching)
12.3 推荐学习资源
- 官方文档: Oracle Java Documentation
- 经典书籍: 《Java核心技术》、《Effective Java》、《深入理解Java虚拟机》
- 在线平台: CSDN、掘金、Stack Overflow
结语: Java基础知识是构建高楼大厦的地基,只有地基牢固,才能在框架学习、分布式系统、微服务架构等高级领域游刃有余。本文涵盖了Java基础的核心知识点,建议结合实践反复巩固。如有错误或不足,欢迎在评论区指正交流!
如果觉得本文对你有帮助,欢迎点赞、收藏、转发! 您的支持是我持续更新的动力!