前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >JAVA知识总结

JAVA知识总结

原创
作者头像
lfffffy
修改2024-12-26 18:37:21
修改2024-12-26 18:37:21
770
举报

A24计科6班-罗坤

第1章 初识Java与面向对象程序设计

1.1 Java概述

核心概念

  • 计算机编程语言的发展历程:机器语言、汇编语言、高级语言。
  • Java语言的发展史:James Gosling、Oak语言、不同版本的Java(如JDK1.0到JDK17)。
  • Java的三个版本:Java SE、Java EE、Java ME。

知识点

  • 了解Java语言的背景和演变过程。
  • 理解Java SE、Java EE、Java ME的区别和应用场景。

1.2 面向对象程序设计思想

核心概念

  • 面向过程程序设计:以过程为中心,关注步骤。
  • 面向对象程序设计(OOP):以对象为中心,关注数据和行为的封装。
  • OOP的四大特性:抽象、封装、继承、多态。

知识点

  • 区分面向过程和面向对象的程序设计方法。
  • 理解OOP的基本原则及其在Java中的实现。

1.3 Java开发环境搭建

核心概念

  • JDK(Java Development Kit):Java开发工具包,包括编译器、JRE等。
  • JRE(Java Runtime Environment):Java运行环境,包括JVM和类库。
  • 环境变量配置:设置JAVA_HOME、Path等。

知识点

  • 安装和配置JDK。
  • 验证Java环境的安装是否成功。

1.4 第一个Java程序:HelloWorld!

核心概念

  • Java程序的基本结构:类、方法、主方法(main method)。
  • 编译和运行Java程序的步骤。
  • 注释的使用:单行注释、多行注释、文档注释。

知识点

  • 使用文本编辑器编写Java源代码。
  • 使用javac命令编译Java程序。
  • 使用java命令运行Java程序。
  • 掌握正确的代码注释方法。

示例代码

下面是一个简单的HelloWorld.java程序,展示了Java程序的基本结构和注释的使用。

代码语言:java
复制
/**
 * 这是一个简单的Java程序,用于输出"Hello, World!"。
 */
public class HelloWorld {

    /**
     * 程序的主方法,执行程序的入口。
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 输出 Hello, World! 到控制台
        System.out.println("Hello, World!");
    }
}

编译和运行步骤

  1. 使用记事本或其他文本编辑器将上述代码保存为HelloWorld.java
  2. 打开命令行窗口,切换到HelloWorld.java所在的目录。
  3. 编译程序:javac HelloWorld.java
  4. 运行程序:java HelloWorld
  5. 控制台应显示Hello, World!

1.5 Java常用开发工具

核心概念

  • Eclipse:一个流行的Java IDE,支持代码编辑、编译、调试等功能。
  • IntelliJ IDEA:另一个强大的Java IDE,提供高级的代码分析和项目管理工具。

知识点

  • 了解Eclipse和IntelliJ IDEA的基本功能。
  • 安装和初步使用这些IDE进行Java程序的编写和运行。

总结

通过这一章,我能够:

  • 理解Java语言的发展背景和不同版本的特点。
  • 掌握面向对象程序设计的基本概念和原则。
  • 搭建Java开发环境,正确配置JDK和环境变量。
  • 编写、编译和运行一个简单的Java程序。
  • 了解并尝试使用常见的Java IDE工具,如Eclipse和IntelliJ IDEA。

第2章 Java编程基础

2.1 变量与常量

核心概念

  • 变量(Variable): 在程序中可以改变的存储单元,用于存储数据。
  • 常量(Constant): 在程序中不可改变的值,一旦赋值后不能更改。
  • 标识符(Identifier): 用于类、方法、变量等的命名,需遵循Java的命名规则。
  • 数据类型(DataType): 定义变量或常量可以存储的数据的种类。

知识点

  1. 关键字和保留字: Java中的classpublic等是关键字,不能作为标识符使用;保留字是为Java未来版本预留的关键字。
  2. 标识符命名规范:
    • 以字母、下划线_或美元符号$开头。
    • 不能以数字开头。
    • 区分大小写。
    • 驼峰命名法:首单词全小写,后续单词首字母大写。
  3. 基本数据类型:
    • 整型:byteshortintlong
    • 浮点型:floatdouble
    • 字符型:char
    • 布尔型:boolean
  4. 变量的定义与赋值:
    • 语法:DataType VariableName = Value;
    • 例如:int age = 20;double price = 19.95;
  5. 常量的定义:
    • 使用final关键字。
    • 例如:final double PI = 3.14159;

示例代码

代码语言:java
复制
// 定义变量与常量
public class VariablesAndConstants {
    public static void main(String[] args) {
        // 变量定义与赋值
        int studentNumber = 100;
        double averageScore = 85.5;
        char grade = 'A';
        
        // 常量定义
        final double PI = 3.14159;
        final int MAX_STUDENTS = 200;
        
        // 打印变量与常量
        System.out.println("Student Number: " + studentNumber);
        System.out.println("Average Score: " + averageScore);
        System.out.println("Grade: " + grade);
        System.out.println("PI: " + PI);
        System.out.println("Maximum Students: " + MAX_STUDENTS);
    }
}

运行结果

代码语言:java
复制
Student Number: 100
Average Score: 85.5
Grade: A
PI: 3.14159
Maximum Students: 200

个人理解与心得

刚开始学习变量和常量的时候,对标识符的命名规则有些困惑,尤其是哪些字符可以作为开头,哪些不可以。通过记忆和练习,逐渐掌握了驼峰命名法,并且理解了变量和常量在程序中的不同用途。赋值时需要注意数据类型的匹配,避免类型不兼容的问题。

2.2 运算符与表达式

核心概念

  • 运算符(Operator): 用于对数据进行运算的符号。
  • 表达式(Expression): 由变量、常量和运算符组成的有意义的式子,可以被计算出一个值。

知识点

  1. 算术运算符:
    • +-*/%(取余)
    • 例如:int sum = 10 + 5;int remainder = 10 % 3;remainder = 1
  2. 赋值运算符:
    • =+=-=*=/=%= 等。
    • 例如:int a = 5;a += 3;a = 8
  3. 关系运算符:
    • ==!=><>=<=
    • 用于比较两个值,返回布尔值。
    • 例如:boolean isEqual = (10 == 20);isEqual = false
  4. 逻辑运算符:
    • &&(与)、||(或)、!(非)
    • 用于组合多个关系表达式。
    • 例如:!(10 > 5) || (20 < 30)true
  5. 位运算符:
    • &|^(异或)、~(取反)、<<(左移)、>>(右移)
    • 用于对位进行操作,较少用于日常编程。
  6. 三元运算符:
    • ? : 用于根据条件选择两个表达式中的一个。
    • 例如:int max = (a > b) ? a : b;

示例代码

代码语言:java
复制
// 运算符与表达式的使用
public class OperatorsAndExpressions {
    public static void main(String[] args) {
        int a = 10, b = 20;
        double c = 15.5;
        
        // 算术运算符
        System.out.println("a + b = " + (a + b));
        System.out.println("a - b = " + (a - b));
        System.out.println("a * c = " + (a * c));
        System.out.println("b / a = " + (b / (double)a));
        System.out.println("b % a = " + (b % a));
        
        // 赋值运算符
        a += 5;  // a = a + 5 → 15
        System.out.println("a after += 5: " + a);
        
        // 关系运算符
        boolean isGreater = (a > b);  // false
        System.out.println("Is a > b? " + isGreater);
        
        // 逻辑运算符
        boolean condition = (a > 5) && (c < 20);  // true
        System.out.println("Condition: " + condition);
        
        // 三元运算符
        int max = (a > b) ? a : b;
        System.out.println("Max of a and b: " + max);
    }
}

运行结果

代码语言:java
复制
a + b = 30
a - b = -10
a * c = 155.0
b / a = 2.0
b % a = 10
a after += 5: 15
Is a > b? false
Condition: true
Max of a and b: 20

个人理解与心得

运算符是编程中的基础,理解每种运算符的用法和优先级非常重要。刚开始的时候,我对位运算符不太熟悉,但通过练习和查阅资料,逐渐掌握了它们的使用场景。特别是三元运算符,虽然简洁,但在某些情况下可以替代if语句,使代码更加优雅。不过,需要注意的是,三元运算符不应嵌套使用,否则会降低代码的可读性。

2.3 选择结构

核心概念

  • 选择结构(Selection结构): 根据条件选择执行不同代码块的程序结构。
  • if语句: 最基本的选择结构,用于单一条件判断。
  • switch语句: 用于多个条件的精确匹配。

知识点

1、if语句:

