|
|
@@ -133,6 +133,40 @@ new Compute() {
|
|
|
|
|
|
**注意**:这种方式因为没有变量名,所以只能调用一次。
|
|
|
|
|
|
+### 2.8 继承普通类的匿名内部类
|
|
|
+
|
|
|
+匿名内部类不仅可以继承抽象类或实现接口,也可以继承 **普通类(非抽象)**。
|
|
|
+
|
|
|
+```java
|
|
|
+// Student 是普通类(非抽象、非接口)
|
|
|
+new Student(1001, "张三", 25, "男") {
|
|
|
+ String s = "哈哈哈哈";
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void study() {
|
|
|
+ System.out.println("临时学员" + getName() + "在学习");
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void lesson() {
|
|
|
+ System.out.println("临时学员" + getName() + "在上课");
|
|
|
+ }
|
|
|
+
|
|
|
+ public void myDay() {
|
|
|
+ study();
|
|
|
+ lesson();
|
|
|
+ System.out.println(s);
|
|
|
+ }
|
|
|
+}.myDay(); // 直接调用匿名内部类的特有方法
|
|
|
+```
|
|
|
+> 📄 来源:`exercise01/Test.java`
|
|
|
+
|
|
|
+**特点**:
|
|
|
+- 可以重写父类的非抽象方法(`study()`、`lesson()`)
|
|
|
+- 可以定义匿名内部类特有的方法(`myDay()`)
|
|
|
+- 可以通过匿名对象直接调用特有方法
|
|
|
+- 适合临时扩展已有类的行为,而不需要显式创建子类
|
|
|
+
|
|
|
---
|
|
|
|
|
|
## 三、接口与抽象类定义
|
|
|
@@ -307,9 +341,223 @@ System.out.println(max.getName());
|
|
|
|
|
|
**说明**:使用匿名内部类实现 `Sort` 接口的比较逻辑,根据学生 ID 比较大小,返回较小的学生对象。
|
|
|
|
|
|
+### 5.4 抽象类匿名内部类案例
|
|
|
+
|
|
|
+匿名内部类可以直接继承抽象类,并实现其所有抽象方法。
|
|
|
+
|
|
|
+```java
|
|
|
+abstract class Animal {
|
|
|
+ public abstract void makeSound();
|
|
|
+}
|
|
|
+
|
|
|
+public class TestAnonymous {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ new Animal() {
|
|
|
+ @Override
|
|
|
+ public void makeSound() {
|
|
|
+ System.out.println("喵喵喵");
|
|
|
+ }
|
|
|
+ }.makeSound();
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+> 📄 来源:`exercise07/TestAnonymous.java`
|
|
|
+
|
|
|
+### 5.5 接口多实现案例(计算器)
|
|
|
+
|
|
|
+同一个接口,通过多个匿名内部类实现不同的业务逻辑。
|
|
|
+
|
|
|
+```java
|
|
|
+interface Calculator {
|
|
|
+ int calculate(int a, int b);
|
|
|
+}
|
|
|
+
|
|
|
+public class TestCalculator {
|
|
|
+ public static void main(String[] args) {
|
|
|
+ // 加法
|
|
|
+ new Calculator() {
|
|
|
+ @Override
|
|
|
+ public int calculate(int a, int b) { return a + b; }
|
|
|
+ }.calculate(15, 7);
|
|
|
+
|
|
|
+ // 减法
|
|
|
+ new Calculator() {
|
|
|
+ @Override
|
|
|
+ public int calculate(int a, int b) { return a - b; }
|
|
|
+ }.calculate(15, 7);
|
|
|
+
|
|
|
+ // 乘法
|
|
|
+ new Calculator() {
|
|
|
+ @Override
|
|
|
+ public int calculate(int a, int b) { return a * b; }
|
|
|
+ }.calculate(15, 7);
|
|
|
+
|
|
|
+ // 除法
|
|
|
+ new Calculator() {
|
|
|
+ @Override
|
|
|
+ public int calculate(int a, int b) { return a / b; }
|
|
|
+ }.calculate(15, 7);
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+> 📄 来源:`exercise07/TestCalculator.java`
|
|
|
+
|
|
|
+**说明**:同一个 `Calculator` 接口,通过 4 个不同的匿名内部类分别实现加、减、乘、除四种运算,体现了匿名内部类灵活多变的特性。
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 六、Java API 概述
|
|
|
+
|
|
|
+### 6.1 什么是 API
|
|
|
+
|
|
|
+**API(Application Programming Interface)**—— 应用程序编程接口。
|
|
|
+
|
|
|
+Java 中的 API 指 JDK 提供的各种功能的 Java 类,这些类把底层的实现封装了起来。我们不需要关心这些类是怎么实现的,只需要学习怎么去使用这些类即可。
|
|
|
+
|
|
|
+我们可以通过 **Java 帮助文档** 来学习怎么使用这些 API。
|
|
|
+
|
|
|
+> 📄 来源:`api/Demo01.java`
|
|
|
+
|
|
|
+包括之前使用过的 `Scanner` 键盘输入类和 `Random` 随机数类,都属于 Java 的 API。
|
|
|
+
|
|
|
+### 6.2 String 字符串类
|
|
|
+
|
|
|
+`String` 是 Java 中最常用的 API 类之一,用于处理字符串数据。
|
|
|
+
|
|
|
+#### 6.2.1 String 的内存模型
|
|
|
+
|
|
|
+String 类型的变量存储位置有两种情况:
|
|
|
+
|
|
|
+| 创建方式 | 存储位置 | 特点 |
|
|
|
+|----------|---------|------|
|
|
|
+| **直接赋值** `String s = "Hello";` | **字符串常量池** | 只要字符序列(顺序和大小写)相同,JVM 只建立一个 String 对象并维护在常量池中 |
|
|
|
+| **构造方法创建** `new String("Hello");` | **堆内存** | 每次 `new` 都会在堆中创建一个新对象,内容相同但地址值不同 |
|
|
|
+
|
|
|
+```java
|
|
|
+String s1 = "Hello";
|
|
|
+String s2 = "Hello";
|
|
|
+System.out.println(s1 == s2); // true —— 常量池中同一个对象
|
|
|
+
|
|
|
+String s4 = new String("Hello");
|
|
|
+String s5 = new String("Hello");
|
|
|
+System.out.println(s1 == s4); // false —— 常量池 vs 堆,地址不同
|
|
|
+System.out.println(s4 == s5); // false —— 堆中两个不同对象
|
|
|
+```
|
|
|
+> 📄 来源:`api/StringTest.java`
|
|
|
+
|
|
|
+#### 6.2.2 String 的构造方法
|
|
|
+
|
|
|
+| 构造方法 | 说明 |
|
|
|
+|----------|------|
|
|
|
+| `public String()` | 创建空白字符串对象,不含任何内容 |
|
|
|
+| `public String(char[] chs)` | 根据字符数组的内容创建字符串 |
|
|
|
+| `public String(String original)` | 根据传入的字符串内容创建字符串 |
|
|
|
+| `String s = "abc"` | 直接赋值方式创建(常用) |
|
|
|
+
|
|
|
+```java
|
|
|
+String s1 = new String(); // 空白字符串
|
|
|
+char[] chs = {'H', 'e', 'l', 'l', 'o'};
|
|
|
+String s2 = new String(chs); // "Hello"
|
|
|
+String s3 = new String("Hello"); // "Hello"
|
|
|
+String s4 = "Hello"; // 直接赋值
|
|
|
+```
|
|
|
+> 📄 来源:`api/StringTest.java`
|
|
|
+
|
|
|
+#### 6.2.3 `==` 与 `equals()` 的区别
|
|
|
+
|
|
|
+| 比较方式 | 基本数据类型 | 引用数据类型 |
|
|
|
+|----------|-------------|-------------|
|
|
|
+| **`==`** | 比较具体的值 | 比较内存地址 |
|
|
|
+| **`equals()`** | — | 比较对象的内容(String 已重写) |
|
|
|
+
|
|
|
+```java
|
|
|
+String s4 = new String("Hello");
|
|
|
+String s5 = new String("Hello");
|
|
|
+System.out.println(s4 == s5); // false —— 比较地址
|
|
|
+System.out.println(s4.equals(s5)); // true —— 比较内容
|
|
|
+```
|
|
|
+> 📄 来源:`api/StringTest.java`
|
|
|
+
|
|
|
+### 6.3 String 常用方法
|
|
|
+
|
|
|
+```java
|
|
|
+String str1 = " hello world ";
|
|
|
+String str2 = " Hello World ";
|
|
|
+```
|
|
|
+
|
|
|
+#### 6.3.1 比较方法
|
|
|
+
|
|
|
+| 方法 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `equals(String s)` | 比较字符串内容是否相同,**区分大小写** |
|
|
|
+| `equalsIgnoreCase(String s)` | 比较字符串内容是否相同,**不区分大小写** |
|
|
|
+
|
|
|
+```java
|
|
|
+boolean b = str1.equals(str2); // false
|
|
|
+boolean b1 = str1.equalsIgnoreCase(str2); // true(忽略大小写)
|
|
|
+```
|
|
|
+
|
|
|
+#### 6.3.2 获取信息方法
|
|
|
+
|
|
|
+| 方法 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `length()` | 返回字符串长度 |
|
|
|
+| `charAt(int index)` | 返回指定索引位置的字符 |
|
|
|
+| `isEmpty()` | 判断字符串是否为空(长度为 0) |
|
|
|
+| `isBlank()` | 判断字符串是否为空或空白字符(JDK 11+) |
|
|
|
+
|
|
|
+```java
|
|
|
+int len = str1.length(); // 15
|
|
|
+char c = str1.charAt(2); // ' '
|
|
|
+boolean e = str1.isEmpty(); // false
|
|
|
+boolean b = str1.isBlank(); // false(JDK 11+)
|
|
|
+```
|
|
|
+
|
|
|
+#### 6.3.3 截取与查找方法
|
|
|
+
|
|
|
+| 方法 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `substring(int begin, int end)` | 截取字符串 `[begin, end)`,含头不含尾 |
|
|
|
+| `indexOf(String s)` | 返回子字符串第一次出现的位置,未找到返回 -1 |
|
|
|
+| `contains(String s)` | 判断是否包含指定子字符串 |
|
|
|
+| `startsWith(String s)` | 判断是否以指定字符串开头 |
|
|
|
+| `endsWith(String s)` | 判断是否以指定字符串结尾 |
|
|
|
+
|
|
|
+```java
|
|
|
+String sub = str1.substring(0, 5); // " hel"(索引0~4)
|
|
|
+int idx = str1.indexOf("lo"); // 2
|
|
|
+boolean b = str1.contains("world"); // true
|
|
|
+```
|
|
|
+
|
|
|
+#### 6.3.4 转换与替换方法
|
|
|
+
|
|
|
+| 方法 | 说明 |
|
|
|
+|------|------|
|
|
|
+| `toUpperCase()` | 字符串转大写 |
|
|
|
+| `toLowerCase()` | 字符串转小写 |
|
|
|
+| `trim()` | 去除首尾空格(半角) |
|
|
|
+| `strip()` | 去除首尾全角/半角空格(JDK 11+) |
|
|
|
+| `replace(String old, String new)` | 将旧字符串替换为新字符串 |
|
|
|
+| `split(String regex)` | 按指定字符分割为字符串数组 |
|
|
|
+| `String.join(String delimiter, CharSequence... elements)` | 使用指定分隔符拼接多个字符串 |
|
|
|
+
|
|
|
+```java
|
|
|
+String upper = str1.toUpperCase(); // " HELLO WORLD "
|
|
|
+String lower = str1.toLowerCase(); // " hello world "
|
|
|
+String trim = str1.trim(); // "hello world"
|
|
|
+String strip = str1.strip(); // "hello world"(JDK 11+)
|
|
|
+String replace = str1.replace("world", "java"); // " hello java "
|
|
|
+
|
|
|
+String[] arr = "A,B,C".split(","); // ["A", "B", "C"]
|
|
|
+String joined = String.join("-", "A", "B", "C"); // "A-B-C"
|
|
|
+```
|
|
|
+> 📄 来源:`api/StringTest02.java`
|
|
|
+
|
|
|
+> **注意**:`String` 类比较特殊,**打印其对象名时不会输出内存地址,而是输出该对象所记录的字符串内容**。这个特性是通过重写 `Object` 类的 `toString()` 方法实现的。
|
|
|
+
|
|
|
---
|
|
|
|
|
|
-## 六、匿名内部类应用场景总结
|
|
|
+## 七、匿名内部类应用场景总结
|
|
|
|
|
|
| 场景 | 说明 | 示例 |
|
|
|
|------|------|------|
|
|
|
@@ -325,7 +573,7 @@ System.out.println(max.getName());
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 七、随堂练习要点
|
|
|
+## 八、随堂练习要点
|
|
|
|
|
|
> 📄 对应练习文件:`课堂练习题/20260727-内部类练习.md`
|
|
|
|
|
|
@@ -339,7 +587,7 @@ System.out.println(max.getName());
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 八、拓展阅读
|
|
|
+## 九、拓展阅读
|
|
|
|
|
|
- [Java 匿名内部类(Anonymous Inner Class)详解](https://docs.oracle.com/javase/tutorial/java/javaOO/anonymous.html)
|
|
|
- 内部类与 Lambda 表达式的关系(后续课程会详细讲解)
|