一、第一章:初识 Java 与面向对象程序设计
(一)核心知识点
- Java 概述
- 计算机编程语言发展史:简单介绍了编程语言从早期到现代的发展历程,从机器语言、汇编语言到高级语言的演变。
- Java 语言发展史:讲述了 Java 的起源与发展,由 Sun 公司开发,最初用于解决嵌入式系统的编程问题,后来发展成为广泛应用于企业级开发、移动开发等多个领域的编程语言。
- Java 语言的特点:
- 跨平台性:通过 Java 虚拟机(JVM)实现 “一次编写,到处运行”。例如,编写一个简单的 Java 程序,在 Windows 系统上编译后,无需修改就可以在 Linux 系统上运行。
- 面向对象:以对象为核心组织程序结构,提高代码的复用性和可维护性。
- 健壮性:具有强大的异常处理机制和内存管理机制,减少程序出错的可能性。
- Java 跨平台原理:Java 程序首先被编译成字节码(
.class
文件),字节码可以在任何安装了 JVM 的平台上运行,JVM 负责将字节码解释或编译成对应平台的机器码执行。
- 面向对象程序设计思想
- 面向过程程序设计:以过程为中心,注重函数的实现和调用顺序。例如,计算圆的面积,可能会编写一个函数来实现面积计算
S = 3.14 * r * r
,在主程序中调用这个函数。 - 面向对象程序设计:以对象为核心,将数据和操作数据的方法封装在一起。例如,定义一个
Circle
类,其中有radius
属性表示半径,还有calculateArea
方法来计算面积。 - 面向对象与面向过程程序设计的比较:面向过程侧重于解决问题的步骤,而面向对象侧重于将问题分解为对象及其相互关系。面向对象的代码复用性更好,例如多个不同的图形类(如
Circle
、Rectangle
)可以继承自一个抽象的Shape
类,共享一些通用的方法和属性。
- 面向过程程序设计:以过程为中心,注重函数的实现和调用顺序。例如,计算圆的面积,可能会编写一个函数来实现面积计算
- Java 开发环境搭建
- JDK 与 JRE:
- JDK(Java Development Kit):是 Java 开发工具包,包含了编译、调试等开发工具和 JRE。
- JRE(Java Runtime Environment):是 Java 运行时环境,用于运行已开发好的 Java 程序,包含 Java 虚拟机、Java 核心类库等。
- JDK 安装:详细步骤包括下载合适版本的 JDK 并进行安装,例如从 Oracle 官网下载对应操作系统版本的 JDK 安装包,双击运行安装程序,按照提示完成安装。
- 环境变量配置:配置
PATH
等环境变量,以便在命令行中能够调用 Java 相关命令。在 Windows 系统中,需要将 JDK 的bin
目录添加到系统的PATH
变量中,这样就可以在命令提示符中使用javac
和java
命令。
- JDK 与 JRE:
- 第一个 Java 程序:HelloWorld!
- 显示文件扩展名:确保能正确查看文件类型,在 Windows 系统中,需要在文件资源管理器的查看选项中勾选 “文件扩展名” 选项。
- 编写代码:编写简单的
HelloWorld
程序,如下:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
- 编译与执行:
- 使用
javac
编译生成.class
文件,在命令提示符中进入HelloWorld.java
所在目录,执行javac HelloWorld.java
命令。 - 再用
java
命令执行,执行java HelloWorld
命令,就会在控制台输出Hello, World!
。
- 使用
- 代码解析:
public class
是类的定义,HelloWorld
是类名。public static void main(String[] args)
是程序的入口方法,public
表示该方法可以被其他类访问,static
表示该方法属于类而不属于对象,void
表示该方法没有返回值,args
是传递给主方法的参数数组。System.out.println("Hello, World!");
用于在控制台输出字符串。
- 代码的注释:了解单行注释
//
和多行注释/* */
。例如,在HelloWorld
程序中可以添加注释来解释代码:
public class HelloWorld {
// 这是主类
public static void main(String[] args) {
// 以下代码用于在控制台输出Hello, World!
System.out.println("Hello, World!");
}
}
- Java 常用开发工具
- Eclipse 的安装与使用:
- Eclipse 是一款流行的集成开发环境(IDE),具有代码编辑、调试等功能。从 Eclipse 官网下载安装包,解压后运行
eclipse.exe
即可启动。 - 在 Eclipse 中,可以创建 Java 项目,在项目中创建类,Eclipse 会自动编译代码,还提供了代码自动补全、语法检查等功能。例如,创建一个新的 Java 项目,在项目中新建一个类,输入
main
方法的前几个字母,Eclipse 会自动补全public static void main(String[] args)
。
- Eclipse 是一款流行的集成开发环境(IDE),具有代码编辑、调试等功能。从 Eclipse 官网下载安装包,解压后运行
- IntelliJ IDEA 的安装与使用:
- IDEA 也是强大的 Java 开发工具,有智能代码补全等优势。从 JetBrains 官网下载 IDEA 的安装包,安装后启动。
- 在 IDEA 中,同样可以创建 Java 项目和类,它的智能代码补全功能更加智能,例如在定义一个变量时,它会根据变量的使用场景推荐合适的数据类型。同时,IDEA 还提供了强大的调试工具,可以方便地调试 Java 程序。
- Eclipse 的安装与使用:
(二)个人理解与心得
这一章是 Java 编程的入门基础。在搭建开发环境时遇到了一些问题,比如环境变量配置错误导致无法在命令行中执行javac
和java
命令。通过查阅官方文档和在线教程,仔细检查每一步配置,最终解决了问题。理解 Java 的跨平台原理需要一定的抽象思维,通过实际编写简单程序并在不同操作系统上运行,体会到了这一特性的便利性。
二、第二章:Java 编程基础
(一)核心知识点
- 变量与常量
- 关键字和保留字:如
public
、class
等关键字有特定含义,保留字是 Java 预留的可能用于未来扩展的词汇。例如,public
用于修饰类、方法、变量等,表示它们可以被其他类访问。 - 标识符与命名规范:变量、类名等标识符的命名规则,例如变量名不能以数字开头,类名通常采用大驼峰命名法(如
MyClass
),变量名采用小驼峰命名法(如myVariable
)。 - 数据类型:
- 基本数据类型:
- 整数类型:如
int
(4 字节,用于存储整数,例如int num = 5;
)、long
(8 字节,用于存储较大整数,如long bigNum = 1234567890L;
,注意长整型数值后要加L
或l
)。 - 浮点类型:如
double
(8 字节,用于存储浮点数,例如double pi = 3.14;
)、float
(4 字节,如float smallFloat = 1.23f;
,浮点型数值后要加f
或F
)。 - 字符类型:
char
(2 字节,用于存储单个字符,如char ch = 'A';
)。 - 布尔类型:
boolean
(1 字节,只有true
和false
两个值,例如boolean flag = true;
)。
- 整数类型:如
- 引用数据类型:如类、数组等。
- 基本数据类型:
- 变量的定义与赋值:如
int num = 5;
,这里定义了一个名为num
的整数变量,并赋值为 5。 - 常量:使用
final
关键字定义常量,例如final int MAX_VALUE = 100;
,常量的值在定义后不能被修改。 - 变量的类型转换:
- 自动类型转换:当把一个较小范围的数据类型赋值给一个较大范围的数据类型时会自动进行转换,例如
int a = 5; double b = a;
,这里int
类型的a
自动转换为double
类型赋值给b
。 - 强制类型转换:当把一个较大范围的数据类型转换为较小范围的数据类型时,需要进行强制转换,例如
double c = 3.14; int d = (int)c;
,这里将double
类型的c
强制转换为int
类型赋值给d
,会丢失小数部分,d
的值为 3。
- 自动类型转换:当把一个较小范围的数据类型赋值给一个较大范围的数据类型时会自动进行转换,例如
- Scanner 的使用:用于从控制台获取用户输入,例如:
- 关键字和保留字:如
import java.util.Scanner;
public class ScannerExample {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个整数:");
int input = scanner.nextInt();
System.out.println("你输入的整数是:" + input);
scanner.close();
}
}
- 运算符与表达式
- 算术运算符:如
+
、-
、*
、/
、%
。例如int a = 10; int b = 3; int sum = a + b; // sum的值为13
,int remainder = a % b; // remainder的值为1
。 - 赋值运算符:如
=
、+=
、-=
等。例如int x = 5; x += 3; // 等价于x = x + 3,x的值变为8
。 - 关系运算符:如
==
、!=
、>
、<
、>=
、<=
。例如int m = 5; int n = 3; boolean isEqual = m == n; // isEqual的值为false
。 - 逻辑运算符:如
&&
、||
、!
。例如boolean p = true; boolean q = false; boolean result = p && q; // result的值为false
。 - 位运算符:如
&
、|
、^
、~
、<<
、>>
、>>>
。例如int a = 5; // 二进制为0101,int b = 3; // 二进制为0011,int c = a & b; // c的值为0001,即1
。 - 三元运算符:
条件表达式? 表达式1 : 表达式2
。例如int max = (a > b)? a : b;
,如果a > b
成立,max
的值为a
,否则为b
。 - 运算符的优先级:规定了在表达式中运算的先后顺序,例如先计算括号内的表达式,再进行乘除运算,最后进行加减运算等。
- 算术运算符:如
- 选择结构
- if 语句:根据条件判断执行不同的代码块,例如:
int score = 80;
if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
- switch 语句:用于多分支选择,例如:
int day = 3;
switch (day) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
default:
System.out.println("其他");
}
- 选择结构的嵌套:在选择语句内部再嵌套选择语句,例如:
int age = 20;
if (age >= 18) {
System.out.println("成年");
if (age >= 22) {
System.out.println("可以结婚");
} else {
System.out.println("还不能结婚");
}
} else {
System.out.println("未成年");
}
- 两种选择结构的对比:
if
语句适用于条件判断比较复杂、不规律的情况,而switch
语句适用于等值判断的情况,且switch
语句在某些情况下性能可能更好。
- 循环结构
- for 语句:用于已知循环次数的循环,例如:
for (int i = 0; i < 10; i++) {
System.out.println(i);
}
- while 语句:根据条件判断是否执行循环,例如:
int j = 0;
while (j < 10) {
System.out.println(j);
j++;
}
- do - while 语句:先执行一次循环体,再判断条件,例如:
int k = 0;
do {
System.out.println(k);
k++;
} while (k < 10);
- break 和 continue 语句:
break
用于跳出循环,例如:
for (int m = 0; m < 10; m++) {
if (m == 5) {
break;
}
System.out.println(m);
}
continue
用于跳过本次循环剩余语句进入下一次循环,例如:
for (int n = 0; n < 10; n++) {
if (n == 5) {
continue;
}
System.out.println(n);
}
- 循环语句的嵌套:在一个循环内部再嵌套另一个循环,例如打印九九乘法表:
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j + "×" + i + "=" + (i * j) + "\t");
}
System.out.println();
}
- 三种循环结构的应用场景:
for
循环适用于已知循环次数的情况,while
循环适用于根据条件判断是否循环的情况,do - while
循环适用于至少要执行一次循环体的情况。
- 方法
- 方法介绍:是一段可重复调用的代码块,用于实现特定功能。
- 方法声明与调用:声明方法包括方法名、参数列表、返回值类型等,例如
public int add(int a, int b) { return a + b; }
,调用时如int result = add(3, 5);
。 - 方法重载:多个方法具有相同的名字,但参数列表不同,例如:
public int add(int a, int b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
- 方法递归:方法自己调用自己,例如计算阶乘:
public int factorial(int n) {
if (n == 0 || n == 1) return 1;
else return n * factorial(n - 1);
}
- 数组
- 数组概述:是一种存储同类型数据的容器。
- 数组的常见操作:
- 数组的定义:如
int[] arr = new int[5];
。 - 初始化:如
int[] arr = {1, 2, 3};
。 - 访问元素:如
arr[0]
。 - 遍历:如
for (int i = 0; i < arr.length; i++) { System.out.println(arr[i]); }
。
- 数组的定义:如
- 数组排序算法:如冒泡排序:
public class BubbleSort {
public static void main(String[] args) {
int[] arr = {5, 3, 8, 6, 4};
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int num : arr) {
System.out.print(num + " ");
}
}
}
- 二分查找法:在有序数组中查找元素的高效方法,例如
public class BinarySearch {
public static int binarySearch(int[] arr, int target) {
int low = 0;
int high = arr.length - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (arr[mid] == target) return mid;
else if (arr[mid] < target) low = mid + 1;
else high = mid - 1;
}
return -1;
}
public static void main(String[] args
-
- 方法中的可变参数:例如
public void printNumbers(int... numbers) { for (int num : numbers) { System.out.println(num); } }
,调用时可以传入任意数量的整数参数,如printNumbers(1, 2, 3);
或printNumbers(4);
。 - 二维数组:数组的数组,例如
int[][] matrix = new int[3][4];
,访问二维数组元素如matrix[0][0]
,遍历二维数组:
- 方法中的可变参数:例如
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
- Arrays 工具类:提供了数组操作的一些实用方法,如
Arrays.sort()
用于排序:
import java.util.Arrays;
public class ArraysExample {
public static void main(String[] args) {
int[] arr = {5, 3, 8, 6, 4};
Arrays.sort(arr);
for (int num : arr) {
System.out.print(num + " ");
}
}
}
- JVM 中的堆内存与栈内存
- 堆和栈:
- 栈:用于存储局部变量等,例如方法中的局部变量在栈中存储。当方法调用结束时,栈中的局部变量会被销毁。
- 堆:用于存储对象等。当使用
new
关键字创建对象时,对象在堆中分配内存。例如Person person = new Person();
,Person
对象在堆中创建。
- 数据类型传递:
- 基本数据类型按值传递:例如:
- 堆和栈:
public class ValuePassing {
public static void main(String[] args) {
int a = 5;
changeValue(a);
System.out.println(a); // 仍然是5,因为在changeValue方法中只是修改了副本
}
public static void changeValue(int num) {
num = 10;
}
}
- 引用数据类型按引用传递:例如:
class Person {
String name;
}
public class ReferencePassing {
public static void main(String[] args) {
Person person = new Person();
person.name = "Alice";
changeName(person);
System.out.println(person.name); // 变成了Bob,因为传递的是对象的引用
}
public static void changeName(Person p) {
p.name = "Bob";
}
}
- 方法中的数据交换:在方法中交换两个变量的值,例如:
public class SwapExample {
public static void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public static void main(String[] args) {
int[] arr = {1, 2};
swap(arr, 0, 1);
System.out.println(arr[0] + " " + arr[1]); // 2 1
}
}
(二)个人理解与心得
这一章内容丰富,是 Java 编程的核心基础。在学习过程中,循环结构的嵌套和方法递归是难点。对于循环嵌套,通过绘制流程图来理清循环的执行顺序和变量的变化情况,从而掌握了如何编写多层循环来解决实际问题,比如打印九九乘法表。方法递归需要理解递归的思想和边界条件,通过手动计算简单的递归示例,逐步明白了如何正确编写递归方法,如实现简单的斐波那契数列计算。
三、第三章:面向对象程序设计 (基础)
(一)核心知识点
- 面向对象的概念
- 什么是面向对象:将现实世界中的事物抽象成对象,对象具有属性和行为。例如,将汽车抽象为一个对象,它有颜色、速度等属性,有启动、加速、刹车等行为。
- 面向对象的特性:包括封装、继承、多态。
- 类和对象:类是对象的模板,对象是类的实例,例如:
class Car {
String color;
void drive() {
System.out.println("The car is driving");
}
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car();
myCar.color = "red";
myCar.drive();
}
}
- 面向对象编程
- 类的定义:定义类的成员变量和成员方法,例如:
class Student {
String name;
int age;
void study() {
System.out.println(name + " is studying");
}
}
- 对象的创建与使用:使用
new
关键字创建对象并调用对象的方法和访问属性,例如:
public class Main {
public static void main(String[] args) {
Student student = new Student();
student.name = "Tom";
student.age = 20;
student.study();
}
}
- 成员变量默认值:不同数据类型的成员变量有其默认初始值,例如
int
类型默认值是 0,boolean
类型默认值是false
,String
类型默认值是null
。 - 对象内存存储:理解对象在内存中的存储方式,对象的引用在栈中,对象本身在堆中。
- 匿名对象:没有名字的对象,通常用于只使用一次的情况,例如
new Car().drive();
。
- 构造方法
- 什么是构造方法:用于创建对象时初始化对象的成员变量,方法名与类名相同,无返回值,例如:
class Person {
String name;
int age;
Person(String n, int a) {
name = n;
age = a;
}
}
- 构造方法的使用:
public class Main {
public static void main(String[] args) {
Person person = new Person("Alice", 25);
System.out.println(person.name + " " + person.age);
}
}
- 构造方法的重载:多个构造方法具有不同的参数列表,例如:
class Circle {
double radius;
Circle() {
radius = 1.0;
}
Circle(double r) {
radius = r;
}
}
- this 关键字
- this 关键字介绍:用于指代当前对象,例如在构造方法和成员方法中用于区分成员变量和局部变量,例如:
class Book {
String title;
double price;
Book(String title, double price) {
this.title = title;
this.price = price;
}
}
- this 关键字的使用:在方法中调用其他构造方法也可以使用
this
,例如:
class Rectangle {
int length;
int width;
Rectangle() {
this(1, 1);
}
Rectangle(int length, int width) {
this.length = length;
this.width = width;
}
}
- static 关键字
- 静态变量:属于类,所有对象共享,例如:
class Counter {
static int count;
}
public class Main {
public static void main(String[] args) {
Counter.count++;
System.out.println(Counter.count);
}
}
- 静态方法:可以通过类名直接调用,不能访问非静态成员变量和方法,例如:
class MathUtils {
static int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
int result = MathUtils.add(3, 5);
System.out.println(result);
}
}
- 静态代码块:在类加载时执行,用于初始化静态变量等,例如:
class StaticExample {
static int num;
static {
num = 10;
}
}
- 包
- 包的概念:用于组织和管理类,避免类名冲突,例如
package com.example;
。 - 类的访问与导包:使用
import
导入包中的类,以便在代码中使用,例如:
- 包的概念:用于组织和管理类,避免类名冲突,例如
import java.util.Date;
public class Main {
public static void main(String[] args) {
Date date = new Date();
System.out.println(date);
}
}
(二)个人理解与心得
面向对象编程是 Java 的核心思想。在理解类和对象的关系时,起初感觉比较抽象。通过将生活中的实例进行抽象,比如将汽车抽象为Car
类,每一辆具体的汽车就是一个对象,逐渐掌握了面向对象的基本概念。在构造方法和this
关键字的学习中,通过编写多个类和对象的实例,对比有和没有构造方法、使用和不使用this
关键字的区别,加深了对它们的理解。
四、第四章:面向对象程序设计 (进阶)
(一)核心知识点
- 封装
- 什么是封装:将对象的属性和操作属性的方法封装在一起,隐藏对象的内部细节,只对外提供公共的访问接口。例如:
class BankAccount {
private double balance;
public void deposit(double amount) {
balance += amount;
}
public void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
} else {
System.out.println("Insufficient balance");
}
}
public double getBalance() {
return balance;
}
}
- 访问修饰符:
- public(公共的,任何类都可以访问):例如
public class PublicClass {}
。 - private(私有的,只有本类可以访问):如上述
BankAccount
类中的balance
变量。 - protected(受保护的,本类及其子类可以访问):例如:
- public(公共的,任何类都可以访问):例如
class ParentClass {
protected int protectedValue;
}
class ChildClass extends ParentClass {
void accessValue() {
protectedValue = 10;
}
}
- get ()/set () 方法:用于获取和设置私有成员变量的值,例如:
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- 继承
- 什么是继承:子类继承父类的属性和方法,实现代码复用,例如:
class Animal {
void eat() {
System.out.println("The animal is eating");
}
}
class Dog extends Animal {
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
}
}
- 继承的使用:子类可以重写父类的方法,例如:
class Dog extends Animal {
@Override
void eat() {
System.out.println("The dog is eating bones");
}
}
- 方法重写:子类重写父类方法时,方法签名(方法名、参数列表、返回值类型)必须相同,例如:
class Parent {
public void print() {
System.out.println("Parent print");
}
}
class Child extends Parent {
@Override
public void print() {
System.out.println("Child print");
}
}
- super 关键字
- super 关键字的使用:
- 在子类中调用父类的构造方法,例如:
- super 关键字的使用:
class Parent {
Parent() {
System.out.println("Parent constructor");
}
}
class Child extends Parent {
Child() {
super();
System.out.println("Child constructor");
}
}
- 在子类中调用父类的成员方法,例如:
class Parent {
void method() {
System.out.println("Parent method");
}
}
class Child extends Parent {
void callParentMethod() {
super.method();
}
}
- super 与 this 对比:
this
指代当前对象,super
指代父类对象。例如在构造方法中,this
用于调用本类其他构造方法,super
用于调用父类构造方法。
- final 关键字
- final 关键字介绍:用于修饰类、方法和变量。
- 修饰类时该类不能被继承,例如
final class FinalClass {}
。 - 修饰方法时该方法不能被重写,例如:
- 修饰类时该类不能被继承,例如
- final 关键字介绍:用于修饰类、方法和变量。
class Parent {
public final void finalMethod() {
System.out.println("Final method");
}
}
class Child extends Parent {
// 不能重写finalMethod方法
}
- 修饰变量时该变量是常量,例如
final int FINAL_VARIABLE = 10;
。 - final 关键字的使用:在多线程环境下,
final
变量可以保证其值在初始化后不会被改变,保证了数据的一致性。
- Object 类
- Object 类介绍:是所有类的父类,提供了一些通用的方法,如
toString()
、equals()
等。 - Object 类的常见方法:
- 重写
toString
方法:可以返回对象的有意义的字符串表示,例如:
- 重写
- Object 类介绍:是所有类的父类,提供了一些通用的方法,如
class Person {
String name;
int age;
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 重写
equals
方法:用于比较两个对象是否相等,例如:
class Person {
String name;
int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass()!= o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
}
- 多态
- 什么是多态:同一操作作用于不同对象产生不同的行为,例如:
class Animal {
void eat() {
System.out.println("The animal is eating");
}
}
class Dog extends Animal {
@Override
void eat() {
System.out.println("The dog is eating bones");
}
}
class Cat extends Animal {
@Override
void eat() {
System.out.println("The cat is eating fish");
}
}
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.eat();
animal2.eat();
}
}
- 多态的实现:通过继承和方法重写实现多态。
- 引用类型数据转换:
- 向上转型(子类对象赋值给父类引用):例如
Animal animal = new Dog();
,这种转换是自动进行的。 - 向下转型(父类引用转换为子类对象,需要强制类型转换且可能出现
ClassCastException
):例如:
- 向上转型(子类对象赋值给父类引用):例如
Animal animal = new Dog();
Dog dog = (Dog) animal; // 正确的向下转型
Cat cat = (Cat) animal; // 错误的向下转型,会抛出ClassCastException
- 多态中变量与方法的调用:在多态情况下,变量的访问取决于引用类型,方法的调用取决于对象类型。例如:
class Parent {
int value = 10;
void method() {
System.out.println("Parent method");
}
}
class Child extends Parent {
int value = 20;
@Override
void method() {
System.out.println("Child method");
}
}
public class Main {
public static void main(String[] args) {
Parent parent = new Child();
System.out.println(parent.value); // 输出10,因为变量访问取决于引用类型
parent.method(); // 输出Child method,因为方法调用取决于对象类型
}
}
- 抽象类
- 什么是抽象类:不能被实例化,用于为子类提供模板,包含抽象方法(只有方法声明,没有方法体),例如:
abstract class Shape {
abstract void draw();
}
- 抽象类的定义与使用:子类必须实现抽象类中的抽象方法,否则子类也是抽象类。例如:
-
abstract class Shape { abstract void draw(); } class Circle extends Shape { @Override void draw() { System.out.println("Drawing a circle"); } }
- 接口
- 什么是接口:是一种特殊的抽象类型,只包含方法签名、常量和默认方法,例如:
-
interface Drawable { void draw(); }
- 接口的定义与使用:类可以实现多个接口,实现接口必须实现接口中的所有方法,例如:
-
class Square implements Drawable { @Override public void draw() { System.out.println("Drawing a square"); } }
- 接口的多实现:一个类可以实现多个接口,实现多接口的类需要实现所有接口中的方法。例如:
-
interface Flyable { void fly(); } class Bird implements Drawable, Flyable { @Override public void draw() { System.out.println("Drawing a bird"); } @Override public void fly() { System.out.println("The bird is flying"); } }
- 接口的继承:接口可以继承另一个接口,继承接口的接口需要实现所有继承的方法。例如:
-
interface Movable { void move(); } interface Flyable extends Movable { void fly(); } class Airplane implements Flyable { @Override public void move() { System.out.println("The airplane is moving on the runway"); } @Override public void fly() { System.out.println("The airplane is flying"); } }
- 接口的 static 方法和 default 方法:
static
方法可以通过接口名直接调用,例如:
-
interface MathInterface { static int add(int a, int b) { return a + b; } } public class Main { public static void main(String[] args) { int result = MathInterface.add(3, 5); System.out.println(result); } }
default
方法提供了默认实现,例如:-
interface Vehicle { default void start() { System.out.println("The vehicle is starting"); } } class Car implements Vehicle { } public class Main { public static void main(String[] args) { Car car = new Car(); car.start(); } }
- 抽象类与接口的区别:
- 抽象类可以有部分实现,接口只有方法签名和常量。
- 类只能单继承抽象类,但可以多实现接口。例如,一个类不能同时继承两个抽象类,但可以实现多个接口来获得多种行为规范。
- 内部类概述
- 内部类:定义在另一个类内部的类,包括成员内部类、静态内部类、局部内部类、匿名内部类等。例如:
-
class OuterClass { private int outerValue = 10; // 成员内部类 class InnerMemberClass { void accessOuterValue() { System.out.println(outerValue); } } // 静态内部类 static class InnerStaticClass { static void staticMethod() { System.out.println("This is a static method in static inner class"); } } void outerMethod() { // 局部内部类 class InnerLocalClass { void localMethod() { System.out.println("This is a local method in local inner class"); } } InnerLocalClass innerLocalClass = new InnerLocalClass(); innerLocalClass.localMethod(); } }
(二)个人理解与心得
这一章深入了面向对象编程的高级特性。在学习继承和多态时,理解多态的动态绑定机制是一个难点。通过编写大量的代码示例,观察不同对象在调用相同方法时的实际执行情况,逐渐理解了多态的原理和应用场景。在处理抽象类和接口的关系时,起初容易混淆它们的概念和使用方法。通过对比分析它们的特点,如抽象类更适合具有部分通用实现的场景,接口更适合定义行为规范,提高了对它们的运用能力。
五、第五章:异常
(一)核心知识点
- 异常概述
- 什么是异常:在程序运行过程中出现的不正常情况,如除以零、数组越界等。例如,当执行
int a = 5/0;
时,就会抛出异常。 - 异常与错误:
- 异常是可以被程序处理的,例如
NullPointerException
(空指针异常)等。 - 错误(如
OutOfMemoryError
)通常是不可恢复的系统问题,一般是由于系统资源耗尽等原因导致,程序很难从错误中恢复。
- 异常是可以被程序处理的,例如
- Throwable 与异常体系:
Throwable
是所有异常和错误的父类,其下有Exception
(可处理的异常)和Error
(不可处理的错误)。Exception
:是程序中需要处理的异常类型,分为检查异常(编译时异常,如IOException
)和非检查异常(运行时异常,如NullPointerException
)。例如:
- 什么是异常:在程序运行过程中出现的不正常情况,如除以零、数组越界等。例如,当执行
-
public class ExceptionExample { public static void main(String[] args) { // 运行时异常示例 String str = null; try { System.out.println(str.length()); } catch (NullPointerException e) { e.printStackTrace(); } } }
- 异常处理
- 抛出异常:使用
throw
关键字在方法内手动抛出异常,例如:
- 抛出异常:使用
-
public class ThrowExample { public static void checkAge(int age) { if (age < 0) { throw new IllegalArgumentException("Age must be non - negative"); } } public static void main(String[] args) { try { checkAge(-5); } catch (IllegalArgumentException e) { e.printStackTrace(); } } }
- 声明异常:在方法签名中使用
throws
关键字声明可能抛出的异常,例如: -
import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class ThrowsExample { public static void readFile() throws IOException { File file = new File("test.txt"); FileInputStream fis = new FileInputStream(file); // 读取文件操作可能抛出IOException } public static void main(String[] args) { try { readFile(); } catch (IOException e) { e.printStackTrace(); } } }
- 捕获异常:使用
try - catch - finally
块来捕获和处理异常,例如: -
public class TryCatchFinallyExample { public static void main(String[] args) { try { int a = 5/0; } catch (ArithmeticException e) { System.out.println("捕获到算术异常"); e.printStackTrace(); } finally { System.out.println("finally块总会执行"); } } }
- 异常进阶
- 自定义异常:通过继承
Exception
或其子类来创建自定义异常类,例如:
- 自定义异常:通过继承
-
class MyException extends Exception { public MyException(String message) { super(message); } } public class CustomExceptionExample { public static void checkValue(int value) throws MyException { if (value > 100) { throw new MyException("Value is too large"); } } public static void main(String[] args) { try { checkValue(150); } catch (MyException e) { e.printStackTrace(); } } }
- 方法重写中的异常:子类重写父类方法时,不能抛出比父类方法更多的检查异常。例如:
-
class Parent { public void method() throws IOException { } } class Child extends Parent { @Override public void method() { // 不能抛出IOException或其超类异常 } }
(二)个人理解与心得
异常处理是保证程序健壮性的重要手段。一开始对于检查异常和非检查异常的区别有些模糊,通过实际编写代码,尝试在不同方法中处理这两种异常,明白了检查异常需要在编译时处理(要么捕获要么声明抛出),而非检查异常则不需要。在处理
try - catch - finally
块时,对于finally
块的执行顺序和作用有了更深刻的理解,特别是在资源释放(如关闭文件流)方面的应用。自定义异常有助于更好地组织和处理特定业务场景下的异常情况,通过实际设计和使用自定义异常,能够更优雅地处理程序中的错误逻辑。六、第六章:Java 常用类
(一)核心知识点
- 包装类
- 什么是包装类:将基本数据类型包装成对象,方便在需要对象的场景中使用。例如
Integer
是int
的包装类,Double
是double
的包装类等。 - 基本数据类型与包装类:
- 自动装箱(基本数据类型自动转换为包装类):如
Integer i = 5;
,编译器会在后台将int
类型的5
转换为Integer
对象。 - 自动拆箱(包装类自动转换为基本数据类型):如
int j = i;
,这里将Integer
对象i
自动转换为int
类型赋值给j
。
- 自动装箱(基本数据类型自动转换为包装类):如
- 自动装箱与拆箱:编译器在编译时会自动处理装箱和拆箱操作,但在某些情况下可能会导致性能问题,例如在循环中大量使用装箱操作。
- 大数据运算:利用包装类可以处理超出基本数据类型范围的数值运算,例如
BigInteger
和BigDecimal
类用于处理大整数和高精度小数运算。例如:
- 什么是包装类:将基本数据类型包装成对象,方便在需要对象的场景中使用。例如
-
import java.math.BigInteger; public class BigIntegerExample { public static void main(String[] args) { BigInteger num1 = new BigInteger("12345678901234567890"); BigInteger num2 = new BigInteger("98765432109876543210"); BigInteger sum = num1.add(num2); System.out.println(sum); } }
- String 类概述
- String:是不可变的字符序列,例如
String str = "Hello";
。 - String 类查找方法:
indexOf()
用于查找字符或子字符串在字符串中的位置,例如:
- String:是不可变的字符序列,例如
-
String str = "Hello World"; int index = str.indexOf("World"); System.out.println(index); // 6
lastIndexOf()
用于从后向前查找,例如:-
String str = "Hello World"; int lastIndex = str.lastIndexOf("o"); System.out.println(lastIndex); // 7
- String 类转换方法:
toUpperCase()
(转换为大写):例如:String str = "hello"; String upperStr = str.toUpperCase(); System.out.println(upperStr); // HELLO
toLowerCase()
(转换为小写):例如:String str = "HELLO"; String lowerStr = str.toLowerCase(); System.out.println(lowerStr); // hello
toCharArray()
(转换为字符数组):例如:String str = "abc"; char[] charArray = str.toCharArray(); for (char c : charArray) { System.out.print(c + " "); } // a b c
- String 类中的其他方法:
substring()
用于获取子字符串,例如:String str = "Hello World"; String subStr = str.substring(6); System.out.println(subStr); // World
concat()
用于字符串连接,例如:String str1 = "Hello"; String str2 = " World"; String result = str1.concat(str2); System.out.println(result); // Hello World
- StringBuffer 类与 StringBuilder 类
- StringBuffer 类:是可变的字符序列,线程安全。常用于多线程环境下对字符串进行频繁修改的操作,例如:
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" World");
System.out.println(buffer.toString());
- StringBuffer 类常见方法:
append()
用于追加字符串,例如:StringBuffer buffer = new StringBuffer("Hello"); buffer.append(" World"); System.out.println(buffer); // Hello World
insert()
用于插入字符串,例如:StringBuffer buffer = new StringBuffer("Hello"); buffer.insert(5, " World"); System.out.println(buffer); // Hello World
delete()
用于删除字符,例如:StringBuffer buffer = new StringBuffer("Hello World"); buffer.delete(5, 11); System.out.println(buffer); // Hello
- StringBuilder 类:与
StringBuffer
类似,但非线程安全,性能在单线程环境下更高,例如:
StringBuilder builder = new StringBuilder("Java");
builder.append(" is great");
System.out.println(builder.toString());
- 字符串拼接效率比较:在大量字符串拼接操作时,
StringBuffer
和StringBuilder
比String
更高效,因为String
每次拼接都会创建新的字符串对象。例如:
public class StringConcatEfficiency {
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
String str = "";
for (int i = 0; i < 10000; i++) {
str += "a";
}
long endTime = System.currentTimeMillis();
System.out.println("String拼接时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 10000; i++) {
builder.append("a");
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder拼接时间:" + (endTime - startTime));
}
}
- 链式编程:在
StringBuffer
和StringBuilder
中可以使用链式编程,例如:builder.append("Hello").append(" World");
- 时间和日期相关类
- 时间戳:表示从 1970 年 1 月 1 日 00:00:00 UTC 到某个时间点的毫秒数,可以使用
System.currentTimeMillis()
获取当前时间戳,例如:
- 时间戳:表示从 1970 年 1 月 1 日 00:00:00 UTC 到某个时间点的毫秒数,可以使用
long timestamp = System.currentTimeMillis();
System.out.println(timestamp);
- Date 类:用于表示日期和时间,但很多方法已过时,例如
Date date = new Date();
。 - SimpleDateFormat 类:用于格式化和解析日期,例如:
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatExample {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy - MM - dd HH:mm:ss");
Date date = new Date();
String dateStr = sdf.format(date);
System.out.println(dateStr);
try {
Date parsedDate = sdf.parse(dateStr);
System.out.println(parsedDate);
} catch (java.text.ParseException e) {
e.printStackTrace();
}
}
}
- Calendar 类:是一个抽象类,用于进行日期和时间的计算和操作,例如:
import java.util.Calendar;
public class CalendarExample {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2022);
int year = calendar.get(Calendar.YEAR);
System.out.println(year);
}
}
- 其他常用类
- Math 类:提供了大量的数学运算方法,如
Math.sqrt()
(求平方根)、Math.pow()
(求幂)等,例如double result = Math.sqrt(9);
。 - Random 类:用于生成随机数,例如
Random random = new Random(); int randomNumber = random.nextInt(10);
。 - UUID 类:用于生成通用唯一识别码(Universally Unique Identifier),例如
UUID uuid = UUID.randomUUID();
。 - 枚举类:用于定义一组常量,例如:
- Math 类:提供了大量的数学运算方法,如
enum Season {
SPRING, SUMMER, FALL, WINTER
}
(二)个人理解与心得
这一章介绍了很多实用的 Java 类。在学习包装类时,对于自动装箱和拆箱的底层原理不太清楚。通过查看字节码文件和相关资料,了解到编译器在背后进行的操作,同时也明白了在性能敏感的场景下需要注意避免不必要的装箱和拆箱操作。在处理字符串相关类时,String
的不可变性和StringBuffer
、StringBuilder
的可变性是重要的概念。通过对比它们在字符串操作中的性能表现