  • 基本形式:
    • if (条件) {代码块}
    • if (条件) {代码块} else {代码块}
    • if else if链用于多个条件判断。
  • 例如:
代码语言:java
复制
if (score > 90) {
    grade = 'A';
} else if (score > 80) {
    grade = 'B';
} else {
    grade = 'C';
}

2、switch语句:

  • 用于基于特定值的选择。
  • 语法:
代码语言:java
复制
switch (表达式) {
    case 值1:
        代码块1;
        break;
    case 值2:
        代码块2;
        break;
    ...
    default:
        代码块n;
}

例如:

代码语言:java
复制
switch (day) {
    case "Monday":
        System.out.println("开始新的一周");
        break;
    case "Friday":
        System.out.println("即将周末");
        break;
    default:
        System.out.println("普通的一天");
}

3、嵌套选择结构:

  • 在一个选择结构中包含另一个选择结构。
  • 需要注意代码的可读性和逻辑的复杂度。

示例代码:

代码语言:java
复制
// 选择结构示例
public class Selection Structures {
    public static void main(String[] args) {
        int score = 85;
        char grade;
        
        // if else if 结构
        if (score > 90) {
            grade = 'A';
        } else if (score > 80) {
            grade = 'B';
        } else if (score > 70) {
            grade = 'C';
        } else if (score > 60) {
            grade = 'D';
        } else {
            grade = 'F';
        }
        System.out.println("Grade: " + grade);
        
        // switch结构
        String day = "Friday";
        switch (day) {
            case "Monday":
                System.out.println("开始新的一周");
                break;
            case "Tuesday":
            case "Wednesday":
            case "Thursday":
                System.out.println("工作日");
                break;
            case "Friday":
                System.out.println("即将周末");
                break;
            case "Saturday":
            case "Sunday":
                System.out.println("周末");
                break;
            default:
                System.out.println("未知的日期");
        }
    }
}

运行结果:

代码语言:java
复制
Grade: B
即将周末

个人理解与心得

选择结构是控制程序流程的关键工具。if语句简单直接,但当条件较多时,使用if else if链可以保持代码的清晰。switch语句在处理枚举或已知的固定值时非常方便,但需要注意每个case后的break,避免程序流向下执行。嵌套选择结构虽然强大,但容易使逻辑复杂化,影响代码的可维护性。在实际开发中,应尽量简化逻辑,避免过多的嵌套。

2.4 循环结构

核心概念

  • 循环结构(Loop): 重复执行某段代码,直到满足特定条件。
  • for循环: 用于已知循环次数的情况。
  • while循环: 用于未知循环次数,先判断条件再执行。
  • do...while循环: 用于至少执行一次循环体,再判断条件。

知识点

1、for循环:

  • 语法: for (初始化表达式; 循环条件; 更新表达式) {代码块}
  • 例如:
代码语言:java
复制
for (int i = 0; i < 5; i++) {
    System.out.println("i = " + i);
}

2、while循环:

  • 语法: while (条件) {代码块}
  • 例如:
代码语言:java
复制
while (balance > 0) {
    withdraw(10);
    balance -= 10;
}

3、do...while循环:

  • 语法: do {代码块} while (条件);
  • 例如:
代码语言:java
复制
do {
    System.out.println("至少执行一次");
} while (false);

4、循环控制语句:

  • break:跳出当前循环。
  • continue:跳过当前迭代,继续下一次循环。
  • 例如:
代码语言:java
复制
for (int i = 0; i < 10; i++) {
    if (i == 5) continue;
    System.out.println(i);
}

运行结果会跳过5,打印0到9,除了5。

5、嵌套循环:

  • 在一个循环中包含另一个循环。
  • 需要注意循环的层数和控制条件。

示例代码:

代码语言:java
复制
// 循环结构示例
public class Loops {
    public static void main(String[] args) {
        // for循环
        for (int i = 1; i <= 10; i++) {
            System.out.println("Number: " + i);
        }
        
        // while循环
        int j = 1;
        while (j <= 10) {
            System.out.println("Number: " + j);
            j++;
        }
        
        // do...while循环
        int k = 1;
        do {
            System.out.println("Number: " + k);
            k++;
        } while (k <= 10);
        
        // 嵌套循环
        for (int row = 1; row <= 3; row++) {
            for (int col = 1; col <= 3; col++) {
                System.out.print(row * col + " ");
            }
            System.out.println();
        }
    }
}

运行结果:

代码语言:java
复制
Number: 1
Number: 2
...
Number: 10
代码语言:java
复制
Number: 1
Number: 2
...
Number: 10
代码语言:java
复制
Number: 1
Number: 2
...
Number: 10
代码语言:java
复制
1 2 3 
2 4 6 
3 6 9 

个人理解与心得

循环结构是编程中非常重要的部分,用于重复执行任务。for循环适合已知循环次数的情况,而while和do...while则适用于未知次数的循环。理解不同循环的适用场景,能够帮助我们写出更高效、更可读的代码。嵌套循环虽然强大,但容易导致逻辑复杂,因此在使用时应谨慎,确保每层循环的条件和控制变量清晰明了。此外,breakcontinue是控制循环流程的重要工具,但过多使用可能会降低代码的可维护性,应合理使用。

2.5 方法

核心概念

  • 方法(Method): 在类中定义的具有特定功能的子程序,用于执行特定的任务。
  • 方法重载(Method Overloading): 同一个类中,方法名相同但参数列表不同的多个方法。

知识点

1、方法的定义:

  • 语法: 修饰符 返回类型 方法名(参数列表) {方法体}
  • 例如:
代码语言:java
复制
public static void greet(String name) {
    System.out.println("Hello, " + name);
}

2、方法的调用:

  • 通过对象调用实例方法,或通过类名调用静态方法。
  • 例如: greet("Luo");Hello, Luo

3、方法重载:

  • 允许多个方法具有相同的方法名,但参数类型或数量不同。
  • 例如:
代码语言:java
复制
public static void greet() {
    System.out.println("Hello, Stranger");
}

public static void greet(String name) {
    System.out.println("Hello, " + name);
}

4、递归方法(Recursive Method):方法调用自身。

  • 例如,计算阶乘:
代码语言:java
复制
public static int factorial(int n) {
    if (n <= 1) return 1;
    else return n * factorial(n - 1);
}

5、可变参数(Varargs):允许方法接受不定数量的参数。

  • 语法: 修饰符 返回类型 方法名(参数类型 ... 参数名) {方法体}
  • 例如:
代码语言:java
复制
public static void printNumbers(int... numbers) {
    for (int number : numbers) {
        System.out.print(number + " ");
    }
}

6、返回值:

  • 方法可以返回一个值给调用者,使用return语句。
  • 例如: return x + y;

示例代码

代码语言:java
复制
// 方法示例
public class Methods {
    // 定义一个无参数的方法
    public static void greet() {
        System.out.println("Hello, Stranger");
    }
    
    // 定义一个有参数的方法
    public static void greet(String name) {
        System.out.println("Hello, " + name);
    }
    
    // 定义一个有返回值的方法
    public static int add(int a, int b) {
        return a + b;
    }
    
    // 定义一个可变参数的方法
    public static void printNumbers(int... numbers) {
        for (int number : numbers) {
            System.out.print(number + " ");
        }
        System.out.println();
    }
    
    public static void main(String[] args) {
        greet();  // 调用无参数方法
        greet("Luo");  // 调用有参数方法
        int sum = add(5, 10);  // 调用有返回值的方法
        System.out.println("Sum: " + sum);
        printNumbers(1, 2, 3, 4, 5);  // 调用可变参数的方法
    }
}

运行结果:

代码语言:java
复制
Hello, Stranger
Hello, Luo
Sum: 15
1 2 3 4 5 

个人理解与心得

方法是组织和重用代码的基本单元。通过定义方法,我们可以将复杂的任务分解成更小、更易管理的部分。方法重载增加了方法的灵活性,使我们能够用不同的参数来执行类似的操作。递归方法在处理某些问题时非常有用,如阶乘和树结构的遍历,但需要注意基例的设定,以避免无限递归。可变参数使得方法能够接受不定数量的参数,增加了方法的通用性。理解方法的定义、调用和返回值的处理,是编写结构化程序的基础。

2.6 数组

核心概念

  • 数组(Array): 一种线性数据结构,用于存储相同类型的元素的集合。
  • 数组索引(Index): 访问数组元素的位置,从0开始。

知识点

1、数组的声明与初始化:

