Java开发教程
Java开发教程
一、简介
📢 公司:由 SUN 公司 詹姆斯-高斯林 开发,后被 甲骨文(Oracle)收购。 知名作品:我的世界、淘宝网、Android 操作系统。
Java 容器:很多繁琐又重复的工作我们可以提前做好,然后调用,但谁来做呢,有个组织出来定义了接口,谁家都可以造轮子,用户想用哪家的都可以,各家自己造的轮子(如Tomcat、GlassFish、IBM WebSphere)就叫做 Java 容器。随着越来越多的企业加入到这个阵营,官方给出的规范组件并不是最受欢迎的,反而一些企业的组件在实际开发中更让人喜欢。
Java SE,EE,ME 三者的区别
开发桌面应用的 Java SE(Java Platform,Standard Edition)
开发 Web 应用的 Java EE(Java Platform,Enterprise Edition)
Android 开发移动应用 和 嵌入式 的 Java ME(Java Platform,Micro Edition)
参考连接: Java SE EE ME具体区别
JAR: Java 类库的 class 文件。
JDK,JRE,JVM 三者的区别:
总的来说,JDK 中包含 JRE,因为开发总要运行嘛,而 JRE 又包含 JVM。具体可以打开我们下载的JDK文件夹,里面又包含了一个JRE文件夹。参考CSDN 1、JDK:JDK(Java Development Kit)称为 Java 开发包 或 Java 开发工具,是一个编写 Java 的 Applet 小程序和应用程序的程序开发环境。JDK 是整个 Java 的核心,包括了 Java 运行环境 JRE(Java Runtime Envirnment),JVM 和 Java 的核心类库(Java API)。 JDK 不同版本特性 2、JRE: JRE(Java Runtime Envirnment)运行java程序的环境,JRE里面只有client运行环境,安装过程中,会自动添加PATH。 3、JVM:Java 虚拟机(Java Virtual Machine)
Java和C++的区别:
Java是解释型语言,所谓的解释型语言,就是源码会先经过一次编译,成为中间码,中间码再被解释器解释成机器码。对于Java而言,中间码就是字节码(.class),而解释器在JVM中内置了。
C++是编译型语言,所谓编译型语言,就是源码一次编译,直接在编译的过程中链接了,形成了机器码。
C++比Java执行速度快,但是Java可以利用JVM跨平台。
Java是纯面向对象的语言,所有代码(包括函数、变量)都必须在类中定义。而C++中还有面向过程的东西,比如是全局变量和全局函数。
C++中有指针,Java中没有,但是有引用。
C++支持多继承,Java中类都是单继承的。但是继承都有传递性,同时Java中的接口是多继承,类对接口的实现也是多实现。
C++中,开发需要自己去管理内存,但是Java中JVM有自己的GC机制,虽然有自己的GC机制,但是也会出现OOM和内存泄漏的问题。C++中有析构函数,Java中Object的finalize方法
C++运算符可以重载,但是Java中不可以。同时C++中支持强制自动转型,Java中不行,会出现ClassCastException(类型不匹配)。
Linux、Windows与MAC OS下的换行符
我使用的是 Windows,提交上来的文档总是不能够换行,导致格式很糟糕,于是就去查了一下,是不是提交上来的换行符有问题。参考连接
历史:为了保证打字机换行时消耗的时间内不会有其它字符进来,主动添加了两个无效字符(回车 换行)。 计算机出现后,开始讨论加一个还是两个的问题,注意了 Typora 的软换行在 GitHub 中是无效的,在 Typora 中按下 Shift + Enter 是软换行,按下此组合键后,可以看到换了一行,但是推送到 GitHub 上后,你会发现换行是无效的。要解决这问题,你就要搞清楚空格、软换行、硬换行、换段的在 Typora 中的概念。
Typora 在空格与换行部分主要是使用 CommonMark 作为标注规范。与前文提到的 GFM 一样,CommonMark 也是比较流行的 Markdown 语言规范(解析器)之一。
空格:在输入连续的空格后,Typora 会在编辑器视图里为你保留这些空格,但当你打印或导出时,这些空格会被省略成一个。 你可以在源代码模式下,为每个空格前加一个
\转义符,或者直接使用 HTML 风格的&nbps;来保持连续的空格。软换行: 需要说明的是,在 Markdown 语法中,换行(line break)与换段是不同的。且换行分为软换行和硬换行。在 Typora 中,你可以通过
Shift + Enter完成一次软换行。软换行只在编辑界面可见,当文档被导出时换行会被省略。硬换行: 你可以通过
空格 + 空格 + Shift + Enter完成一次硬换行,而这也是许多 Markdown 编辑器所原生支持的。硬换行在文档被导出时将被保留,且没有换段的段后距。换段: 你可以通过
Enter完成一次换段。Typora 会自动帮你完成两次Shift + Enter的软换行,从而完成一次换段。这也意味着在 Markdown 语法下,换段是通过在段与段之间加入空行来实现的。Windows 风格(CR+LF)与 Unix 风格(CR)的换行符: CR 表示回车
\r,即回到一行的开头,而 LF 表示换行\n,即另起一行。 所以 Windows 风格的换行符本质是「回车 + 换行」,而 Unix 风格的换行符是「换行」。这也是为什么 Unix / Mac 系统下的文件,如果在 Windows 系统直接打开会全部在同一行内。 你可以在文件 - 偏好设置 - 编辑器 - 默认换行符中对此进行切换。
二、从0-1配置Java
1. 安装 Java 开发环境
1.1 安装 JDK(Java Development Kit)
JDK 是 Java 开发的核心工具包,包含编译器(javac)和 JRE(Java 运行环境)。
下载:访问 Oracle JDK 或 OpenJDK,根据系统选择版本(如 Windows 64 位)。
安装:运行安装程序,按默认路径安装(如
C:\Program Files\Java\jdk-17)。配置环境变量:
JAVA_HOME:指向 JDK 安装路径(如C:\Program Files\Java\jdk-17)。PATH:添加%JAVA_HOME%\bin到系统路径。验证:打开命令行输入
java -version和javac -version,显示版本号即成功。
1.2 安装集成开发环境(IDE)
推荐使用 IntelliJ IDEA Community Edition(免费)或 Eclipse:
IntelliJ IDEA:下载地址,安装后启动即可。
常用快捷键:
2. 编写第一个 Java 程序
2.1 创建项目
以 IntelliJ IDEA 为例:
打开 IDE,选择
File→New→Project。选择
Java,SDK 选择已安装的 JDK,点击Create。
2.2 编写 Hello World
在src目录下创建Main.java文件,输入以下代码:
public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}代码解释:
public class Main:定义一个名为Main的公共类。public static void main(String[] args):程序入口方法,Java 虚拟机(JVM)从这里开始执行。System.out.println():向控制台输出内容。
2.3 运行程序
在代码编辑器右键点击 →
Run 'Main.main()'。或使用命令行:
# 编译java文件 javac Main.java # 运行编译后的类 java Main输出:
Hello, World!
三、Java基础语法
1. 命名与基本方法
类名:UpperCamelCase,首字母全部大写
方法名:lowerCamelCase,第一个首字母小写
源文件名:Java 文件名必须匹配类名。请使用类名保存文件并添加扩展名 “.java”。(如果文件名和类名不相同则会导致编译错误)。
关键字与保留字:Java 保留字是指现在 Java 版本尚未使用,但以后版本可能会作为关键字使用。所以注意 false、true、null 等都是保留字。
Java 标识符:字母、数字、下划线、美元符($)。数字不能作为首位。
主方法入口:所有的 Java 程序由 public static void main(String [ ] args) 方法开始执行。
2. 输入输出方法
使用标准输入输出流。
2.1 标准输入流(System.in)
类型:
InputStream(字节流)作用:从控制台(键盘)读取输入数据
通常需要包装为字符流使用,更方便处理文本
示例:使用System.in读取输入
import java.io.IOException;
import java.io.InputStream;
public class StdinExample {
public static void main(String[] args) {
System.out.print("请输入内容: ");
try (InputStream in = System.in) {
byte[] buffer = new byte[1024];
int bytesRead = in.read(buffer); // 读取字节
String input = new String(buffer, 0, bytesRead).trim();
System.out.println("你输入了: " + input);
} catch (IOException e) {
e.printStackTrace();
}
}
}实际开发中,更常用Scanner或BufferedReader包装System.in:
BufferedReader:主要用于高效读取字符流,特别适合读取大文件或需要缓冲的场景,只能读取字符串类型数据,使用readLine()读取整行.Scanner:专门设计用于解析和读取各种类型的数据,包括基本数据类型,可以直接读取多种数据类型(int, double, String 等), 提供多种读取方法如nextLine(),nextInt(),nextDouble()等.// 使用BufferedReader包装(推荐) BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line = br.readLine(); System.out.print(line); // 使用Scanner(简单场景) Scanner scanner = new Scanner(System.in); String input = scanner.nextLine(); System.out.print(input);
2.2 标准输出流(System.out)
类型:
PrintStream(字节流的子类,提供方便的打印方法)作用:向控制台输出数据
常用方法:
print(),println(),printf()
示例:使用System.out输出
public class StdoutExample {
public static void main(String[] args) {
System.out.print("这是print,"); // 不自动换行
System.out.println("这是println,会自动换行");
// 格式化输出
String name = "Java";
int version = 17;
System.out.printf("编程语言: %s, 版本: %d%n", name, version);
}
}2.3 标准错误流(System.err)
类型:
PrintStream作用:向控制台输出错误信息
特点:通常显示为红色(取决于终端),用于区分正常输出和错误信息
public class StderrExample { public static void main(String[] args) { try { int result = 10 / 0; System.out.println("结果: " + result); } catch (ArithmeticException e) { // 使用err输出错误信息 System.err.println("发生错误: " + e.getMessage()); } } }
2.4 重定向标准流
可以通过System类的方法重定向标准流,将输入输出指向文件或其他流:
import java.io.FileOutputStream;
import java.io.PrintStream;
public class RedirectStreams {
public static void main(String[] args) throws Exception {
// 保存原始输出流
PrintStream originalOut = System.out;
// 重定向标准输出到文件
System.setOut(new PrintStream(new FileOutputStream("output.txt")));
System.out.println("这句话会被写入文件");
// 恢复原始输出流
System.setOut(originalOut);
System.out.println("这句话会显示在控制台");
}
}3. 注释
//:单行注释/* */:多行注释
4. 变量
String- 存储文本,例如 “Hello”。字符串值用双引号括起来int- 存储整数(whole numbers),没有小数,例如 123 或 -123float- 存储带小数的浮点数,例如 19.99 或 -19.99char- 存储单个字符,例如 ‘a’ 或 ‘B’。 char 值用单引号括起来boolean- 以两种状态存储值:true 或 false
声明(创建)变量
如需创建变量,必须指定类型并为其赋值:
typevariable =value;其中 type 是 Java 的一种类型(比如 int 或者 String),variableName 是变量的名称(比如 x 或者 name)。等号用于为变量赋值。
Final变量
final 关键字(这会将变量声明为 “final” 或 “constant”,表示不可更改和只读):
final int myNum = 15;
myNum = 20; // 将产生错误:无法为 final 变量赋值5. 数据类型
数据类型分为两组:
原始数据类型 - 包括
byte、short、int、long、float、double、boolean和char非原始数据类型 - 例如 字符串、数组 和 类
5.1 原始数据类型
原始数据类型指定变量值的大小和类型,并且不拥有额外的方法。
Java 中有八种原始数据类型:
5.2 数字
原始数字类型分为两组:
整数类型 存储整数,正数或负数(例如 123 或 -456),没有小数。有效类型为
byte、short、int和long。您应该使用哪种类型取决于数值。浮点类型 表示带有小数部分的数字,包含一位或多位小数。有两种类型:
float和double。float的精度只有六位或七位小数,而double变量的精度约为 15 位。因此,对于大多数计算来说,使用double更安全。
! 提示: 尽管 Java 中有许多数字类型,但最常用于数字的是 int(整数)和 double(浮点数)。
// 示例
byte byte_Num = 100;
short short_Num = 5000;
int int_Num = 100000;
long long_Num = 15000000000L;
float float_Num = 5.75f;
double double_Num = 19.99d;
boolean isJavaFun = true;
char myGrade = 'B';
String greeting = "Hello World";5.3 非原始数据类型
非原始数据类型称为引用类型,因为它们引用对象。
原始数据类型和非原始数据类型之间的主要区别是:
Java 中预定义(已经定义了)原始类型。非原始类型是由程序员创建的,不是由 Java 定义的(
String除外)。非原始类型可用于调用方法来执行某些操作,而原始类型则不能。
原始类型总是有值,而非原始类型可以为
null。原始类型以小写字母开头,而非原始类型以大写字母开头。
6. 类型转换
类型转换指的是将一种原始数据类型的值赋给另一种类型。
在 Java 中,有两种类型的转换:
放大转换(Widening Casting)(自动) - 将较小的类型转换为较大的类型
byte->short->char->int->long->float->double缩小转换(Narrowing Casting)(手动) - 将较大的类型转换为较小的类型
double->float->long->int->char->short->byte
// 放大转换自动完成
int myInt = 9;
double myDouble = myInt; // 自动转换:int 到 double
// 缩小转换必须再值前面的括号中指明转换类型
double myDouble = 9.78d;
int myInt = (int) myDouble; // 手动转换:double 转换为 int7. 运算符
7.1 算数运算符
7.2 赋值运算符
7.3 比较运算符
7.4 逻辑运算符
8. 字符串
String是不可变对象,所有修改操作(如replace、substring)都会返回新的字符串,原字符串不变。频繁拼接字符串时,建议使用
StringBuilder或StringBuffer以提高性能。
8.1 常用字符串方法
length() :返回字符串长度String str = "Hello"; int len = str.length(); // 结果:5
isEmpty() :判断字符串是否为空(长度为 0)"".isEmpty(); // true "a".isEmpty(); // false
isBlank() (Java 11+):判断字符串是否为空或仅包含空白字符" ".isBlank(); // true " a ".isBlank(); // falsetoUpperCase():将字符串全部转换为大写字母String txt = "Hello World"; System.out.println(txt.toUpperCase()); // 输出 "HELLO WORLD"toLowerCase():将字符串全部转换为小写字母String txt = "Hello World"; System.out.println(txt.toLowerCase()); // 输出 "hello world"
trim() :去除首尾空白字符(不包括中间)" Hello ".trim(); // "Hello"
strip() (Java 11+):去除首尾空白字符(支持 Unicode 空白)" Hello ".strip(); // "Hello"(全角空格也会被去除)
replace(char oldChar, char newChar) :替换所有指定字符"Hello".replace('l', 'x'); // "Hexxo"
replace(CharSequence target, CharSequence replacement) :替换所有指定子串"Hello World".replace("World", "Java"); // "Hello Java"
replaceAll(String regex, String replacement) :按正则表达式替换"a1b2c3".replaceAll("\\d", ""); // "abc"(移除所有数字)
toCharArray() :转换为字符数组char[] arr = "abc".toCharArray(); // ['a','b','c']
valueOf(...) :静态方法,将其他类型转换为字符串String.valueOf(123); // "123" String.valueOf(true); // "true"
join(CharSequence delimiter, CharSequence... elements) :拼接多个字符串并添加分隔符String.join("-", "2023", "10", "01"); // "2023-10-01"
8.2 字符串的截取与拆分
substring(int beginIndex) :从指定索引截取到末尾"Hello".substring(2); // "llo"
substring(int beginIndex, int endIndex) :截取 [begin, end) 区间的子串"Hello".substring(1, 4); // "ell"
split(String regex) :按正则表达式拆分字符串为数组"a,b,c".split(","); // ["a", "b", "c"]
8.3 字符串的查找与判断
contains(CharSequence s) :判断是否包含指定字符序列"Hello World".contains("World"); // true
startsWith(String prefix) :判断是否以指定前缀开头"Hello".startsWith("He"); // true
endsWith(String suffix) :判断是否以指定后缀结尾"file.txt".endsWith(".txt"); // true
indexOf(String str) :返回指定子串首次出现的索引(未找到返回 - 1)"abcabc".indexOf("ab"); // 0
lastIndexOf(String str) :返回指定子串最后出现的索引"abcabc".lastIndexOf("ab"); // 3
charAt(int index) :返回指定索引的字符"Hello".charAt(1); // 'e'
8.4 字符串的拼接与比较
concat(String str) :拼接字符串(等价于+运算符)"Hello".concat(" World"); // "Hello World" // 直接使用+也可以 String str = "Hello" + "World";
equals(Object anObject) :判断内容是否相等(区分大小写)"Hello".equals("hello"); // false
equalsIgnoreCase(String anotherString) :忽略大小写比较内容"Hello".equalsIgnoreCase("hello"); // true
compareTo(String anotherString) :按字典顺序比较(返回整数)"a".compareTo("b"); // -1(a在b前) "b".compareTo("a"); // 1(b在a后) "a".compareTo("a"); // 0(相等)
8.5 字符串中的转义字符
9. 数学方法
注意:所有数学方法都是 static(静态的)。
10. if…else… 判断
eg:
int myNum = 10; // 这是一个正数还是负数?
if (myNum > 0) {
System.out.println("该值为正数。");
} else if (myNum < 0) {
System.out.println("该值为负数。");
} else {
System.out.println("该值为 0。");
}note: 可以用三元运算符代替if…else…
int time = 20;
if (time < 18) {
System.out.println("早安");
} else {
System.out.println("晚安");
}
// 可以写为
int time = 20;
String result = (time < 18) ? "早安" : "晚安";
System.out.println(result);11. Switch 判断
eg:
int day = 4;
switch (day) {
case 6:
System.out.println("Today is Saturday");
break;
case 7:
System.out.println("Today is Sunday");
break;
default:
System.out.println("Today is WorkDay");
}
// 输出 "Today is WorkDay"12. While循环
12.1 while
eg:
int i = 0;
while (i < 5) {
System.out.println(i);
i++;
}12.2 do…while…
eg:
int i = 0;
do {
System.out.println(i);
i++;
}
while (i < 5);13. For循环
eg:
for (int i = 0; i <= 10; i = i + 2) {
System.out.println(i);
}还有一个 “for-each” 循环,专门用于遍历_数组_中的元素:
String[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
for (String i : cars) {
System.out.println(i);
}Note: break 语句可用于跳出_循环_。continue 语句会中断一次迭代(在循环中),并继续循环中的下一次迭代。
14. 数组
14.1 声明数组
声明数组,请使用_方括号_定义变量类型:
String[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
int[] myNum = {10, 20, 30, 40};14.2 数组的访问与修改
访问元素:通过索引(从 0 开始)访问
int first = nums[0]; // 获取第一个元素 String second = names[1]; // 获取第二个元素修改元素:通过索引重新赋值
nums[2] = 100; // 将第三个元素改为100 names[0] = "Anna"; // 修改第一个元素 // 注意:访问超出数组长度的索引会抛出ArrayIndexOutOfBoundsException
14.3 数组排序
使用
java.util.Arrays工具类的sort()方法:import java.util.Arrays; int[] arr = {3, 1, 4, 2}; Arrays.sort(arr); // 升序排序,结果:[1, 2, 3, 4] // 对字符串数组排序(按字典顺序) String[] strs = {"banana", "apple", "cherry"}; Arrays.sort(strs); // 结果:["apple", "banana", "cherry"]自定义排序(对象数组):
// 定义学生类 class Student { String name; int age; // 添加构造函数 public Student(String name, int age) { this.name = name; this.age = age; } // 可选:添加toString方法便于输出 @Override public String toString() { return "Student{name='" + name + "', age=" + age + "}"; } } // 对学生数组按年龄排序(在main方法中使用) Student[] students = {new Student("Bob", 20), new Student("Alice", 18)}; Arrays.sort(students, (s1, s2) -> s1.age - s2.age);
14.4 数组的查找
线性查找:遍历数组逐个比较
public static int findIndex(int[] arr, int target) { for (int i = 0; i < arr.length; i++) { if (arr[i] == target) { return i; // 找到返回索引 } } return -1; // 未找到返回-1 }二分查找:需先排序,效率更高(使用
Arrays.binarySearch())int[] sortedArr = {1, 2, 3, 4, 5}; int index = Arrays.binarySearch(sortedArr, 3); // 返回2(找到) int notFound = Arrays.binarySearch(sortedArr, 6); // 返回负数(未找到)
14.5 数组的复制
Arrays.copyOf() :复制指定长度的数组int[] original = {1, 2, 3}; int[] copy = Arrays.copyOf(original, 5); // 复制并扩容到5个元素,结果:[1,2,3,0,0]
System.arraycopy() :指定源数组、起始位置、目标数组、目标起始位置和复制长度int[] src = {10, 20, 30}; int[] dest = new int[5]; System.arraycopy(src, 1, dest, 2, 2); // 从src[1]复制2个元素到dest[2],结果:[0,0,20,30,0]
14.6 数组的转换
数组转字符串:使用
Arrays.toString()int[] arr = {1, 2, 3}; String str = Arrays.toString(arr); // 结果:"[1, 2, 3]"数组转集合:使用
Arrays.asList()(注意:返回的是固定大小的集合)String[] strs = {"a", "b", "c"}; List<String> list = Arrays.asList(strs);
14.7 多维数组
// 初始化二维数组
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 遍历二维数组
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();
}四、Java方法
1. Java 方法
方法是仅在被调用时运行的代码块。
将数据(称为参数)传递到方法中。
方法用于执行特定的操作,也被称为函数。
为什么要使用方法?重用代码:定义一次代码,多次使用。
📢 这玩意其实就是函数,Java中称之为方法,非要叫的这么高大上。
方法必须在类中声明。它用方法名定义,后跟括号 ()。 Java 提供了一些预定义的方法,例如 System.out.println(),但也可以创建自己的方法来执行某些操作:
如需在 Java 中调用方法,请写方法名称,后跟两个括号 () 和一个分号;
在下例中,myMethod() 用于在调用时打印文本(操作):
public class Main {
static void myMethod() {
System.out.println("Hello world!");
}
public static void main(String[] args) {
myMethod();
}
}
// 输出 "Hello world!"2. 方法重载(函数重载)
可以使得多个方法可以拥有相同的名称和不同的参数:
注意: 只要参数的数量和/或类型不同,多个方法就可以拥有相同的名称。
static int plusMethod(int x, int y) {
return x + y;
}
static double plusMethod(double x, double y) {
return x + y;
}
public static void main(String[] args) {
int myNum1 = plusMethod(8, 5);
double myNum2 = plusMethod(4.3, 6.26);
System.out.println("int: " + myNum1);
System.out.println("double: " + myNum2);
}3. 作用域
在 Java 中,只能在变量被创建的区域内对其访问。这称为作用域。
3.1 方法作用域
直接在方法内部声明的变量,可在方法中声明它们的代码行之后的任何位置使用:
public class Main {
public static void main(String[] args) {
// 此处的代码不能使用 x
int x = 100;
// 此处的代码能够使用 x
System.out.println(x);
}
}3.2 块作用域
代码块是指大括号 {} 之间的所有代码。在代码块内声明的变量只能由大括号之间的代码访问,且这些代码位于声明变量的行之后:
public class Main {
public static void main(String[] args) {
// 此处的代码不能使用 x
{ // 这是代码块
// 此处的代码不能使用 x
int x = 100;
// 此处的代码能够使用 x
System.out.println(x);
} // 代码块在此处结束
// 此处的代码不能使用 x
}
}4. Java 递归
递归(Recursion)是使函数调用其本身。
eg: 使用递归将 5 到 10 之间的所有数字相加
public class Main {
public static void main(String[] args) {
int result = sum(5, 10);
System.out.println(result);
}
public static int sum(int start, int end) {
if (end > start) {
return end + sum(start, end - 1);
} else {
return end;
}
}
}Note: 递归必须有停止条件,避免递归陷入死循环。
五、Java 类
1. Java 类和对象
类是对现实世界中事物的抽象(比如 “人” 可以抽象为
Person类,包含 “姓名、年龄” 等属性和 “吃饭、睡觉” 等方法)。所有的 Java 代码(变量、方法、逻辑)都必须定义在类中,没有 “类外的代码”。
程序的运行也是以类为单位:通过类创建对象(
new 类名()),通过对象调用方法来完成功能。类名使用大驼峰命名法(每个单词首字母大写)
1.1 类的定义语法与示例
[修饰符] class 类名 [extends 父类名] [implements 接口名列表] {
// 成员变量(属性)
// 成员方法(行为)
// 构造方法
// 内部类
}示例:
// 定义一个Person类
public class Person {
// 成员变量(属性)
private String name;
private int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 成员方法(行为)
public void sayHello() {
System.out.println("Hello, my name is " + name);
}
// getter和setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}1.2 类定义中的关键字
访问控制修饰符
用于控制类、成员变量、方法的访问权限。
// public类:可以被所有类访问
public class PublicClass {
public String publicField; // 所有类可访问
protected String protectedField; // 本类、同包类、子类可访问
String defaultField; // 本类、同包类可访问
private String privateField; // 仅本类可访问
public void publicMethod() {} // 所有类可访问
protected void protectedMethod() {}// 本类、同包类、子类可访问
void defaultMethod() {} // 本类、同包类可访问
private void privateMethod() {} // 仅本类可访问
}static 关键字
用于修饰类的成员(变量、方法、内部类),表示属于类本身而非实例。
静态变量(类变量)
public class Counter { // 静态变量:所有对象共享同一个值 private static int count = 0; // 实例变量:每个对象有独立的值 private int id; public Counter() { count++; id = count; } public static int getCount() { return count; } public int getId() { return id; } } // 使用示例 public class Main { public static void main(String[] args) { Counter c1 = new Counter(); Counter c2 = new Counter(); System.out.println(Counter.getCount()); // 输出:2(通过类名访问) System.out.println(c1.getId()); // 输出:1 System.out.println(c2.getId()); // 输出:2 } }静态方法(类方法)
可直接通过类名调用,无需创建对象
静态方法中不能使用
this和super关键字静态方法只能访问静态成员,不能访问非静态成员
public class MathUtil { // 静态方法:工具类常用 public static int add(int a, int b) { return a + b; } public static int multiply(int a, int b) { return a * b; } } // 调用静态方法 int sum = MathUtil.add(3, 5); // 直接通过类名调用静态内部类
public class OuterClass { private int outerField = 10; private static int staticOuterField = 20; // 静态内部类 public static class StaticInnerClass { public void print() { // 可以访问外部类的静态成员 System.out.println("静态外部变量: " + staticOuterField); // 不能直接访问外部类的非静态成员 // System.out.println(outerField); // 编译错误 } } // 非静态内部类 public class NonStaticInnerClass { public void print() { // 可以访问外部类的所有成员 System.out.println("非静态外部变量: " + outerField); System.out.println("静态外部变量: " + staticOuterField); } } }
final 关键字
表示 “不可改变”,可修饰类、方法、变量。
修饰类
被
final修饰的类不能被继承。// final类不能有子类 public final class FinalClass { // ... } // 编译错误:不能继承final类 // public class SubClass extends FinalClass {}修饰方法
被
final修饰的方法不能被重写。public class Parent { // final方法不能被重写 public final void finalMethod() { System.out.println("这是final方法"); } } public class Child extends Parent { // 编译错误:不能重写final方法 // public void finalMethod() {} }修饰变量
被
final修饰的变量成为常量,一旦赋值就不能改变。public class FinalVariableExample { // 声明时赋值 public final int CONSTANT1 = 100; // 空白final变量,必须在构造方法中赋值 public final int CONSTANT2; public FinalVariableExample() { CONSTANT2 = 200; // 构造方法中赋值 } public void method() { final int localConstant = 300; // localConstant = 400; // 编译错误:不能修改final变量 } }
abstract 关键字
用于声明抽象类和抽象方法。
抽象类
不能被实例化
可以包含抽象方法和非抽象方法
抽象类的子类必须实现所有抽象方法(除非子类也是抽象类)
// 抽象类 public abstract class Animal { // 非抽象方法 public void breathe() { System.out.println("呼吸空气"); } // 抽象方法:只有声明,没有实现 public abstract void makeSound(); } // 继承抽象类并实现抽象方法 public class Dog extends Animal { @Override public void makeSound() { System.out.println("汪汪汪"); } } public class Cat extends Animal { @Override public void makeSound() { System.out.println("喵喵喵"); } }
this 关键字
表示当前对象的引用,用于:
区分成员变量和局部变量
public class Person { private String name; public void setName(String name) { this.name = name; // this.name表示成员变量 } }调用当前类的其他构造方法
public class Person { private String name; private int age; public Person() { this("未知", 0); // 调用带参数的构造方法 } public Person(String name, int age) { this.name = name; this.age = age; } }返回当前对象
public class Person { private int age; public Person setAge(int age) { this.age = age; return this; // 返回当前对象,支持方法链调用 } } // 方法链调用 Person p = new Person(); p.setAge(20).setName("张三"); // 假设还有setName方法
super 关键字
用于访问父类的成员,主要用途:
调用父类的构造方法
public class Animal { protected String name; public Animal(String name) { this.name = name; } } public class Dog extends Animal { private String breed; public Dog(String name, String breed) { super(name); // 调用父类的构造方法 this.breed = breed; } }调用父类的方法
public class Parent { public void print() { System.out.println("父类的print方法"); } } public class Child extends Parent { @Override public void print() { super.print(); // 调用父类的print方法 System.out.println("子类的print方法"); } }
其他相关关键字
extends 关键字
用于表示类的继承关系,Java 中类只能单继承。
public class Animal { // ... } // Dog类继承Animal类 public class Dog extends Animal { // 继承了Animal类的属性和方法 // 可以添加自己特有的属性和方法 }implements 关键字
用于表示类实现接口,一个类可以实现多个接口。
public interface Runnable { void run(); } public interface Swimmable { void swim(); } // 实现多个接口 public class Duck implements Runnable, Swimmable { @Override public void run() { System.out.println("鸭子在跑"); } @Override public void swim() { System.out.println("鸭子在游泳"); } }transient 关键字
用于修饰成员变量,表示该变量不会被序列化。
import java.io.Serializable; public class User implements Serializable { private String username; private transient String password; // 不会被序列化 // getter和setter方法 }volatile 关键字
用于修饰成员变量,确保多线程环境下变量的可见性。
public class VolatileExample { private volatile boolean flag = false; public void setFlag(boolean flag) { this.flag = flag; } public void checkFlag() { while (!flag) { // 循环等待,直到flag变为true } System.out.println("Flag已变为true"); } }synchronized 关键字
方法一次只能被一个线程访问。
1.3 创建对象
在 Java 中,对象是从类创建的。我们已经创建了名为 Main 的类,所以现在我们可以使用它来创建对象。
如需创建 Main 对象,请指定类名,后跟对象名,并使用关键字 new:
public class Main {
int x = 5;
public static void main(String[] args) {
Main myObj1 = new Main(); // 对象 1
Main myObj2 = new Main(); // 对象 2
System.out.println(myObj1.x);
System.out.println(myObj2.x);
}
}1.4 使用多个类
还可以创建一个类的对象并在另一个类中访问它。这通常用于更好地组织类(一个类拥有所有属性和方法,而另一个类拥有 main() 方法(要执行的代码))。
请记住,java 的文件名应与类名相匹配。在这个例子中,我们在同一个目录/文件夹中创建了两个文件:
Main.java
Second.java
Main.java
public class Main {
int x = 5;
}Second.java
class Second {
public static void main(String[] args) {
Main myObj = new Main();
System.out.println(myObj.x);
}
}当两个文件都编译完成后:
C:\Users\Your Name>javac Main.java
C:\Users\Your Name>javac Second.java运行 Second.java 文件:
C:\Users\Your Name>java Second将会输出5.
2. Java 类方法
方法是在类中声明的,并且它们用于执行某些操作:
示例:
在 Main 中创建名为 myMethod() 的方法:
public class Main {
static void myMethod() {
System.out.println("Hello World!");
}
public static void main(String[] args) {
myMethod();
}
}
// 输出 "Hello World!"静态与非静态
经常会看到具有 static 或 public 属性和方法的 Java 程序。 static 方法和 public 方法之间差异的例子:
public class Main {
// 静态方法:
static void myStaticMethod() {
System.out.println("无需创建对象即可调用静态方法");
}
// 公共方法:
public void myPublicMethod() {
System.out.println("公共方法必须通过创建对象来调用");
}
// 主方法:
public static void main(String[] args) {
myStaticMethod(); // 调用静态方法
// myPublicMethod(); 这会编译错误
Main myObj = new Main(); // 创建 Main 的对象
myObj.myPublicMethod(); // 调用对象的公共方法
}
}3. Java 构造函数
Java 中的构造函数是一种用于初始化对象的特殊方法。创建类的对象时,会调用构造函数。它可用于设置对象属性的初始值:
请注意,构造函数名称必须与类名称匹配 , 并且不能有返回类型(比如 void)。
public class Main {
int modelYear;
String modelName;
public Main(int year, String name) {
modelYear = year;
modelName = name;
}
public static void main(String[] args) {
Main myCar = new Main(1969, "Mustang");
System.out.println(myCar.modelYear + " " + myCar.modelName);
}
}
// 输出 1969 Mustang4. Java 封装
封装(Encapsulation) 的含义,是确保“敏感”数据对用户隐藏。要实现这一目标,您必须:
将类变量/属性声明为
private提供公共 get 和 set 方法来访问和更新
private变量的值
public class Person {
private String name; // private = 禁止进入
// Getter
public String getName() {
return name;
}
// Setter
public void setName(String newName) {
this.name = newName;
}
}
public class Main {
public static void main(String[] args) {
Person myObj = new Person();
myObj.name = "Bill"; // 错误
System.out.println(myObj.name); // 错误
}
}get 方法返回变量名的值。
set 方法接受一个参数 (newName) 并将其分配给 name 变量。this 关键字用于引用当前对象。
但是,由于 name 变量被声明为 private,我们_无法_从此类外部访问它:
正确访问应该如下:
public class Main {
public static void main(String[] args) {
Person myObj = new Person();
myObj.setName("Bill"); // 将 name 变量的值设置为 "Bill"
System.out.println(myObj.getName());
}
}
// 输出 "Bill"为什么要封装?
更好地控制类属性和方法
类属性可以设为_只读 *(如果只使用
get* * 方法)或*只写_(如果只使用set方法)灵活:程序员可以改变一部分代码而不影响其他部分
提高数据安全性
5. Java 包和 API
Java 中的包用于对相关类进行分组。可将其视为_文件目录中的文件夹_。我们使用包来避免名称冲突,并编写更好的可维护代码。
包分为两类:
内置包(来自 Java API 的包)
用户定义的包(创建您自己的包)
5.1 内置软件包
Java API 是一个预先编写的类库,可以免费使用,包含在 Java 开发环境中。
该库包含用于管理输入、数据库编程等的组件。完整列表可以在 Oracles 网站上找到:
https://docs.oracle.com/javase/8/docs/api/
库分为包和类。这意味着您可以导入单个类(及其方法和属性),也可以导入包含属于指定包的所有类的整个包。
如需使用库中的类或包,您需要使用 import 关键字:
语法:
import package.name.Class; // 导入单个类
import package.name.*; // 导入整个包5.2 导入类
如果导入需要使用的类,例如_用于获取用户输入_的 Scanner 类,请编写以下代码: 实例
import java.util.Scanner;
class MyClass {
public static void main(String[] args) {
Scanner myObj = new Scanner(System.in);
System.out.println("Enter username");
String userName = myObj.nextLine();
System.out.println("Username is: " + userName);
}
}在上面的例子中,java.util 是一个包,而 Scanner 是 java.util 包的一个类。使用时需要创建该类的对象并使用 Scanner 类文档中的任何可用方法。上面的例子中,使用 nextLine() 方法,该方法用于读取完整行。
5.3 导入包
有很多包可供选择。在前面的实例中,我们使用了 java.util 包中的 Scanner 类。这个包还包含日期和时间工具、随机数生成器和其他实用程序类。
如需导入整个包,请以星号 (*) 结束句子。下例将导入 java.util 包中的所有类:
import java.util.*;5.4 用户定义的包
如需创建自己的包,您需要了解:Java 使用文件系统目录来存储它们。就像计算机上的文件夹一样:
└── root
└── mypack
└── MyPackageClass.java如需创建包,请使用 package 关键字: MyPackageClass.java
package mypack;
class MyPackageClass {
public static void main(String[] args) {
System.out.println("这是我的包!");
}
}将文件保存为 MyPackageClass.java,并编译它:
C:\Users\Your Name>javac MyPackageClass.java然后编译包:
C:\Users\Your Name>javac -d . MyPackageClass.java这会强制编译器创建 “mypack” 包。
d关键字指定保存类文件的目的地。您可以使用任何目录名称,例如 c:/user (windows),或者,如果您想将包保存在同一目录中,您可以使用点号 “.”,如上例所示。注意: 包名要小写,以免与类名冲突。
当我们编译上例中的包时,会创建名为 “mypack” 的新文件夹。
如需运行 MyPackageClass.java 文件,请键入以下内容:
C:\Users\Your Name>java mypack.MyPackageClass
// 输出:这是我的包!6. Java 继承(子类和超类)
在 Java 中,可以从一个类继承属性和方法到另一个类。将“继承”这个概念分为两类:
subclass (子类) - 从另一个类继承的类
superclass(父类) - 被继承的类
如需从类继承,请使用 extends 关键字。
在下例中,Car 类(子类)继承了 Vehicle 类(超类)的属性和方法:
class Vehicle {
protected String brand = "Ford"; // Vehicle 属性
public void honk() { // Vehicle 方法
System.out.println("Tuut, tuut!");
}
}
class Car extends Vehicle {
private String modelName = "Mustang"; // Car 属性
public static void main(String[] args) {
// 创建 myCar 对象
Car myCar = new Car();
// 调用 myCar 对象上的 honk() 方法(来自 Vehicle 类)
myCar.honk();
// 显示 brand 属性的值(来自 Vehicle 类)和来自 Car 类的 modelName 的值
System.out.println(myCar.brand + " " + myCar.modelName);
}
}是否注意到 Vehicle 中的
protected 修饰符?将 Vehicle 中的 brand 属性设置为
protected访问修饰符。如果将其设置为private,则 Car 类将无法访问它。为什么以及何时使用“继承”?
它对于代码可重用性很有用:请在创建新类时重用现有类的属性和方法。
final 关键词
如果不希望其他类从某个类继承,使用 final 关键字:
如果尝试访问 final 类,Java 将生成错误:
final class Vehicle {
...
}
class Car extends Vehicle {
...
}输出将是这样的:
Main.java:9: error: cannot inherit from final Vehicle
class Main extends Vehicle {
^
1 error)7. Java 多态
多态(Polymorphism)的意思是“多种形式”,它发生在我们有许多通过继承相互关联的类时。继承让我们从另一个类继承属性和方法 。多态使用这些方法来执行不同的任务。这允许我们以不同的方式执行单一操作。 例如:名为 Animal 的超类,它有一个名为 animalSound() 的方法。Animals 的子类可以是 Pigs、Cats、Dogs、Birds - 而且它们也有自己的动物声音实现(猪的 oinks 和猫的 meows 等):
class Animal {
public void animalSound() {
System.out.println("The animal makes a sound");
}
}
class Pig extends Animal {
public void animalSound() {
System.out.println("The pig says: wee wee");
}
}
class Dog extends Animal {
public void animalSound() {
System.out.println("The dog says: bow wow");
}
}
class Main {
public static void main(String[] args) {
Animal myAnimal = new Animal(); // 创建 Animal 对象
Animal myPig = new Pig(); // 创建 Pig 对象
Animal myDog = new Dog(); // 创建 Dog 对象
myAnimal.animalSound();
myPig.animalSound();
myDog.animalSound();
}
}8. Java 内部类
8.1 Java 内部类
在 Java 中,也可以嵌套类(类中的类)。嵌套类的目的是将属于一起的类进行分组,这会使您的代码更具可读性和可维护性。
如需访问内部类,先创建外部类的对象,然后再创建内部类的对象:
class OuterClass {
int x = 10;
class InnerClass {
int y = 5;
}
}
public class Main {
public static void main(String[] args) {
OuterClass myOuter = new OuterClass();
OuterClass.InnerClass myInner = myOuter.new InnerClass();
System.out.println(myInner.y + myOuter.x);
}
}
// 输出 15 (5 + 10)8.2 私有内部类
与“常规”类不同,内部类可以是 private 或 protected。如果您不希望外部对象访问内部类,请将该类声明为 private:
class OuterClass {
int x = 10;
private class InnerClass {
int y = 5;
}
}
public class Main {
public static void main(String[] args) {
OuterClass myOuter = new OuterClass();
OuterClass.InnerClass myInner = myOuter.new InnerClass();
System.out.println(myInner.y + myOuter.x);
}
}从外部访问私有内部类会发生错误:
Main.java:13: error: OuterClass.InnerClass has private access in OuterClass
OuterClass.InnerClass myInner = myOuter.new InnerClass();8.3 静态内部类
内部类也可以是 static,这意味着您可以在不创建外部类的对象的情况下访问它:
class OuterClass {
int x = 10;
static class InnerClass {
int y = 5;
}
}
public class Main {
public static void main(String[] args) {
OuterClass.InnerClass myInner = new OuterClass.InnerClass();
System.out.println(myInner.y);
}
}
// 输出 58.4 从内部类访问外部类
内部类的优点之一是它们可以访问外部类的属性和方法:
class OuterClass {
int x = 10;
class InnerClass {
public int myInnerMethod() {
return x;
}
}
}
public class Main {
public static void main(String[] args) {
OuterClass myOuter = new OuterClass();
OuterClass.InnerClass myInner = myOuter.new InnerClass();
System.out.println(myInner.myInnerMethod()); // 直接调用内部类的方法返回了外部类的属性
}
}
// 输出 109. Java 抽象
数据抽象是隐藏某些细节并仅向用户显示基本信息的过程。
抽象可以通过抽象类或接口来实现
abstract 关键字是一个非访问修饰符,用于类和方法:
抽象类:是一种受限制的类,不能用于创建对象(要访问它,它必须从另一个类继承)。
抽象方法:只能在抽象类中使用,并且没有主体。主体由子类提供(继承自)。
抽象类可以同时拥有抽象方法和常规方法:
abstract class Animal {
public abstract void animalSound();
public void sleep() {
System.out.println("Zzz");
}
}在上例中,无法创建 Animal 类的对象:
Animal myObj = new Animal(); // 会产生错误如需访问抽象类,它必须从另一个类继承。
// 抽象类:
abstract class Animal {
// 抽象方法(没有主体):
public abstract void animalSound();
// 常规方法:
public void sleep() {
System.out.println("Zzz");
}
}
// 子类(继承自 Animal):
class Pig extends Animal {
public void animalSound() {
// 此处提供了 animalSound() 的主体
System.out.println("The pig says: wee wee");
}
}
class Main {
public static void main(String[] args) {
Pig myPig = new Pig(); // 创建 Pig 对象
myPig.animalSound(); // 打印: The pig says: wee wee
myPig.sleep(); // 打印: Zzz
}
}10. Java 接口
在 Java 中实现抽象的另一种方法是使用接口。
interface 是一种完全 “抽象类” ,用于组合相关方法与空主体:
// 接口:
interface Animal {
public void animalSound(); // 接口方法(没有主体)
public void run(); // 接口方法(没有主体)
}如需访问接口方法,接口必须由另一个类使用 implements 关键字(而不是 extends)来“实现”(有点像继承)。
// 接口:
interface Animal {
public void animalSound(); // 接口方法(没有主体)
public void sleep(); // 接口方法(没有主体)
}
// Pig “实现”了 Animal 接口:
class Pig implements Animal {
public void animalSound() {
// 此处提供了 animalSound() 的主体
System.out.println("The pig says: wee wee");
}
public void sleep() {
// 此处提供了 sleep() 的主体
System.out.println("Zzz");
}
}
class Main {
public static void main(String[] args) {
Pig myPig = new Pig(); // 创建 Pig 对象
myPig.animalSound();
myPig.sleep();
}
}接口注意事项:
与抽象类一样,接口不能用于创建对象(在上面的例子中,不可能在 MyMainClass 中创建 “Animal” 对象)
接口方法没有主体 - 主体由 “implement” 类提供
在实现接口时,您必须覆盖其所有方法
接口方法默认是
abstract和public接口属性默认为
public、static和final接口不能包含构造函数(因为它不能用于创建对象)
为什么以及何时使用接口?
1)为了实现安全 - 隐藏某些细节,只显示一个对象(接口)的重要细节。
2)Java 不支持“多重继承”(一个类只能从一个超类继承)。但是,它可以通过接口来实现,因为类可以_实现_ 多个接口。
注释: 如需实现多个接口,用逗号分隔它们(请见下面的例子)。
多个接口
要实现多个接口,请用逗号分隔它们:
interface FirstInterface {
public void myMethod(); // 接口方法
}
interface SecondInterface {
public void myOtherMethod(); // 接口方法
}
class DemoClass implements FirstInterface, SecondInterface {
public void myMethod() {
System.out.println("Some text..");
}
public void myOtherMethod() {
System.out.println("Some other text...");
}
}
class Main {
public static void main(String[] args) {
DemoClass myObj = new DemoClass();
myObj.myMethod();
myObj.myOtherMethod();
}
}11. Java 枚举
11.1 枚举
枚举(enum)是一种特殊的“类”,代表一组 常量(不可更改的变量,如 final 变量)。
如需创建 enum,请使用 enum 关键字(而不是类或接口),并用逗号分隔常量。请注意,它们应为大写字母:
enum Level {
LOW,
MEDIUM,
HIGH
}使用点语法访问 enum 常量:
Level myVar = Level.MEDIUM;11.2 类中的枚举
public class Main {
enum Level {
LOW,
MEDIUM,
HIGH
}
public static void main(String[] args) {
Level myVar = Level.MEDIUM;
System.out.println(myVar);
}
}
// 输出:MEDIUM11.3 Switch 语句中的枚举
枚举通常用于 switch 语句中,以检查相应的值:
enum Level {
LOW,
MEDIUM,
HIGH
}
public class Main {
public static void main(String[] args) {
Level myVar = Level.MEDIUM;
switch(myVar) {
case LOW:
System.out.println("低级");
break;
case MEDIUM:
System.out.println("中级");
break;
case HIGH:
System.out.println("高级");
break;
}
}
}
// 输出:中级11.4 遍历枚举
枚举类型有一个 values() 方法,它返回包含所有枚举常量的数组。当您想遍历枚举的常量时,此方法很有用:
for (Level myVar : Level.values()) {
System.out.println(myVar);
}
// 输出:LOW
// MEDIUM
// HIGH枚举和类的区别
enum可以像class一样拥有属性和方法。唯一的区别是枚举常量是public、static和final(不可更改 - 不能被覆盖)。
enum不能用于创建对象,也不能扩展其他类(但它可以实现接口)。为什么以及何时使用枚举?
当您知道某些值不会改变时请使用枚举,例如月、日、颜色、一副牌等。
12. Java 用户输入 (Scanner)
Scanner 类用于获取用户输入,它位于 java.util 包中。如需使用 Scanner 类,请创建该类的对象并使用 Scanner 类文档中的任何可用方法。输入类型表如下:
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner myObj = new Scanner(System.in);
System.out.println("请输入名字、年龄、薪资:");
// 字符串输入
String name = myObj.nextLine();
// 数值输入
int age = myObj.nextInt();
double salary = myObj.nextDouble();
// 输出用户的输入
System.out.println("名字:" + name);
System.out.println("年龄:" + age);
System.out.println("薪资:" + salary);
}
}13. Java 日期和时间
Java 没有内置的 Date 类,但我们可以导入 java.time 包来使用日期和时间 API。该软件包囊括了许多日期和时间类。例如:
13.1 显示当前日期
如需显示当前日期,请导入 java.time.LocalDate 类,并使用其 now() 方法:
import java.time.LocalDate; // 导入 LocalDate 类
public class Main {
public static void main(String[] args) {
LocalDate myObj = LocalDate.now(); // 创建日期对象
System.out.println(myObj); // 显示当前日期
}
}
// 输出: 2025-07-2713.2 显示当前时间
如需显示当前时间(小时、分钟、秒和纳秒),请导入 java.time.LocalTime 类,并使用其 now() 方法:
import java.time.LocalTime; // 导入 LocalTime 类
public class Main {
public static void main(String[] args) {
LocalTime myObj = LocalTime.now();
System.out.println(myObj);
}
}
// 输出: 18:51:44.89097460013.3 显示当前日期和时间
如需显示当前日期和时间,请导入 java.time.LocalDateTime 类,并使用其 now() 方法:
import java.time.LocalDateTime; // 导入 LocalDateTime 类
public class Main {
public static void main(String[] args) {
LocalDateTime myObj = LocalDateTime.now();
System.out.println(myObj);
}
}
// 输出: 2025-07-27T18:52:39.20753350013.4 格式化日期和时间
上例中的 “T” 用于将日期与时间分开。您可以使用 DateTimeFormatter 类和同一包中的 ofPattern() 方法来格式化或解析日期时间对象。下例将从日期时间中删除 “T” 和纳秒:
import java.time.LocalDateTime; // 导入 LocalDateTime 类
import java.time.format.DateTimeFormatter; // 导入 DateTimeFormatter 类
public class Main {
public static void main(String[] args) {
LocalDateTime myDateObj = LocalDateTime.now();
System.out.println("格式化之前:" + myDateObj);
DateTimeFormatter myFormatObj = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm:ss");
String formattedDate = myDateObj.format(myFormatObj);
System.out.println("格式化之后:" + formattedDate);
}
}
// 格式化之前:2025-07-27T18:53:41.060494900
// 格式化之后:27-07-2025 18:53:41ofPattern() 方法接受各种值,如果您想以不同的格式显示日期和时间。例如:
六、Java 数据结构
1. 包装类
1.1 先明确两个关键概念
基本数据类型(Primitive Types) Java 有 8 种基本类型:
int、byte、short、long、float、double、char、boolean。特点:直接存储值(而非地址),不继承Object类,不能调用方法,存储在栈内存中。引用数据类型(Reference Types) 包括:类(如
String、Integer)、接口、数组、枚举等。特点:存储的是对象的地址(而非值本身),继承Object类,可调用方法,对象实体存储在堆内存中。
Java中的集合框架(如List、Set、Map等)对存储类型的支持规则不同,但共同遵循一个原则:引用类型可以直接存储,基本类型需特殊处理。
1.2 为什么String可以直接使用?
String是引用类型(本质是String类的对象),无论在数组还是列表中,都符合容器对 “存储引用类型” 的要求。
1.3 为什么其他基本类型(如int)需要用Integer?
以int为例,它是基本类型,而 Java 的集合框架(如List、Set)只能存储引用类型,不能直接存储基本类型。因此需要用对应的 “包装类”(Integer)来包装基本类型,使其成为引用类型。
1.4 包装类的作用:连接基本类型和引用类型
在使用非 String 类型时,必须指定等效的包装类:Integer
2. ArrayList(数组)
ArrayList 类是一种可调整大小的数组,可以在 java.util 包中找到。
Java 中的内置数组和 ArrayList 的区别在于,数组的大小不能修改(如果要向数组添加元素或从数组中删除元素,则必须创建一个新数组)。虽然可以随时在 ArrayList 中添加和删除元素。语法也略有不同。
以下表格列出了 ArrayList 的所有方法。
部分方法使用 ArrayList 中元素的类型作为参数或返回值。在表格中,这种类型将被表示为 T。
示例:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo"); // 添加元素
cars.add(0, "Mazda"); // 在列表开头(索引0)插入元素
String temp_car = cars.get(0); // 访问元素
cars.set(1, "BWM"); // 修改指定索引的元素
cars.remove(0); // 删除指定索引的元素
cars.clear(); // 删除所有元素
int size = cars.size(); // 获取数组长度
// for 循环遍历数组
for (int i = 0; i < cars.size(); i++) {
System.out.println(cars.get(i));
}
// for-each 循环遍历数组
for (String i : cars) {
System.out.println(i);
}
System.out.println(size);
System.out.println(temp_car);
System.out.println(cars);
}
}对数组进行排序
java.util 包中另一个有用的类是 Collections 类,它包括 sort() 方法,用于按字母或数字对列表进行排序:
import java.util.ArrayList;
import java.util.Collections; // 导入 Collections 类
public class Main {
public static void main(String[] args) {
ArrayList<Integer> myNumbers = new ArrayList<Integer>(); //注意非String对象的数据类型必须为Integer
myNumbers.add(33);
myNumbers.add(15);
myNumbers.add(20);
myNumbers.add(34);
myNumbers.add(8);
myNumbers.add(12);
Collections.sort(myNumbers); // 对 myNumbers 进行升序排序
// Collections.sort(myNumbers, Collections.reverseOrder()); // 对 myNumbers 进行逆序排序
for (int number : myNumbers) {
System.out.println(number);
}
}
}3. LinkedList(链表)
以下表格列出了 LinkedList 的所有方法。
部分方法使用 LinkedList 中元素的类型作为参数或返回值。在表格中,这种类型将被表示为 T。
示例:
// 导入 LinkedList 类
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
LinkedList<String> cars = new LinkedList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
System.out.println(cars);
}
}ArrayList 与 LinkedList
LinkedList类是一种集合,它可以包含许多相同类型的对象,就像ArrayList一样。
LinkedList类拥有与ArrayList类相同的所有方法,因为它们都实现了List接口。这意味着您可以以相同的方式添加项目、更改项目、删除项目和清除列表。然而,虽然
ArrayList类和LinkedList类能够以相同的方式使用,但它们的构建方式却大不相同。ArrayList 的工作原理
ArrayList类内部有一个常规数组。添加元素时,将其放入数组中。如果数组不够大,则会创建一个新的更大的数组来替换旧数组,然后删除旧数组。LinkedList 的工作原理
LinkedList将其项目存储在“容器”中。该列表有一个指向第一个容器的链接,每个容器都有一个指向列表中下一个容器的链接。要将元素添加到列表中,需要将该元素放入一个新容器中,并将该容器链接到列表中的其他容器之一。何时使用
请使用
ArrayList存储和访问数据,使用LinkedList操作数据。
4. HashMap
HashMap 用来存储键值对。它可以存储不同的类型:String 键和 Integer 值,或相同的类型,如:String 键和 String 值:
4.1 创建 HashMap
创建名为 capitalCities 的 HashMap 对象,它将存储 String 键 和 String 值:
import java.util.HashMap; // 导入 HashMap 类
HashMap<String, String> capitalCities = new HashMap<String, String>();4.2 添加项目
向其中添加项目,使用 put() 方法:
// 导入 HashMap 类
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
// 创建名为 capitalCities 的 HashMap 对象
HashMap<String, String> capitalCities = new HashMap<String, String>();
// Add keys and values (Country, City)
capitalCities.put("China", "Beijing");
capitalCities.put("England", "London");
capitalCities.put("Germany", "Berlin");
capitalCities.put("USA", "Washington DC");
System.out.println(capitalCities);
}
}4.3 访问项目
如需访问 HashMap 中的值,使用 get() 方法并引用其键:
capitalCities.get("England")4.4 删除项目
如需删除项目,使用 remove() 方法并引用键:
capitalCities.remove("England")如需删除所有项目,使用 clear() 方法:
capitalCities.clear();4.5 哈希图大小
如需找出有多少项目,使用 size() 方法:
capitalCities.size();4.6 循环遍历 HashMap
使用 for-each 循环遍历 HashMap 的项目。
注释: 如果您只需要键,请使用 keySet() 方法,如果您只需要值,请使用 values() 方法:
// 打印键
for (String i : capitalCities.keySet()) {
System.out.println(i);
}
// 打印值
for (String i : capitalCities.values()) {
System.out.println(i);
}
// 打印键和值
for (String i : capitalCities.keySet()) {
System.out.println("key: " + i + " value: " + capitalCities.get(i));
}5. HashSet
HashSet 是项目的集合,其中每个项目都是唯一的,可以在 java.util 包中找到:
5.1 创建HashSet
创建名为 cars 的 HashSet 对象,用于存储字符串:
import java.util.HashSet; // 导入 HashSet 类
HashSet<String> cars = new HashSet<String>();5.3 添加项目
要向其中添加项目,使用 add() 方法:
// 导入 HashSet 类
import java.util.HashSet;
public class Main {
public static void main(String[] args) {
HashSet<String> cars = new HashSet<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("BMW");
cars.add("Mazda");
System.out.println(cars);
}
}5.4 检查项目是否存在
如需检查 HashSet 中是否存在项目,使用 contains() 方法:
cars.contains("Mazda");5.5 删除项目
如需删除项目,使用 remove() 方法:
cars.remove("Volvo");如需删除所有项目,使用 clear() 方法:
cars.clear()5.6 HashSet 大小
如需找出有多少项,使用 size 方法:
cars.size()5.7 循环遍历 HashSet
for (String i : cars) {
System.out.println(i);
}6. Iterator 迭代器
迭代器(Iterator)是一种对象,可用于循环遍历集合,比如 ArrayList 和 HashSet。 要使用迭代器,必须从 java.util 包中导入它。
6.1 获取迭代器
iterator() 方法可用于获取任何集合的 Iterator:
// 导入 ArrayList 类和 Iterator 类:
import java.util.ArrayList;
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
// 生成集合:
ArrayList<String> cars = new ArrayList<String>();
cars.add("Volvo");
cars.add("BMW");
cars.add("Ford");
cars.add("Mazda");
// 获取迭代器:
Iterator<String> it = cars.iterator(); //此时迭代器的初始状态是指向集合中第一个元素的 “前面”
// 打印首个项目:
System.out.println(it.next());
}
}6.2 循环遍历集合
如需循环遍历集合,使用 Iterator 的 hasNext() 和 next() 方法:
while(it.hasNext()) {
System.out.println(it.next());
}6.3 从集合中删除项目
迭代器旨在轻松更改它们循环遍历的集合。remove() 方法可以在循环时从集合中删除项目。
示例:使用迭代器从集合中删除小于 10 的数字:
import java.util.ArrayList;
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(12);
numbers.add(8);
numbers.add(2);
numbers.add(23);
Iterator<Integer> it = numbers.iterator();
while(it.hasNext()) { // it.hasNext()用于检查集合中是否还有下一个元素。
Integer i = it.next();
if(i < 10) {
it.remove();
}
}
System.out.println(numbers);
}
}注意: 尝试使用 for 循环或 for-each 循环删除项目将无法正常工作,因为在代码尝试循环的同时,集合正在更改大小。
七、Java 高级
1. 异常
在执行 Java 代码时,可能会发生各种错误:程序员的编码错误、错误输入导致的异常或其他不可预见的情况。当发生错误时,Java 通常会停止并生成错误消息。用技术术语讲就是:Java 将抛出 异常(抛出错误)。
1.1 Try…Catch
try 语句允许您定义要在执行时测试错误的代码块。 如果try块中发生错误,catch 语句允许您定义要执行的代码块。 try 和 catch 关键字成对出现: 语法:
try {
// 要尝试的代码块
}
catch(Exception e) {
// 处理错误的代码块
}示例:
public class Main {
public static void main(String[ ] args) {
try {
int[] myNumbers = {1, 2, 3};
System.out.println(myNumbers[10]);
} catch (Exception e) {
System.out.println("出错了。");
}
}
}
// 输出: 出错了1.2 Finally
finally 语句让你在 try...catch 之后执行代码,不管结果如何:
public class Main {
public static void main(String[] args) {
try {
int[] myNumbers = {1, 2, 3};
System.out.println(myNumbers[10]);
} catch (Exception e) {
System.out.println("出错了。");
} finally {
System.out.println("'try catch' 已结束。");
}
}
}
// 输出:
// 出错了。
// 'try catch' 已结束。1.3 throw 关键字
throw 语句允许您创建自定义错误。
throw 语句可与异常类型一同使用。Java 中有许多可用的异常类型:
ArithmeticException:算术异常,当出现数学运算错误时抛出。最常见的情况是整数除以零(int a = 5 / 0;),因为这在数学上是无意义的操作。FileNotFoundException:文件未找到异常,属于 IO 异常的一种。当程序试图打开一个不存在的文件(如通过FileInputStream读取文件),且该操作未被正确捕获处理时抛出。ArrayIndexOutOfBoundsException:数组索引越界异常。当访问数组时使用了超出其有效范围的索引(如数组长度为 3,却访问索引3或-1)时抛出,因为数组索引从0开始,最大索引为 “长度 - 1”。SecurityException:安全异常。当程序尝试执行一个被安全管理器(SecurityManager)禁止的操作时抛出,例如访问受限资源、修改系统配置等,常见于有安全限制的环境(如 Applet)。
实例
如果年龄低于 18 岁,则抛出异常(打印 “拒绝访问”)。如果年龄为 18 岁或以上,则打印 “允许访问”:
public class Main {
static void checkAge(int age) {
if (age < 18) {
throw new ArithmeticException("拒绝访问 - 您需要至少满 18 岁。");
}
else {
System.out.println("允许访问 - 您的年纪够大!");
}
}
public static void main(String[] args) {
checkAge(15); // 将年龄设置为 15(低于 18 ...)
}
}
// 输出:
Exception in thread "main" java.lang.ArithmeticException: 拒绝访问 - 您需要至少满 18 岁。
at Main.checkAge(Main.java:4)
at Main.main(Main.java:12)
如果年龄是 20 岁,则不会出现异常:2. 正则表达式 - RegEx
正则表达式是形成搜索模式的字符序列。在文本中搜索数据时,您可以使用搜索模式来描述您要搜索的内容。
正则表达式可以是单个字符,也可以是更复杂的模式。
正则表达式可用于执行所有类型的文本搜索 和 文本替换操作。
Java 没有内置的正则表达式类,但我们可以导入 java.util.regex 包来处理正则表达式。该包提供以下类:
Pattern类 - 定义模式(用于搜索)Matcher类 - 用于搜索模式PatternSyntaxException类 - 指示正则表达式模式中的语法错误
实例
找出句子中是否出现 “joey” 一词:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
Pattern pattern = Pattern.compile("joey", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher("Visit joey!");
boolean matchFound = matcher.find();
if(matchFound) {
System.out.println("找到匹配");
} else {
System.out.println("未找到匹配");
}
}
}
// 输出:找到匹配解释:此例在句子中搜索单词 “joey”。
首先,使用 Pattern.compile() 方法创建模式。第一个参数规定要搜索的模式,第二个参数是一个标志,规定搜索应该不区分大小写。第二个参数是可选的。
matcher() 方法用于在字符串中搜索模式。它返回 Matcher 对象,其中包含有关已执行搜索的信息。
如果在字符串中找到模式,则 find() 方法返回 true,如果未找到,则返回 false。
标志
compile() 方法中的标志改变了搜索的执行方式。这是其中几个:
Pattern.CASE_INSENSITIVE- 执行搜索时将忽略字母的大小写。Pattern.LITERAL- 模式中的特殊字符没有任何特殊含义,在执行搜索时将被视为普通字符。Pattern.UNICODE_CASE- 将它与 CASE_INSENSITIVE 标志一起使用也可以忽略英文字母表之外的字母的大小写
正则表达式模式
Pattern.compile() 方法的第一个参数是模式。它描述了正在搜索的内容。
括号用于查找一系列字符:
元字符
元字符是拥有特殊含义的字符:
量词
量词定义数量:
注意: 如果您的表达式需要搜索特殊字符之一,可以使用反斜杠 ( \ ) 将其转义。在 Java 中,字符串中的反斜杠需要自己转义,因此需要两个反斜杠来转义特殊字符。例如,要搜索一个或多个问号,您可以使用以下表达式:“\?”
3. 线程
3.1 创建线程
创建线程有两种方法。
可通过扩展 Thread 类并覆盖其 run() 方法来创建:
扩展语法
public class Main extends Thread {
public void run() {
System.out.println("这段代码在一个线程中运行");
}
}另一种创建线程的方法是实现 Runnable 接口:
实现语法
public class Main implements Runnable {
public void run() {
System.out.println("这段代码在一个线程中运行");
}
}3.2 运行线程
如果类扩展了 Thread 类,则可以通过创建该类的实例并调用其 start() 方法来运行该线程:
扩展实例
public class Main extends Thread {
public static void main(String[] args) {
Main thread = new Main();
thread.start();
System.out.println("这段代码在线程之外");
}
public void run() {
System.out.println("这段代码在一个线程中运行");
}
}如果类实现了 Runnable 接口,则可以通过将类的实例传递给 Thread 对象的构造函数,然后调用线程的 start() 方法来运行线程:
实现实例
public class Main implements Runnable {
public static void main(String[] args) {
Main obj = new Main();
Thread thread = new Thread(obj);
thread.start();
System.out.println("这段代码在线程之外");
}
public void run() {
System.out.println("这段代码在一个线程中运行");
}
}“扩展”和“实现”线程之间的差异
主要区别在于,当类扩展 Thread 类时,您不能扩展任何其他类,但通过实现 Runnable 接口,也可以从另一个类扩展,例如:类
MyClass extends OtherClass implements Runnable。
3.3 并发问题
由于线程与程序的其他部分同时运行,因此无法获知代码将以何种顺序运行。当线程和主程序读取和写入相同的变量时,值是不可预测的。由此产生的问题称为并发问题。
在下面的例子中,变量 amount 是不可预测的:
public class Main extends Thread {
public static int amount = 0;
public static void main(String[] args) {
Main thread = new Main();
thread.start();
System.out.println(amount);
amount++;
System.out.println(amount);
}
public void run() {
amount++;
}
}为了避免并发问题,最好在线程之间共享尽可能少的属性。如果需要共享属性,一种可能的解决方案是使用线程的 isAlive() 方法在使用线程可以更改的任何属性之前检查线程是否已完成运行。
使用 isAlive() 来防止并发问题:
public class Main extends Thread {
public static int amount = 0;
public static void main(String[] args) {
Main thread = new Main();
thread.start();
// Wait for the thread to finish
while(thread.isAlive()) {
System.out.println("Waiting...");
}
// Update amount and print its value
System.out.println("Main: " + amount);
amount++;
System.out.println("Main: " + amount);
}
public void run() {
amount++;
}
}4. Lambda 表达式
Lambda 表达式是在 Java 8 中添加的。
lambda 表达式是一小段代码,它接受参数并返回值。 Lambda 表达式类似于方法,但不需要名称,并可直接在方法主体中实现。
语法
最简单的 lambda 表达式包含一个参数和一个表达式:
parameter -> expression如需使用多个参数,请将它们括在括号中:
(parameter1, parameter2) -> expression表达式(expression)是有限制的。它们必须立即返回值,且不能包含变量、赋值或诸如 if 或 for 之类的语句。
为了进行更复杂的操作,可以在花括号内使用代码块:
(parameter1, parameter2) -> { code block }如果 lambda 表达式需要返回值,那么代码块内需要有 return 语句。
示例:在 ArrayList 的 forEach() 方法中使用 Lamba 表达式来打印列表中的每个项目:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> numbers = new ArrayList<Integer>();
numbers.add(5);
numbers.add(9);
numbers.add(8);
numbers.add(1);
numbers.forEach( (n) -> { System.out.println(n); } );
}
}5. 高级排序(Comparator 和 Comparable)
在“列表排序”章节中,您学习了如何按字母顺序和数字顺序对列表进行排序,但如果列表中包含对象呢?
为了对对象进行排序,您需要指定一个规则来决定对象的排序方式。例如,如果您有一个汽车列表,你可能想按年份排序,规则可以是年份较早的汽车排在前面。
Comparator 和 Comparable 接口允许你指定用于排序对象的规则。
能够指定排序规则还允许您改变字符串和数字的排序方式。
5.1 Comparator(比较器)
实现了 Comparator 接口的对象被称为比较器。
Comparator 接口允许你创建一个包含 compare() 方法的类,该方法比较两个对象以决定哪个在列表中应排在前面。
compare() 方法应返回一个数字,该数字:
为负数时,表示第一个对象应在列表中排在前面。
为正数时,表示第二个对象应在列表中排在前面。
为零时,表示顺序无关紧要。
实现 Comparator 接口的类可能如下所示:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
// 定义一个 Car 类
class Car {
public String brand; // 品牌
public String model; // 型号
public int year; // 年份
// 构造函数
public Car(String b, String m, int y) {
brand = b;
model = m;
year = y;
}
}
// 创建一个比较器
class SortByYear implements Comparator {
// 实现 compare 方法
public int compare(Object obj1, Object obj2) {
// 确保传入的对象是 Car 类型
Car a = (Car) obj1;
Car b = (Car) obj2;
// 比较两辆车的年份
if (a.year < b.year) return -1; // 第一辆车年份更小
if (a.year > b.year) return 1; // 第一辆车年份更大
return 0; // 两辆车年份相同
}
}
public class Main {
public static void main(String[] args) {
// 创建一个汽车列表
ArrayList<Car> myCars = new ArrayList<Car>();
myCars.add(new Car("BMW", "X5", 1999));
myCars.add(new Car("Honda", "Accord", 2006));
myCars.add(new Car("Ford", "Mustang", 1970));
// 使用比较器对汽车进行排序
Comparator myComparator = new SortByYear();
Collections.sort(myCars, myComparator);
// 显示排序后的汽车
for (Car c : myCars) {
System.out.println(c.brand + " " + c.model + " " + c.year);
}
}
}使用 Lambda 表达式
为了简化代码,比较器可以被替换为具有与 compare() 方法相同参数和返回值的 Lambda 表达式:
Collections.sort(myCars, (obj1, obj2) -> {
Car a = (Car) obj1;
Car b = (Car) obj2;
if (a.year < b.year) return -1;
if (a.year > b.year) return 1;
return 0;
});5.2 Comparable 接口
Comparable 接口允许对象通过 compareTo() 方法指定其自身的排序规则。
compareTo() 方法接受一个对象作为参数,并将可比较对象与该参数进行比较,以决定哪个在列表中应排在前面。
与比较器类似,compareTo() 方法返回一个数字,该数字:
为负数时,表示可比较对象应在列表中排在前面。
为正数时,表示另一个对象应在列表中排在前面。
为零时,表示顺序无关紧要。
许多原生 Java 类(如
String和Integer)都实现了Comparable接口。这就是为什么字符串和数字不需要比较器就可以进行排序的原因。
示例:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
// 定义一个可比较的 Car 类
class Car implements Comparable<Car> {
public String brand; // 品牌
public String model; // 型号
public int year; // 年份
// 构造方法,用于初始化 Car 对象
public Car(String b, String m, int y) {
brand = b;
model = m;
year = y;
}
// 实现 compareTo 方法,决定此对象如何与其他 Car 对象进行比较
@Override
public int compareTo(Car other) {
if (year < other.year) return -1; // 如果此车的年份小于另一辆车的年份,则返回 -1,表示此车较小
if (year > other.year) return 1; // 如果此车的年份大于另一辆车的年份,则返回 1,表示此车较大
return 0; // 如果两车的年份相同,则返回 0,表示两车相等(在年份上)
}
}
public class Main {
public static void main(String[] args) {
// 创建一个汽车列表
ArrayList<Car> myCars = new ArrayList<Car>();
myCars.add(new Car("BMW", "X5", 1999));
myCars.add(new Car("Honda", "Accord", 2006));
myCars.add(new Car("Ford", "Mustang", 1970));
// 对汽车进行排序
Collections.sort(myCars);
// 显示汽车列表
for (Car c : myCars) {
System.out.println(c.brand + " " + c.model + " " + c.year);
}
}
}5.3 Comparator vs. Comparable
比较器(comparator)是一个具有一个方法的对象,用于比较两个不同的对象。
可比较对象(comparable)是一个可以与其他对象进行比较的对象。
在可能的情况下,使用 Comparable 接口更容易,但 Comparator 接口更强大,因为它允许你对任何类型的对象进行排序,即使你不能更改其代码。
八、文件处理
1. 文件
java.io 包中的File 类允许我们处理文件。
如需使用File 类,请创建该类的对象,并指定文件名或目录名。
示例:
import java.io.File; // 导入 File 类
File myObj = new File("filename.txt"); // 规定文件名File 类中有许多方法来创建文件并且获取有关文件的信息:
2. 创建/写入文件
2.1 创建文件
createNewFile() 方法。此方法返回一个布尔值:如果文件已成功创建,则为 true,如果文件已存在,则为 false。请注意,该方法包含在 try...catch 块中。这是很必要的,因为如果发生错误(如果由于某种原因无法创建文件),则会抛出 IOException:
import java.io.File; // 导入 File 类
import java.io.IOException; // 导入 IOException 类来处理错误
public class CreateFile {
public static void main(String[] args) {
try {
File myObj = new File("filename.txt"); // 指定文件路径
if (myObj.createNewFile()) {
System.out.println("文件已创建:" + myObj.getName());
} else {
System.out.println("文件已存在。");
}
} catch (IOException e) {
System.out.println("发生错误。");
e.printStackTrace();
}
}
}
// 输出将是:
// 文件已创建:filename.txt2.2 写入文件
使用 FileWriter 类及其 write() 方法将文本写入文件。请注意,当完成写入文件时,应使用 close() 方法关闭它:
import java.io.FileWriter; // 导入 FileWriter 类
import java.io.IOException; // 导入 IOException 类来处理错误
public class WriteToFile {
public static void main(String[] args) {
try {
FileWriter myWriter = new FileWriter("filename.txt");
myWriter.write("Java 中的文件可能很棘手,但它很有趣!");
myWriter.close();
System.out.println("成功写入文件。");
} catch (IOException e) {
System.out.println("发生错误。");
e.printStackTrace();
}
}
}
// 输出将是:
// 成功写入文件。3. 读取文件
3.1 读取文件内容
使用 Scanner 类来读取文本文件的内容:
import java.io.File; // 导入 File 类
import java.io.FileNotFoundException; // 导入这个类来处理错误
import java.util.Scanner; // 导入 Scanner 类以读取文本文件
public class ReadFile {
public static void main(String[] args) {
try {
File myObj = new File("filename.txt");
Scanner myReader = new Scanner(myObj);
while (myReader.hasNextLine()) {
String data = myReader.nextLine();
System.out.println(data);
}
myReader.close();
} catch (FileNotFoundException e) {
System.out.println("发生错误。");
e.printStackTrace();
}
}
}3.2 获取文件信息
如需获取有关文件的更多信息,使用任意 File 方法:
import java.io.File; // 导入 File 类
public class GetFileInfo {
public static void main(String[] args) {
File myObj = new File("filename.txt");
if (myObj.exists()) {
System.out.println("文件名称:" + myObj.getName());
System.out.println("绝对路径:" + myObj.getAbsolutePath());
System.out.println("是否可写:" + myObj.canWrite());
System.out.println("是否可读:" + myObj.canRead());
System.out.println("文件大小:" + myObj.length());
} else {
System.out.println("文件不存在。");
}
}
}4. 删除文件
在 Java 中删除文件,使用 delete() 方法:
import java.io.File; // 导入 File 类
public class DeleteFile {
public static void main(String[] args) {
File myObj = new File("filename.txt");
if (myObj.delete()) {
System.out.println("已删除文件:" + myObj.getName());
} else {
System.out.println("删除文件失败。");
}
}
}
// 输出将是:
// 已删除文件:filename.txt删除文件夹:(文件夹必须为空 )
import java.io.File;
public class DeleteFolder {
public static void main(String[] args) {
File myObj = new File("C:\\Users\\MyName\\Test");
if (myObj.delete()) {
System.out.println("已删除文件夹:" + myObj.getName());
} else {
System.out.println("删除文件夹失败。");
}
}
}
// 输出将是:
// 已删除文件夹:Test
- 感谢你赐予我前进的力量