  • 声明: DataType[] arrayName;DataType arrayName[];
  • 初始化:
    • 静态初始化: int[] numbers = {1, 2, 3, 4, 5};
    • 动态初始化: int[] numbers = new int[5]; 然后逐个赋值。

2、数组的长度:

  • arrayName.length 返回数组的长度。

3、数组的遍历:

  • 使用for循环: for (int i = 0; i < arrayName.length; i++) { System.out.println(arrayName[i]); }
  • 使用增强for循环(foreach): for (DataType element : arrayName) { System.out.println(element); }

4、二维数组:

  • 声明: DataType[][] arrayName;
  • 初始化: int[][] matrix = { {1, 2}, {3, 4}, {5, 6} };

5、数组的排序:

  • 使用Arrays.sort(arrayName); 对数组进行排序。

6、数组的复制:

  • 使用System.arraycopy(src, srcPos, dest, destPos, length); 进行数组复制。

7、数组的搜索:

  • 使用Arrays.binarySearch(sortedArray, key); 进行二分查找。

示例代码

代码语言:java
复制
// 数组示例
public class Arrays {
    public static void main(String[] args) {
        // 一维数组的声明与初始化
        int[] numbers = {1, 2, 3, 4, 5};
        System.out.println("First element: " + numbers[0]);
        numbers[1] = 10;  // 修改元素
        System.out.println("Modified second element: " + numbers[1]);
        System.out.println("Length of array: " + numbers.length);
        
        // 遍历数组
        for (int number : numbers) {
            System.out.print(number + " ");
        }
        System.out.println();
        
        // 二维数组的声明与初始化
        int[][] matrix = { {1, 2}, {3, 4}, {5, 6} };
        System.out.println("Matrix elements:");
        for (int[] row : matrix) {
            for (int element : row) {
                System.out.print(element + " ");
            }
            System.out.println();
        }
    }
}

运行结果:

代码语言:java
复制
First element: 1
Modified second element: 10
Length of array: 5
1 10 3 4 5 
Matrix elements:
1 2 
3 4 
5 6 

个人理解与心得

数组是存储和管理数据的基本数据结构,特别适用于存储相同类型的大量数据。理解数组的声明、初始化和索引的使用,是处理集合数据的基础。遍历数组是常见的操作,无论是使用传统的for循环还是增强for循环,都需要熟练掌握。二维数组在处理表格或矩阵数据时非常有用,但需要注意嵌套循环的逻辑。数组的排序和搜索方法,如Arrays.sortArrays.binarySearch,提供了高效的工具,但需要理解其背后的算法原理,以便在需要时能够手动实现。

2.7 JVM中的堆内存与栈内存

核心概念

  • 栈内存(Stack Memory):用于存储局部变量和方法调用的栈帧。
  • 堆内存(Heap Memory): 用于存储对象和数组,由垃圾回收器管理。

知识点

1、栈内存的特点:

生命周期与方法调用相关,方法执行完毕后,栈帧被销毁。

存取速度快,因为栈的存取是线性的。

栈溢出(StackOverflow):当方法调用层级过多或局部变量过多时发生。

2、堆内存的特点:

生命周期长,对象在堆中分配,直到不再被引用时被垃圾回收。

存取速度较栈慢,因为堆的存取是非线性的。

内存泄漏(Memory Leak):当对象不再被使用但未被正确回收时发生。

3、对象的内存分配:

使用new关键字在堆中分配对象。

对象的引用变量存储在栈中,指向堆中的对象。

4、数组的内存分配:

数组本质上也是对象,因此数组的元素存储在堆中。

数组的引用变量存储在栈中。

示例代码

代码语言:java
复制
// 堆和栈的示例
public class HeapAndStack {
    public static void main(String[] args) {
        // 栈内存:局部变量
        int a = 10;
        int b = 20;
        
        // 堆内存:对象和数组
        int[] numbers = new int[5];
        numbers[0] = 1;
        numbers[1] = 2;
        numbers[2] = 3;
        numbers[3] = 4;
        numbers[4] = 5;
        
        // 打印堆和栈的信息
        System.out.println("a: " + a);  // 栈中的变量
        System.out.println("numbers: " + numbers);  // 堆中的数组
        System.out.println("First element of numbers: " + numbers[0]);
    }
}

运行结果

代码语言:java
复制
a: 10
numbers: [I@15db9742
First element of numbers: 1

个人理解与心得

理解JVM中的堆和栈内存对于编写高效的Java程序至关重要。栈内存主要用于存储局部变量和方法调用的上下文,访问速度快,但生命周期较短。堆内存用于存储对象和数组,由垃圾回收器管理,访问速度相对较慢。需要注意的是,虽然局部变量存储在栈中,但它们引用的对象却存储在堆中。这种分离意味着即使局部变量的生命周期结束,堆中的对象仍然存在,直到没有引用指向它们时才会被回收。这种内存管理机制有助于防止内存泄漏,但也需要程序员谨慎管理对象的引用,确保不再使用的对象能够被正确回收。

总结

通过这一章的学习,我对Java的基本编程概念有了更深入的理解。变量和常量的使用、不同的运算符、选择和循环结构、方法的定义与调用、数组的操作,以及JVM中的内存管理,都是构建复杂程序的基础。在学习过程中,我遇到了一些难点,比如运算符的优先级、方法的重载与递归、以及堆和栈内存的区别。通过大量的练习和查阅资料,我逐步克服了这些困难,提高了我的编程能力和问题解决技巧。接下来,我将继续深入学习Java的面向对象特性,进一步巩固我的编程基础。

第3章 面向对象程序设计(基础)

3.1 面向对象的概念

核心概念

  • 面向对象(OOP): 一种程序设计范式,通过将数据和处理数据的方法结合成对象来模拟现实世界。
  • 类(Class): 对象的模板,定义了一组具有相同属性和行为的对象。
  • 对象(Object): 类的实例,具有具体的属性值和行为。
  • 封装(Encapsulation): 将数据和操作数据的方法隐藏在对象内部,通过公共接口访问。
  • 继承(Inheritance): 允许一个类继承另一个类的属性和方法。
  • 多态(Polymorphism): 一个对象可以有多种形态,通过同一个接口可以调用不同的方法。

知识点

  1. 面向对象的基本原则:封装、继承、多态。
  2. 类与对象的关系:类是对象的抽象,对象是类的实例。
  3. 如何在Java中定义一个类和创建对象。

示例代码

代码语言:java
复制
// 定义一个 Student 类
public class Student {
    // 属性
    String name;
    int age;
    
    // 行为
    public void study() {
        System.out.println(name + " is studying.");
    }
    
    public void eat() {
        System.out.println(name + " is eating.");
    }
}

// 创建 Student 对象
public class Main {
    public static void main(String[] args) {
        Student stu1 = new Student();
        stu1.name = "Alice";
        stu1.age = 20;
        stu1.study();  // 输出: Alice is studying.
        stu1.eat();    // 输出: Alice is eating.
    }
}

个人理解与心得

刚开始接触面向对象的概念时,对类和对象的区别有些模糊。通过编写简单的Student类并创建对象,逐渐理解了类是抽象的模板,而对象是具体的实例。封装、继承、多态这三个特性如何在实际开发中应用,还需要进一步深入学习。

3.2 面向对象编程

核心概念

  • 类的定义: 使用class关键字定义类,包括类名、属性和方法。
  • 对象的创建: 使用new关键字实例化对象。
  • 成员变量与局部变量: 成员变量是类的属性,局部变量定义在方法内部。
  • 构造方法(Constructor): 用于初始化对象的特殊方法。

知识点

  1. 类的定义语法:class ClassName { /* members */ }
  2. 对象的创建:ClassName objectName = new ClassName();
  3. 成员变量的默认值和初始化。
  4. 匿名对象的使用。
  5. 对象在内存中的存储:栈和堆。

示例代码

代码语言:java
复制
// 定义一个 Student 类,包含构造方法
public class Student {
    String name;
    int age;
    
    // 构造方法
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public void introduce() {
        System.out.println("My name is " + name + " and I'm " + age + " years old.");
    }
}

// 创建 Student 对象
public class Main {
    public static void main(String[] args) {
        Student stu1 = new Student("Bob", 22);
        stu1.introduce();  // 输出: My name is Bob and I'm 22 years old.
    }
}

个人理解与心得

在这一部分,我深入理解了类的定义和对象的创建过程。通过引入构造方法,能够更方便地初始化对象的属性。匿名对象的概念有些复杂,但通过练习,我逐渐掌握了它的使用场景。对象在内存中的存储方式也是重要的知识点,理解栈和堆的区别有助于编写高效的程序。

3.3 构造方法

核心概念

  • 构造方法: 一个与类同名的特殊方法,用于初始化对象。
  • 重载构造方法: 一个类可以有多个构造方法,只要参数列表不同。

知识点

  1. 构造方法的定义:ClassName([params]) { /* initialization code */ }
  2. 重载构造方法的使用。
  3. this关键字在构造方法中的应用,用于区分同名变量。

示例代码

代码语言:java
复制
public class Rectangle {
    double length;
    double width;
    
    // 无参数的构造方法
    public Rectangle() {
        length = 0;
        width = 0;
    }
    
    // 有参数的构造方法
    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }
    
    public double area() {
        return length * width;
    }
}

public class Main {
    public static void main(String[] args) {
        Rectangle rect1 = new Rectangle();
        System.out.println("Area: " + rect1.area());  // 输出: Area: 0.0
        
        Rectangle rect2 = new Rectangle(5.0, 3.0);
        System.out.println("Area: " + rect2.area());  // 输出: Area: 15.0
    }
}

个人理解与心得

构造方法的重载让我能够用不同的方式初始化对象,这在实际开发中非常有用。this关键字的使用一开始有些混乱,但通过多练习,我学会了如何正确地用它来区分成员变量和局部变量。理解构造方法如何与对象的生命周期结合,有助于编写更加清晰和高效的代码。

3.4 this 关键字

核心概念

  • this 关键字: 代表当前对象的引用,用于访问当前对象的成员变量和方法。

知识点

  1. this用于区分同名的成员变量和局部变量。
  2. this可以调用当前对象的其他方法或构造方法。
  3. this不能在静态方法中使用,因为静态方法不属于任何对象。

示例代码

代码语言:java
复制
public class Person {
    String name;
    
    public Person(String name) {
        this.name = name;
    }
    
    public void sayHello() {
        System.out.println("Hello, my name is " + this.name);
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Kimi");
        person.sayHello();  // 输出: Hello, my name is Kimi
    }
}

个人理解与心得

this 关键字的使用一开始有些难以理解,特别是何时需要使用它。通过编写代码,我发现this在有同名变量时非常有用,能够清晰地区分成员变量和局部变量。此外,this还可以用于调用当前对象的其他方法,增强了代码的复用性。需要注意的是,this不能在静态方法中使用,因为静态方法不依赖于对象实例。

3.5 static 关键字

核心概念

  • static 关键字: 用于定义类的静态变量、静态方法和静态代码块。
  • 静态变量(类变量): 属于类的变量,所有对象共享。
  • 实例变量(成员变量): 属于对象的变量,每个对象有独立的副本。

知识点

  1. 静态变量的定义和访问。
  2. 静态方法的定义和使用。
  3. 静态代码块的使用。
  4. 静态成员与实例成员的区别。

示例代码

代码语言:java
复制
public class Bank {
    // 静态变量
    static int totalAccounts = 0;
    
    // 实例变量
    String accountHolder;
    double balance;
    
    public Bank(String accountHolder, double balance) {
        this.accountHolder = accountHolder;
        this.balance = balance;
        totalAccounts++;
    }
    
    // 静态方法
    public static void showTotalAccounts() {
        System.out.println("Total accounts: " + totalAccounts);
    }
}

public class Main {
    public static void main(String[] args) {
        Bank bank1 = new Bank("Alice", 1000.0);
        Bank bank2 = new Bank("Bob", 1500.0);
        Bank.showTotalAccounts();  // 输出: Total accounts: 2
    }
}

个人理解与心得

static 关键字让我能够定义属于类而不是对象的变量和方法。这在需要共享数据或提供工具方法时非常有用。静态变量的共享性质意味着它们在所有对象之间保持一致,这在计数或缓存等场景中非常有用。然而,过多使用静态变量和方法可能会使代码难以测试和维护,因此需要谨慎使用。

3.6 包

核心概念

  • 包(Package): 用于组织和管理类的命名空间,避免类名冲突。
  • 导入包(Import): 允许在当前类中使用其他包中的类。

知识点

  1. 定义包的语法:package packageName;
  2. 导入包的语法:import packageName.ClassName;import packageName.*;
  3. Java内置包如java.langjava.util等。
  4. 企业中通常使用反向域名作为包名,如com.companyname.projectname

示例代码

假设我们有两个包com.schoolcom.school.students

com.school包中有一个Teacher类:

代码语言:java
复制
package com.school;

public class Teacher {
    public void teach() {
        System.out.println("Teacher is teaching.");
    }
}

com.school.students包中有一个Student类:

代码语言:java
复制
package com.school.students;

import com.school.Teacher;

public class Student {
    public void studyWithTeacher(Teacher teacher) {
        teacher.teach();
        System.out.println("Student is studying with the teacher.");
    }
}

public class Main {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        Student student = new Student();
        student.studyWithTeacher(teacher);
        // 输出:
        // Teacher is teaching.
        // Student is studying with the teacher.
    }
}

个人理解与心得

包的概念一开始有些抽象,但通过实际操作,我理解了它在组织和管理类方面的重要性。合理地使用包能够避免类名冲突,使项目结构更加清晰。导入包的机制让我能够方便地使用其他包中的类,但需要注意避免循环依赖和过多的导入,这可能会导致项目结构混乱。

总结

通过第三章的学习,我系统地掌握了面向对象程序设计的基础知识,包括类与对象的概念、构造方法的使用、thisstatic关键字的应用,以及包的管理。这些知识点不仅加深了我对Java语言的理解,也为后续更复杂面向对象特性的学习打下了坚实的基础。在学习过程中,我遇到了一些理解上的困难,特别是thisstatic的使用场景,但通过大量的练习和实例编写,我逐渐克服了这些难点,能够更加自信地应用这些概念进行编程。

第4章 面向对象程序设计(进阶)

4.1 封装

核心概念

  • 封装的定义: 将对象的属性和实现细节隐藏起来,仅通过公共的访问方式与外界交互。
  • 访问修饰符: privateprotectedpublic,以及默认(无修饰符)。
  • getter和setter方法: 提供公共的接口来访问和修改私有属性。

知识点

  1. 封装的作用:
    • 提高代码的安全性:隐藏内部实现,防止外部直接访问。
    • 增强代码的复用性:通过公共接口操作,内部实现可以独立变化。
  2. 访问修饰符的使用:
    • private:仅在类内部可访问。
    • protected:在类及其子类中可访问。
    • public:在任何地方都可访问。
    • 默认(无修饰符):在同一个包内可访问。
  3. getter和setter方法的命名规范:
    • getter方法以get开头,后跟属性名,首字母大写,如getName()
    • setter方法以set开头,后跟属性名,首字母大写,如setName(name)

示例代码

代码语言:java
复制
public class Student {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 0 && age < 200) { // 验证年龄的合理性
            this.age = age;
        } else {
            System.out.println("年龄不合法");
        }
    }
}

个人理解与心得

封装让我意识到隐藏类的内部细节的重要性。通过提供getter和setter方法,不仅保护了数据,还使得类的接口更加清晰。然而,我一开始对访问修饰符的使用有些困惑,特别是protected和默认修饰符的区别。通过查阅资料和练习,我逐渐理解了它们在不同场景下的应用。难点在于理解protected修饰符的使用范围。最初,我不清楚protected是否能被其他包中的子类访问。通过查阅Java文档和做实验,我发现protected确实允许子类访问,即使它们在不同的包中。这帮助我明确了不同访问修饰符的适用场景。

4.2 继承

核心概念

  • 继承的定义: 允许一个类(子类)继承另一个类(父类)的属性和方法。
  • 继承的关键字: extends
  • 方法重写: 子类可以提供与父类不同的方法实现。

知识点

  1. 继承的使用:
    • 子类继承父类的公共和受保护的成员。
    • 子类可以添加新的属性和方法,或重写父类的方法。
  2. 方法重写的规则:
    • 方法名和参数列表必须与父类相同。
    • 子类的访问权限不能低于父类。
    • 子类的返回类型必须与父类相同或为子类型。
  3. 继承的限制:
    • Java支持单继承,即一个子类只能有一个直接父类。
    • 但支持多层继承,如A类继承B类,B类继承C类。

示例代码

代码语言:java
复制
class People {
    protected String name;
    protected int age;

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println("人会吃东西");
    }
}

class Teacher extends People {
    public Teacher(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("老师会吃东西,但可能更健康");
    }

    public void teach() {
        System.out.println("老师会教学");
    }
}

class Worker extends People {
    public Worker(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("工人会吃东西,可能更实在");
    }

    public void work() {
        System.out.println("工人会工作");
    }
}

个人理解与心得

继承是面向对象编程的核心之一。它通过extends关键字实现,使得子类可以复用父类的代码,同时添加新的功能。方法重写让我看到了多态性的初步面貌,即同一个方法名在不同类中可以有不同的行为。我一开始对方法重写的规则有些模糊,特别是关于访问权限和返回类型的部分。通过编写示例代码并运行,我逐步理解了这些规则的实际应用。在方法重写时,我曾困惑于如何正确地重写父类的方法,尤其是当父类方法有多个重载时。我通过查阅资料和反复编写测试代码,最终掌握了方法重写的细节。此外,理解单继承和多层继承的区别也花了一些时间,但通过类比和练习,我逐渐理清了思路。

4.3 super关键字

核心概念

  • super的定义: 指向当前对象的直接父类对象的引用。
  • super的使用:
    • 调用父类的构造方法。
    • 调用父类的成员方法和属性,特别是在子类中重写的方法。

知识点

  1. super的使用场景:
    • 在子类的构造方法中,通常第一行使用super()调用父类的构造方法。
    • 在子类的方法中,可以使用super.methodName()调用父类的方法。
  2. super与this的区别:
    • this指向当前对象,可以访问当前类的所有成员。
    • super指向父类对象,只能访问父类的成员,不能访问子类的成员。
  3. super的注意事项:
    • super不能在static方法中使用,因为static方法不与对象实例关联。
    • super只能访问直接父类的成员,不能访问更高级的父类。

示例代码

代码语言:java
复制
class Teacher extends People {
    public Teacher(String name, int age) {
        super(name, age); // 调用父类的构造方法
    }

    public void eat() {
        super.eat(); // 调用父类的eat方法
        System.out.println("老师会吃东西,但可能更健康");
    }
}

个人理解与心得

super关键字在继承中扮演着重要角色,尤其是在调用父类的构造方法和重写的方法时。通过super,子类可以方便地复用父类的实现,同时添加自己的逻辑。我一开始对superthis的区别有些模糊,但通过编写示例代码并观察它们的行为,我逐渐理解了它们各自的应用场景。难点在于理解super只能访问直接父类的成员,而不能访问更高级的父类。在实际编程中,我曾尝试使用super调用祖父类的方法,结果出现了编译错误。通过查阅资料和反复测试,我明白了super的这一限制,从而避免了类似的错误。

4.4 final关键字

核心概念

  • final的定义: 用于声明常量,修饰类、方法和变量。
  • final类: 不能被继承。
  • final方法: 不能被重写。
  • final变量: 一旦赋值,不能改变。

知识点

1、final类的使用:

  • 不能被继承,通常用于定义一些工具类或不希望被扩展的类。

2、final方法的使用:

  • 不能被子类重写,通常用于定义一些不希望被改变的方法。

3、final变量的使用:

  • 一旦赋值,不能改变,通常用于定义常量。

4、final的注意事项:

  • final不能用于局部变量的返回类型。
  • final不能用于抽象方法。

示例代码

代码语言:java
复制
public final class MathUtils {
    public final static double PI = 3.1415926;

    public final double calculateCircleArea(double radius) {
        return PI * radius * radius;
    }
}

个人理解与心得

final关键字在Java中用于定义不可变的元素。通过将类、方法或变量声明为final,可以防止它们被继承、重写或重新赋值。我一开始对final在不同上下文中的应用有些不确定,但通过阅读和编写示例代码,我逐渐掌握了它的用法。特别是,理解final类和final方法如何增强代码的稳定性和安全性,让我对Java的类型系统有了更深的认识。在使用final时,我曾困惑于它与abstract的关系,尤其是在定义抽象类和方法时。通过查阅资料和实际编程,我明白了finalabstract是互斥的,final用于防止扩展,而abstract用于强制子类提供实现。这一理解帮助我正确地在项目中使用这两个关键字。

4.5 Object类

核心概念

  • Object类的定义: Java中所有类的根类,提供了所有类共有的方法。
  • 常用方法: toString()equals()hashCode()等。

知识点

  1. Object类的方法:
    • toString(): 返回对象的字符串表示。
    • equals(Object obj): 比较两个对象是否相等。
    • hashCode(): 返回对象的哈希码。
  2. 方法的重写:
    • 通常重写toString()以提供更有意义的字符串表示。
    • 重写equals()以根据对象的属性定义相等性。
    • 如果重写equals(),应同时重写hashCode()以保持一致性。

示例代码

代码语言:java
复制
class People {
    private String name;
    private int age;

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "People[name=" + name + ", age=" + age + "]";
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        People people = (People) obj;
        return age == people.age && name.equals(people.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

个人理解与心得

Object类是所有类的基类,提供了基本的方法。重写这些方法可以为我们的类提供更合适的行为。特别是,toString()方法在调试和日志记录中非常有用,equals()hashCode()则在集合框架中至关重要。我一开始对这些方法的重要性认识不足,但通过实际编写和测试,我看到了它们在实际应用中的价值。在重写equals()hashCode()时,我曾对如何正确实现这些方法感到困惑。通过查阅Java文档和示例代码,我学习到了最佳实践,例如在equals()中使用getClass()检查类型,并在hashCode()中使用Objects.hash()方法。此外,理解hashCode()的用途,特别是在哈希表中,帮助我避免了潜在的错误。

4.6 多态

核心概念

  • 多态的定义: 一个对象可以有多种形态,即同一个方法调用,由于对象不同,可能有不同的行为。
  • 多态的实现: 通过继承和方法重写实现。

知识点

1、多态的条件:

  • 存在继承关系。
  • 子类重写父类的方法。
  • 父类引用指向子类对象。

2、多态的类型:

  • 编译时多态(静态多态): 通过方法重载实现。
  • 运行时多态(动态多态): 通过方法重写实现。

3、多态的注意点:

  • 只有非static方法可以实现多态。
  • 变量访问的是引用类型的类,而不是实际对象的类。

示例代码

代码语言:java
复制
class People {
    public void eat() {
        System.out.println("人会吃东西");
    }
}

class Teacher extends People {
    @Override
    public void eat() {
        System.out.println("老师会吃东西,但可能更健康");
    }
}

class Worker extends People {
    @Override
    public void eat() {
        System.out.println("工人会吃东西,可能更实在");
    }
}

public class PolymorphismTest {
    public static void main(String[] args) {
        People p1 = new Teacher();
        p1.eat(); // 输出:老师会吃东西,但可能更健康

        p1 = new Worker();
        p1.eat(); // 输出:工人会吃东西,可能更实在
    }
}

个人理解与心得

多态是面向对象编程的三大特性之一,它允许同一个接口或父类引用指向不同的子类对象,并在运行时表现出不同的行为。这极大地增强了代码的灵活性和可扩展性。我一开始对多态的内部机制有些模糊,特别是如何在运行时决定调用哪个方法。通过编写示例代码并观察输出,我理解了JVM在运行时如何处理多态。理解多态与方法重写的关系曾是我的一个难点。我曾不清楚多态是否仅限于方法重写,还是也包括方法重载。通过查阅资料和实际编程,我明确了多态主要涉及方法重写,而方法重载更多是编译时的多态。此外,理解thissuper在多态中的作用,也帮助我更好地掌握了这一概念。

4.7 抽象类

核心概念

  • 抽象类的定义: 不能被实例化的类,通常作为父类,提供一些抽象方法。
  • 抽象方法: 没有方法体,必须由子类重写。

知识点

1、抽象类的使用:

  • 通过abstract关键字定义。
  • 不能直接实例化,只能作为父类被继承。

2、抽象方法的使用:

  • 通过abstract关键字定义,没有方法体。
  • 子类必须重写所有抽象方法才能实例化。

3、抽象类与接口的区别:

  • 抽象类可以有部分实现,而接口在JDK8之前只能定义抽象方法。
  • 子类通过extends继承抽象类,通过implements实现接口。

示例代码

代码语言:java
复制
public abstract class Shape {
    private String name;

    public Shape(String name) {
        this.name = name;
    }

    public abstract double getArea();

    public abstract double getPerimeter();

    public String getName() {
        return name;
    }
}

class Circle extends Shape {
    private double radius;

    public Circle(String name, double radius) {
        super(name);
        this.radius = radius;
    }

    @Override
    public double getArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public double getPerimeter() {
        return 2 * Math.PI * radius;
    }
}

class Rectangle extends Shape {
    private double width;
    private double height;

    public Rectangle(String name, double width, double height) {
        super(name);
        this.width = width;
        this.height = height;
    }

    @Override
    public double getArea() {
        return width * height;
    }

    @Override
    public double getPerimeter() {
        return 2 * (width + height);
    }
}

个人理解与心得

抽象类提供了一种定义接口的方式,同时可以包含一些具体的实现。通过将某些方法声明为抽象,父类可以强制子类提供特定的方法实现。这在设计具有共同属性和行为的类层次结构时非常有用。我一开始对抽象类和抽象方法的使用有些不确定,但通过编写示例代码并观察其行为,我逐渐理解了它们在实际项目中的应用。在理解抽象类与接口的关系时,我曾感到困惑。通过查阅资料和比较它们的定义与使用,我明确了抽象类可以包含部分实现,而接口更多用于定义完全抽象的规范。此外,理解抽象类在继承中的作用,帮助我更好地设计复杂的类层次结构。

4.8 接口

核心概念

  • 接口的定义: 定义了一组方法规范,由实现类提供具体实现。
  • 接口的实现: 通过implements关键字实现。

知识点

1、接口的使用:

  • 通过interface关键字定义。
  • 方法默认为public abstract
  • 可以定义常量。

2、实现接口:

  • 类通过implements关键字实现一个或多个接口。
  • 实现类必须提供接口中所有方法的具体实现。

3、接口的继承:

  • 接口可以继承其他接口,使用extends关键字。
  • 类似于抽象类,接口继承可以实现多继承。

示例代码

代码语言:java
复制
public interface USB {
    void connect();

    void disconnect();

    default void showInfo() {
        System.out.println("USB设备信息");
    }

    static void staticMethod() {
        System.out.println("USB静态方法");
    }
}

class Mouse implements USB {
    @Override
    public void connect() {
        System.out.println("鼠标连接");
    }

    @Override
    public void disconnect() {
        System.out.println("鼠标断开连接");
    }
}

class Keyboard implements USB {
    @Override
    public void connect() {
        System.out.println("键盘连接");
    }

    @Override
    public void disconnect() {
        System.out.println("键盘断开连接");
    }
}

个人理解与心得

接口提供了一种定义方法规范的方式,由实现类提供具体的实现。通过接口,可以定义一个通用的API,使得不同的实现类可以互换使用,极大地增强了代码的灵活性和可扩展性。我一开始对接口中的defaultstatic方法有些困惑,但通过查阅JDK8的新特性资料,我理解了这些方法的用途和实现方式。理解接口与抽象类的区别曾是我的一个难点。通过查阅资料和比较它们的定义与使用,我明确了接口更多用于定义完全抽象的规范,而抽象类可以包含部分实现。此外,理解接口在多继承中的作用,帮助我更好地设计复杂的系统。

4.9 内部类

核心概念

  • 内部类的定义: 定义在另一个类内部的类。
  • 内部类的类型:
    • 成员内部类(非静态)
    • 静态内部类
    • 局部内部类
    • 匿名内部类

知识点

1、成员内部类:

  • 可以访问外部类的所有成员,包括私有成员。
  • 必须通过外部类的对象创建实例。

2、静态内部类:

  • 通过static关键字定义。
  • 只能访问外部类的静态成员。
  • 不需要外部类的对象即可创建实例。

3、局部内部类:

  • 定义在方法或代码块中。
  • 只能在该方法或代码块中使用。

4、匿名内部类:

  • 没有类名,通常用于实现接口或继承类。
  • 通常用于创建一个只使用一次的对象。

示例代码

代码语言:java
复制
public class OuterClass {
    private String outerField = "外层类的字段";

    class InnerClass {
        public void accessOuter() {
            System.out.println("访问外层类的字段: " + outerField);
        }
    }

    static class StaticInnerClass {
        public static void staticMethod() {
            System.out.println("静态内部类的静态方法");
        }
    }

    public void methodWithLocalInnerClass() {
        class LocalInnerClass {
            public void display() {
                System.out.println("局部内部类");
            }
        }
        LocalInnerClass local = new LocalInnerClass();
        local.display();
    }

    public void methodWithAnonymousInnerClass(USB usb) {
        usb.connect();
    }
}

interface USB {
    void connect();
}

class Mouse implements USB {
    public void connect() {
        System.out.println("鼠标连接");
    }
}

个人理解与心得

内部类提供了更细粒度的封装,允许在类内部定义类,从而更好地组织和管理代码。成员内部类可以访问外部类的所有成员,这在某些情况下非常有用。静态内部类则提供了一种不需要外部类实例即可访问的途径。局部内部类和匿名内部类则在特定的上下文中提供了更大的灵活性。我一开始对内部类的使用有些不确定,特别是它们的访问权限和创建方式。通过编写示例代码并观察它们的行为,我逐渐理解了它们在实际项目中的应用。在理解匿名内部类的使用时,我曾感到困惑,特别是它们如何实现接口或继承类。通过查阅资料和编写示例代码,我明白了匿名内部类通常用于创建一个只使用一次的对象,特别是在实现接口或继承类时,它们可以提供一个简洁的语法。此外,理解局部内部类的作用范围,帮助我更好地组织方法内的代码。

总结

通过细致地梳理第四章的每个部分,我不仅清晰地理解了每个核心概念和知识点,还通过编写和测试示例代码,加深了对这些概念的理解。在学习过程中,我遇到了一些难点,如方法重写的规则、superthis的区别、抽象类与接口的关系等,但通过查阅资料、编写测试代码和反复练习,我成功地克服了这些难点。这不仅增强了我的理论知识,还提高了我的实际编程能力。

第五章 异常

5.1 异常概述

核心概念

  • 异常(Exception): 程序运行过程中出现的不正常现象,如文件不存在、网络连接失败等。
  • 错误(Error): 程序运行时遇到的严重问题,通常无法恢复,如内存溢出、堆栈溢出等。
  • Throwable类: 异常和错误的基类,提供了描述错误的方法,如toString()getMessage()printStackTrace()

知识点

1、异常与错误的区别:

  • 异常通常可以被程序捕获并处理,而错误通常导致程序终止。

2、Throwable类的层次结构:

  • Throwable是基类,ExceptionError都继承自Throwable
  • Exception分为检查型异常(Checked Exception)和非检查型异常(Unchecked Exception,即RuntimeException)。

3、异常处理的重要性:

  • 通过异常处理,程序可以优雅地处理错误,避免崩溃。

示例代码

代码语言:java
复制
try {
    // 可能抛出异常的代码
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("发生算术异常: " + e.getMessage());
} finally {
    System.out.println("finally块总是执行");
}

个人理解和心得

异常处理是确保程序鲁棒性的关键机制。通过try-catch结构,我们可以捕获并处理潜在的错误,防止程序意外终止。理解Throwable类的层次结构有助于我们更好地分类和处理不同类型的异常。最初,我对于ExceptionError的区别有些模糊,不清楚何时应该捕获Exception,何时应该让Error通过。通过查阅资料和编写示例代码,我意识到Error通常是由 JVM 抛出的,表示程序遇到了无法恢复的错误,而Exception则是可以被程序捕获和处理的。

5.2 异常处理

核心概念

  • 抛出异常(throw): 使用throw关键字手动抛出异常。
  • 声明异常(throws): 在方法签名中使用throws关键字声明该方法可能抛出的异常。
  • 捕获异常(try-catch): 使用try块包围可能抛出异常的代码,并通过catch块捕获和处理异常。
  • finally块: 无论是否捕获到异常,finally块中的代码总是执行,通常用于释放资源。

知识点

  1. 抛出异常的语法:
    • throw new Exception("错误信息");
  2. 声明异常的语法:
    • public void methodName() throws IOException, SQLException { ... }
  3. 捕获异常的结构:
    • try { ... } catch (ExceptionType e) { ... } finally { ... }
  4. 异常链:
    • 一个方法可以捕获异常并抛出新的异常,保留原始异常的栈信息。

示例代码

代码语言:java
复制
public class FileProcessor {
    public void readFile(String filePath) throws IOException {
        if (filePath == null) {
            throw new FileNotFoundException("文件路径不能为空");
        }
        // 读取文件的代码
    }
}

public class Main {
    public static void main(String[] args) {
        try {
            FileProcessor fp = new FileProcessor();
            fp.readFile("path/to/file.txt");
        } catch (FileNotFoundException e) {
            System.out.println("文件未找到: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("读取文件时发生错误: " + e.getMessage());
        } finally {
            System.out.println("处理完毕");
        }
    }
}

个人理解和心得

异常处理机制使我们能够更灵活地应对程序中的错误。通过合理使用throwthrows,我们可以控制异常的传播,使程序的错误处理更加集中和高效。try-catch-finally结构不仅能够捕获和处理异常,还能确保资源的正确释放,这对于编写高质量的软件至关重要。

小结

在使用throws声明异常时,我曾困惑于何时应该声明Exception,何时应该声明具体的异常类型,如IOExceptionSQLException。通过实际项目中的练习,我意识到声明具体的异常类型可以为调用者提供更明确的信息,有助于他们编写更精确的异常处理逻辑。

5.3 异常进阶

核心概念

  • 自定义异常: 根据应用程序的需要定义特定的异常类。
  • 方法重写中的异常: 子类在重写父类方法时,必须遵循某些规则,特别是在异常声明方面。

知识点

1、自定义异常的步骤:

  • 继承ExceptionRuntimeException类。
  • 提供构造方法,可以包含错误消息和cause(原因)。

2、方法重写中的异常规则:

  • 子类重写的方法不能声明比父类方法更宽泛的检查型异常。
  • 子类可以声明与父类相同的异常或更具体的异常,或者不声明任何异常。

示例代码

代码语言:java
复制
// 自定义异常
public class LoginException extends Exception {
    public LoginException(String message) {
        super(message);
    }
}

public class UserNotFoundException extends LoginException {
    public UserNotFoundException(String message) {
        super(message);
    }
}

public class PasswordWrongException extends LoginException {
    public PasswordWrongException(String message) {
        super(message);
    }
}

// 使用自定义异常
public class LoginService {
    public void login(String username, String password) throws LoginException {
        if (username == null || password == null) {
            throw new LoginException("用户名或密码不能为空");
        }
        if (!userExists(username)) {
            throw new UserNotFoundException("用户不存在");
        }
        if (!verifyPassword(username, password)) {
            throw new PasswordWrongException("密码错误");
        }
        // 登录逻辑
    }
}

个人理解和心得

自定义异常可以更精确地描述应用程序中的错误情况,使错误处理更加细粒度和可读。在方法重写时,遵循异常声明的规则确保了异常处理的一致性和可预测性,避免了因异常声明不当导致的编译错误。最初,我在定义自定义异常时不确定是否应该继承Exception还是RuntimeException。通过查阅资料和编写示例代码,我明白了如果希望调用者必须处理异常,应该继承Exception;如果异常是运行时异常,可以继承RuntimeException。此外,在方法重写时,确保子类的异常声明不比父类更宽泛,是避免编译错误的关键。

总结

通过系统地梳理第五章“异常”的内容,我不仅掌握了异常处理的基本机制,还深入理解了如何通过自定义异常和合理的方法声明来提升程序的鲁棒性和可维护性。在学习过程中,我遇到了一些关于异常声明和自定义异常使用的困惑,但通过编写示例代码和查阅相关资料,我成功地克服了这些难点,对异常处理有了更全面的认识。

第六章 Java常用类

6.1 包装类

核心概念:

  • 包装类(Wrapper Class): Java中,基本数据类型不是对象,但为了在需要对象的场景中使用,为每个基本数据类型提供了对应的包装类。
  • 自动装箱与拆箱: Java 5引入的特性,允许基本类型与对应的包装类对象之间自动转换。

知识点

1、包装类与基本类型的对应关系:

  • intInteger
  • doubleDouble
  • floatFloat
  • longLong
  • shortShort
  • byteByte
  • charCharacter
  • booleanBoolean

2、包装类的常用方法:

  • parseInt(String s): 将字符串转换为int。
  • valueOf(String s): 将字符串转换为对应的包装类对象。
  • toString(): 将包装类对象转换为字符串。

3、自动装箱与拆箱的使用:

  • 自动装箱:将基本类型直接赋值给对应的包装类引用。
  • 自动拆箱:将包装类对象直接使用为基本类型。

示例代码

代码语言:java
复制
// 自动装箱
Integer intObj = 100;  // 等同于 Integer.valueOf(100)

// 自动拆箱
int num = intObj;  // 等同于 intObj.intValue()

// 字符串转换
String s = "123";
int number = Integer.parseInt(s);  // 转换为int
Integer intObj2 = Integer.valueOf(s);  // 转换为Integer对象

个人理解和心得

理解包装类的概念对于在需要对象的场景中使用基本类型至关重要,例如在使用泛型时。自动装箱和拆箱简化了代码,减少了显式转换的需要。然而,需要注意的是,这些操作在背后涉及对象的创建和方法调用,不当使用可能会导致性能问题。最初,我对自动装箱和拆箱的具体工作原理感到困惑,特别是它们如何与泛型等其他Java特性相互作用。通过编写示例代码并逐步测试不同的转换,我更好地理解了这些特性的无缝集成。此外,通过阅读相关文档,我了解到了这些操作的性能影响,这对于编写高效的Java应用程序至关重要。

6.2 大数字运算

核心概念

  • BigInteger和BigDecimal: Java提供了这两个类来处理超出基本数值类型范围的任意精度整数和浮点数。
  • BigInteger: 用于精确的整数运算,没有上限,除了可用内存。
  • BigDecimal: 用于精确的浮点数运算,特别有用在需要高精度的金融计算中。

知识点

1、BigInteger的常用方法:

  • add(BigInteger val): 加法。
  • subtract(BigInteger val): 减法。
  • multiply(BigInteger val): 乘法。
  • divide(BigInteger val): 除法。

2、BigDecimal的常用方法:

  • add(BigDecimal val): 加法。
  • subtract(BigDecimal val): 减法。
  • multiply(BigDecimal val): 乘法。
  • divide(BigDecimal val, int roundingMode): 除法,带舍入模式。
  • setScale(int newScale, int roundingMode): 设置小数点精度和舍入模式。

示例代码

代码语言:java
复制
import java.math.BigInteger;
import java.math.BigDecimal;
import java.math.RoundingMode;

public class BigNumbersExample {
    public static void main(String[] args) {
        // BigInteger示例
        BigInteger bigInt1 = new BigInteger("12345678901234567890");
        BigInteger bigInt2 = new BigInteger("98765432109876543210");
        BigInteger sum = bigInt1.add(bigInt2);
        System.out.println("BigInteger相加结果: " + sum);

        // BigDecimal示例
        BigDecimal bigDec1 = new BigDecimal("1234567890.1234567890");
        BigDecimal bigDec2 = new BigDecimal("9876543210.9876543210");
        BigDecimal sumDec = bigDec1.add(bigDec2);
        System.out.println("BigDecimal相加结果: " + sumDec);

        // 设置精度
        BigDecimal rounded = bigDec1.setScale(2, RoundingMode.HALF_UP);
        System.out.println("BigDecimal设置精度: " + rounded);
    }
}

个人理解和心得

BigInteger和BigDecimal是处理大数运算的强大工具,特别是在需要高精度和大范围的金融或科学计算中。理解它们的方法和使用方式,可以让我在实际项目中更加灵活和准确地处理数值运算。在使用BigDecimal时,我最初对舍入模式感到困惑,不确定何时使用哪种模式。通过查阅文档并实验不同的舍入模式,我更好地理解了它们的行为。此外,记住在创建BigDecimal时使用字符串构造函数以避免精度问题,这一点至关重要。

6.3 String类

核心概念

  • String类: 表示不可变的Unicode字符序列。一旦创建,其值不能改变。
  • 不可变性: 确保字符串可以安全地共享,而不会被修改。

知识点

1、字符串的创建:

  • 使用双引号:String s = "Hello";
  • 使用字符数组:char[] chars = {'H', 'e', 'l', 'l', 'o'}; String s = new String(chars);
  • 使用byte数组:byte[] bytes = {72, 101, 108, 108, 111}; String s = new String(bytes, "UTF-8");

2、字符串的常用方法:

  • length(): 返回字符串的长度。
  • charAt(int index): 返回指定索引处的字符。
  • indexOf(String str): 返回子字符串的起始索引。
  • replace(char old, char new): 替换字符。
  • toUpperCase(), toLowerCase(): 转换大小写。
  • trim(): 去除首尾空格。
  • split(String regex): 根据正则表达式拆分字符串。

示例代码

代码语言:java
复制
public class StringComparisonExample {
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "World";

        System.out.println("s1的长度: " + s1.length());
        System.out.println("s1的第2个字符: " + s1.charAt(1));
        System.out.println("s1中是否包含 'll': " + s1.contains("ll"));
        System.out.println("s1替换 'e' 为 'a': " + s1.replace('e', 'a'));
        System.out.println("s1转大写: " + s1.toUpperCase());
        System.out.println("s1和s2连接: " + s1.concat(s2));
    }
}

个人理解和心得

String类是Java中最常用和最基础的类之一。理解其不可变性非常重要,因为它影响了字符串在内存中的处理方式。掌握常用的方法可以高效地处理和操作字符串,这是任何Java应用程序的基础。最初,我对字符串的不可变性及其对内存管理的影响感到困惑。通过研究和实验,例如在循环中连接字符串,我看到了创建新字符串对象的开销。这使我意识到在处理大量字符串操作时使用StringBuilder或StringBuffer的重要性。

6.4 时间与日期相关类

核心概念

  • Date和Time类: 用于表示和操作日期和时间。
  • SimpleDateFormat类: 用于日期的格式化和解析。
  • Calendar类: 提供了更灵活的日期和时间操作。

知识点

1、Date类:

  • Date(): 创建当前日期和时间的Date对象。
  • getTime(): 返回自1970年1月1日以来的毫秒数。
  • toString(): 返回日期的字符串表示形式。

2、SimpleDateFormat类:

  • SimpleDateFormat(String pattern): 使用给定的模式创建一个日期格式化器。
  • format(Date date): 将Date对象格式化为字符串。
  • parse(String source): 将字符串解析为Date对象。

3、Calendar类:

  • Calendar.getInstance(): 获取当前日期和时间的Calendar对象。
  • set(int year, int month, int day): 设置日期。
  • get(int field): 获取指定的日期字段,如年、月、日。
  • add(int field, int amount): 在日期上添加或减去时间。

示例代码

代码语言:java
复制
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Calendar;

public class DateTimeExample {
    public static void main(String[] args) throws Exception {
        // Date示例
        Date date = new Date();
        System.out.println("当前日期和时间: " + date.toString());
        System.out.println("当前时间戳: " + date.getTime());

        // SimpleDateFormat示例
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("格式化后的日期: " + sdf.format(date));
        Date parsedDate = sdf.parse("2024-05-20 12:00:00");
        System.out.println("解析后的日期: " + parsedDate);

        // Calendar示例
        Calendar calendar = Calendar.getInstance();
        calendar.set(2024, Calendar.MAY, 20);
        System.out.println("Calendar中的日期: " + calendar.getTime());
        calendar.add(Calendar.DAY_OF_MONTH, 10);
        System.out.println("10天后的日期: " + calendar.getTime());
    }
}

个人理解和心得

Date和Time类在处理日期和时间时非常基础,但它们有些过时。SimpleDateFormat提供了强大的日期格式化和解析功能,而Calendar类则提供了更灵活的日期操作。了解这些类可以帮助我有效地处理与日期和时间相关的任务。

小结

最初,我对不同日期和时间类之间的区别感到困惑,特别是Date、Time、Calendar和SimpleDateFormat之间的关系。通过查阅文档并实验不同的用法,我更好地理解了它们的互补作用。此外,记住SimpleDateFormat不是线程安全的这一点非常重要,这影响了我在多线程环境中的使用方式。

6.5 其他常用类

核心概念

  • Math类: 提供了各种数学运算的静态方法。
  • Random类: 用于生成伪随机数。
  • UUID类: 用于生成通用唯一识别码(UUID)。
  • 枚举类: 一种特殊类,其实例是有限的、固定的。

知识点

1、Math类:

  • Math.abs(x): 绝对值。
  • Math.max(x, y): 最大值。
  • Math.min(x, y): 最小值。
  • Math.sqrt(x): 平方根。
  • Math.random(): 生成0.0到1.0之间的随机数。

2、Random类:

  • Random(): 创建一个随机数生成器。
  • nextInt(): 生成下一个int随机数。
  • nextDouble(): 生成下一个double随机数。
  • nextBoolean(): 生成下一个boolean随机数。

3、UUID类:

  • UUID.randomUUID(): 生成一个新的随机UUID。

4、枚举类:

  • 使用enum关键字定义。
  • 枚举常量是枚举类的实例。

示例代码:

代码语言:java
复制
import java.util.Random;
import java.util.UUID;

enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

public class OtherClassesExample {
    public static void main(String[] args) {
        // Math类示例
        System.out.println("绝对值: " + Math.abs(-10));
        System.out.println("最大值: " + Math.max(5, 10));
        System.out.println("最小值: " + Math.min(5, 10));
        System.out.println("平方根: " + Math.sqrt(16));
        System.out.println("随机数: " + Math.random());

        // Random类示例
        Random random = new Random();
        System.out.println("随机int: " + random.nextInt());
        System.out.println("随机double: " + random.nextDouble());
        System.out.println("随机boolean: " + random.nextBoolean());

        // UUID类示例
        UUID uuid = UUID.randomUUID();
        System.out.println("UUID: " + uuid);

        // 枚举类示例
        Day today = Day.MONDAY;
        System.out.println("今天是: " + today);
    }
}

个人理解和心得

Math类提供了一个方便的数学运算工具集,简化了各种数学计算。Random类是生成随机数的强大工具,广泛用于游戏、测试和安全领域。UUID类确保了在分布式系统中生成唯一标识符的简便性。枚举类则提供了一种类型安全的方式来表示固定的一组常量,增强了代码的可读性和维护性。最初,我对枚举类的使用感到有些困惑,特别是它们如何与类和接口一起使用。通过编写示例并探索其用法,我理解了它们在表示有限集合中的值时的价值。此外,记住Random类的线程安全问题非常重要,以避免在多线程应用程序中出现意外行为。

总结

通过细致地梳理第六章的每个部分,我不仅清晰地理解了每个核心概念和知识点,还通过编写和测试示例代码,加深了对这些概念的理解。在学习过程中,我遇到了一些难点,如自动装箱与拆箱的工作原理、大数类的使用细节、字符串的不可变性影响以及日期时间类的多线程安全问题。通过查阅资料、编写测试代码和反复验证,我成功地克服了这些难点,为在实际项目中高效使用这些常用类打下了坚实的基础。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第1章 初识Java与面向对象程序设计
    • 1.1 Java概述
      • 核心概念
    • 1.2 面向对象程序设计思想
      • 核心概念
      • 知识点
    • 1.3 Java开发环境搭建
      • 核心概念
      • 知识点
    • 1.4 第一个Java程序:HelloWorld!
      • 核心概念
      • 知识点
      • 示例代码
      • 编译和运行步骤
    • 1.5 Java常用开发工具
      • 核心概念
      • 知识点
    • 总结
  • 第2章 Java编程基础
    • 2.1 变量与常量
      • 核心概念
      • 知识点
      • 示例代码
      • 运行结果
      • 个人理解与心得
    • 2.2 运算符与表达式
      • 核心概念
      • 知识点
      • 示例代码
      • 运行结果
      • 个人理解与心得
    • 2.3 选择结构
      • 核心概念
      • 知识点
      • 个人理解与心得
    • 2.4 循环结构
      • 核心概念
      • 知识点
      • 个人理解与心得
      • 核心概念
      • 知识点
      • 个人理解与心得
    • 2.6 数组
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 2.7 JVM中的堆内存与栈内存
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 总结
  • 第3章 面向对象程序设计(基础)
    • 3.1 面向对象的概念
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 3.2 面向对象编程
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 3.3 构造方法
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 3.4 this 关键字
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 3.5 static 关键字
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 3.6 包
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 总结
  • 第4章 面向对象程序设计(进阶)
    • 4.1 封装
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 4.2 继承
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 4.3 super关键字
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 4.4 final关键字
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 4.5 Object类
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 4.6 多态
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 4.7 抽象类
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 4.8 接口
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
      • 4.9 内部类
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解与心得
    • 总结
  • 第五章 异常
    • 5.1 异常概述
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解和心得
    • 5.2 异常处理
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解和心得
      • 小结
    • 5.3 异常进阶
      • 知识点
      • 示例代码
      • 个人理解和心得
    • 总结
  • 第六章 Java常用类
    • 6.1 包装类
      • 核心概念:
      • 知识点
      • 示例代码
      • 个人理解和心得
    • 6.2 大数字运算
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解和心得
    • 6.3 String类
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解和心得
    • 6.4 时间与日期相关类
      • 核心概念
      • 知识点
      • 示例代码
      • 个人理解和心得
      • 小结
    • 6.5 其他常用类
      • 核心概念
      • 知识点
      • 示例代码:
      • 个人理解和心得
    • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档