Java 基础知识文档
2025 年 2 月 12 日•内容由 AI 生成,不能完全保障真实
我将要面试,帮我生成一份总结java基础知识的markdown文档。要求涵盖所有的java基础知识点,并且要结构清晰,内容简洁。
Java 基础知识总结
一、Java 概述
1.1 Java 简介
Java 是由 Sun Microsystems 公司(2010 年被 Oracle 收购)于 1995 年推出的高级编程语言。它具有以下显著特点:
- 面向对象:Java 采用面向对象的编程范式,支持封装、继承和多态等特性,使得代码更具可维护性、可扩展性和可复用性。
- 跨平台:Java 程序通过编译器编译成字节码(.class 文件),字节码可以在不同操作系统上的 Java 虚拟机(JVM)中运行,实现了 “一次编写,到处运行”。
- 安全性:Java 提供了安全机制,如字节码验证、安全管理器等,能够有效防止恶意代码的攻击。
- 多线程:Java 内置了对多线程的支持,使得程序可以同时执行多个任务,提高了程序的并发性能。
- 自动内存管理:Java 采用垃圾回收机制(GC),自动管理内存的分配和回收,减少了程序员手动管理内存的负担。
1.2 Java 平台
- Java SE(Standard Edition):Java 标准版,是 Java 技术的基础,提供了核心的类库和开发工具,用于开发桌面和简单服务器应用。
- Java EE(Enterprise Edition):Java 企业版,在 Java SE 的基础上提供了一系列的企业级服务和 API,如 Servlet、JSP、EJB 等,用于开发大型企业级应用。
- Java ME(Micro Edition):Java 微型版,主要用于嵌入式系统和移动设备开发,提供了精简的类库和运行环境。
1.3 Java 跨平台原理
Java 程序的执行过程分为编译和运行两个阶段:
- 编译阶段:Java 源文件(.java)通过 Java 编译器(javac)编译成字节码文件(.class)。字节码是一种中间代码,不针对特定的操作系统和硬件平台。
- 运行阶段:字节码文件在 Java 虚拟机(JVM)中运行。JVM 是 Java 实现跨平台的关键,它负责加载字节码文件,并将字节码或编译成具体操作系统和硬件平台能够执行的机器码。不同的操作系统需要安装相应版本的 JVM,从而保证 Java 程序可以在不同的平台上运行。
二、数据类型
2.1 基本数据类型
Java 提供了 8 种基本数据类型,分为 4 类:整数类型、浮点类型、字符类型和布尔类型。
数据类型 | 位数 | 取值范围 | 默认值 | 示例 |
---|---|---|---|---|
byte | 8 | -128 ~ 127 | 0 | byte b = 10; |
short | 16 | -32768 ~ 32767 | 0 | short s = 100; |
int | 32 | -2147483648 ~ 2147483647 | 0 | int i = 1000; |
long | 64 | -2^63 ~ 2^63 - 1 | 0L | long l = 10000L; |
float | 32 | 单精度浮点数,有效位数约 7 位 | 0.0f | float f = 3.14f; |
double | 64 | 双精度浮点数,有效位数约 15 位 | 0.0d | double d = 3.14159; |
char | 16 | 0 ~ 65535 | '\u0000' | char c = 'A'; |
boolean | 1 | true 或 false | false | boolean flag = true; |
2.2 引用数据类型
引用数据类型是对对象的引用,而不是对象本身。常见的引用数据类型包括:
- 类(Class):类是对象的抽象,定义了对象的属性和方法。例如,
String
类是 Java 中用于处理字符串的类。
String str = "Hello, World!";
- 接口(Interface):接口是一种抽象类型,定义了一组方法的签名,但不包含方法的实现。类可以实现接口,从而实现接口中定义的方法。
interface Animal {void eat();
}class Dog implements Animal {@Overridepublic void eat() {System.out.println("Dog is eating.");}
}
- 数组(Array):数组是一种存储相同类型数据的容器,数组的长度在创建时确定,并且不能改变。
int[] arr = new int[5];
arr[0] = 1;
三、变量和常量
3.1 变量
变量是程序中存储数据的基本单元,使用前需要先声明和初始化。变量的声明格式为:数据类型 变量名;
,初始化格式为:变量名 = 值;
。也可以在声明变量的同时进行初始化。
// 声明变量
int num;
// 初始化变量
num = 10;// 声明并初始化变量
int age = 20;
3.2 常量
常量是在程序运行过程中值不能被改变的量,使用 final
关键字修饰。常量在声明时必须进行初始化,并且不能再被赋值。
final double PI = 3.14159;
// 以下代码会编译错误,因为常量不能再被赋值
// PI = 3.14;
3.3 变量的作用域
变量的作用域是指变量在程序中可以被访问的范围。Java 中变量的作用域分为以下几种:
- 类变量(静态变量):使用
static
关键字修饰,属于类,而不是类的实例。类变量在类加载时被初始化,在整个程序运行期间都存在。
class MyClass {static int classVar = 10;
}
- 实例变量:属于类的实例,每个实例都有自己的一份实例变量。实例变量在创建对象时被初始化。
class MyClass {int instanceVar = 20;
}
- 局部变量:定义在方法、构造方法或代码块中的变量,局部变量必须在使用前进行初始化,其作用域仅限于定义它的方法、构造方法或代码块。
public void method() {int localVar = 30;// 局部变量的作用域仅限于该方法
}
四、运算符
4.1 算术运算符
算术运算符用于执行基本的数学运算,包括加法(+
)、减法(-
)、乘法(*
)、除法(/
)、取模(%
)、自增(++
)和自减(--
)。
int a = 10;
int b = 3;
int sum = a + b; // 加法
int diff = a - b; // 减法
int prod = a * b; // 乘法
int quot = a / b; // 除法
int rem = a % b; // 取模a++; // 自增
b--; // 自减
4.2 赋值运算符
赋值运算符用于将一个值赋给变量,常见的赋值运算符包括 =
、+=
、-=
、*=
、/=
、%=
。
int x = 5;
x += 3; // 相当于 x = x + 3;
x -= 2; // 相当于 x = x - 2;
x *= 4; // 相当于 x = x * 4;
x /= 2; // 相当于 x = x / 2;
x %= 3; // 相当于 x = x % 3;
4.3 比较运算符
比较运算符用于比较两个值的大小关系,返回一个布尔值(true
或 false
)。常见的比较运算符包括 ==
(等于)、!=
(不等于)、>
(大于)、<
(小于)、>=
(大于等于)、<=
(小于等于)。
int m = 10;
int n = 20;
boolean result1 = m == n; // false
boolean result2 = m != n; // true
boolean result3 = m > n; // false
boolean result4 = m < n; // true
boolean result5 = m >= n; // false
boolean result6 = m <= n; // true
4.4 逻辑运算符
逻辑运算符用于对布尔值进行逻辑运算,常见的逻辑运算符包括 &&
(逻辑与)、||
(逻辑或)、!
(逻辑非)。
boolean p = true;
boolean q = false;
boolean andResult = p && q; // false
boolean orResult = p || q; // true
boolean notResult = !p; // false
4.5 位运算符
位运算符用于对整数类型的数据进行二进制位操作,常见的位运算符包括 &
(按位与)、|
(按位或)、^
(按位异或)、~
(按位取反)、<<
(左移)、>>
(右移)、>>>
(无符号右移)。
int num1 = 5; // 二进制: 0101
int num2 = 3; // 二进制: 0011
int andResult = num1 & num2; // 二进制: 0001,十进制: 1
int orResult = num1 | num2; // 二进制: 0111,十进制: 7
int xorResult = num1 ^ num2; // 二进制: 0110,十进制: 6
int notResult = ~num1; // 二进制: 1010,十进制: -6
int leftShift = num1 << 1; // 二进制: 1010,十进制: 10
int rightShift = num1 >> 1; // 二进制: 0010,十进制: 2
五、控制语句
5.1 条件语句
if - else 语句
if - else
语句用于根据条件的真假来执行不同的代码块。
int score = 80;
if (score >= 60) {System.out.println("及格");
} else {System.out.println("不及格");
}
if - else if - else 语句
当有多个条件需要判断时,可以使用 if - else if - else
语句。
int score = 80;
if (score >= 90) {System.out.println("优秀");
} else if (score >= 80) {System.out.println("良好");
} else if (score >= 60) {System.out.println("及格");
} else {System.out.println("不及格");
}
switch 语句
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("其他");
}
5.2 循环语句
for 循环
for
循环用于执行指定次数的循环。
for (int i = 0; i < 5; i++) {System.out.println(i);
}
while 循环
while
循环在条件为真时重复执行代码块。
int j = 0;
while (j < 5) {System.out.println(j);j++;
}
do - while 循环
do - while
循环先执行一次代码块,然后再判断条件是否为真,如果为真则继续执行循环。
int k = 0;
do {System.out.println(k);k++;
} while (k < 5);
5.3 跳转语句
break 语句
break
语句用于跳出当前所在的循环或 switch
语句。
for (int i = 0; i < 10; i++) {if (i == 5) {break;}System.out.println(i);
}
continue 语句
continue
语句用于跳过本次循环的剩余代码,直接进入下一次循环。
for (int i = 0; i < 10; i++) {if (i == 5) {continue;}System.out.println(i);
}
return 语句
return
语句用于从方法中返回值并结束方法的执行。
public int add(int a, int b) {return a + b;
}
六、面向对象编程
6.1 类和对象
类
类是对象的抽象,定义了对象的属性和方法。类的定义格式为:
class 类名 {// 成员变量(属性)数据类型 变量名;// 构造方法类名() {// 构造方法体}// 成员方法(行为)返回类型 方法名(参数列表) {// 方法体return 返回值;}
}
对象
对象是类的实例,通过 new
关键字创建对象。
class Person {String name;int age;void speak() {System.out.println("My name is " + name + ", I'm " + age + " years old.");}
}public class Main {public static void main(String[] args) {// 创建对象Person p = new Person();// 给对象的属性赋值p.name = "John";p.age = 20;// 调用对象的方法p.speak();}
}
6.2 封装
封装是将对象的属性和方法隐藏起来,只对外提供公共的访问方式,提高了代码的安全性和可维护性。在 Java 中,可以使用访问修饰符来实现封装。
访问修饰符 | 本类 | 同一个包中的类 | 不同包中的子类 | 不同包中的非子类 |
---|---|---|---|---|
private | 可以访问 | 不可以访问 | 不可以访问 | 不可以访问 |
default | 可以访问 | 可以访问 | 不可以访问 | 不可以访问 |
protected | 可以访问 | 可以访问 | 可以访问 | 不可以访问 |
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) {this.age = age;}}
}
6.3 继承
继承是指一个类可以继承另一个类的属性和方法,提高了代码的复用性。被继承的类称为父类(基类),继承的类称为子类(派生类)。Java 中使用 extends
关键字实现继承。
class Animal {void eat() {System.out.println("Animal is eating.");}
}class Dog extends Animal {void bark() {System.out.println("Dog is barking.");}
}public class Main {public static void main(String[] args) {Dog dog = new Dog();dog.eat(); // 调用父类的方法dog.bark(); // 调用子类的方法}
}
6.4 多态
多态是指同一个方法可以根据对象的不同类型表现出不同的行为,包括方法重载和方法重写。
方法重载
方法重载是指在同一个类中,方法名相同但参数列表不同的多个方法。方法重载的判断依据是方法的参数类型、参数个数或参数顺序不同。
class Calculator {int add(int a, int b) {return a + b;}int add(int a, int b, int c) {return a + b + c;}double add(double a, double b) {return a + b;}
}
方法重写
方法重写是指在子类中重写父类的方法,方法名、参数
继续生成未生成的内容
列表和返回值类型都必须与父类方法相同,并且可以使用@Override
注解来确保重写的正确性。方法重写体现了运行时多态。
class Animal {void sound() {System.out.println("Animal makes a sound.");}
}class Cat extends Animal {@Overridevoid sound() {System.out.println("Cat meows.");}
}class Dog extends Animal {@Overridevoid sound() {System.out.println("Dog barks.");}
}public class Main {public static void main(String[] args) {Animal cat = new Cat();Animal dog = new Dog();cat.sound(); // 输出 "Cat meows."dog.sound(); // 输出 "Dog barks."}
}
6.5 抽象类和接口
抽象类
抽象类是使用abstract
关键字修饰的类,抽象类不能被实例化,主要用于作为其他类的基类。抽象类中可以包含抽象方法和具体方法。抽象方法是使用abstract
关键字修饰的方法,只有方法声明,没有方法体,子类必须实现抽象类中的所有抽象方法。
abstract class Shape {abstract double area(); // 抽象方法void printInfo() {System.out.println("This is a shape.");}
}class Circle extends Shape {private double radius;public Circle(double radius) {this.radius = radius;}@Overridedouble area() {return Math.PI * radius * radius;}
}
接口
接口是一种特殊的抽象类型,使用interface
关键字定义。接口中只能包含抽象方法和常量(默认使用public static final
修饰)。类通过implements
关键字实现接口,一个类可以实现多个接口。
interface Flyable {void fly();
}interface Swimmable {void swim();
}class Duck implements Flyable, Swimmable {@Overridepublic void fly() {System.out.println("Duck is flying.");}@Overridepublic void swim() {System.out.println("Duck is swimming.");}
}
6.6 内部类
内部类是定义在另一个类内部的类,根据定义位置和修饰符的不同,内部类可以分为成员内部类、局部内部类、静态内部类和匿名内部类。
成员内部类
成员内部类是定义在类的成员位置的类,它可以访问外部类的所有成员。
class Outer {private int outerField = 10;class Inner {void printOuterField() {System.out.println(outerField);}}
}public class Main {public static void main(String[] args) {Outer outer = new Outer();Outer.Inner inner = outer.new Inner();inner.printOuterField();}
}
局部内部类
局部内部类是定义在方法或代码块内部的类,它只能在定义它的方法或代码块内部使用。
class Outer {void outerMethod() {class LocalInner {void printMessage() {System.out.println("This is a local inner class.");}}LocalInner localInner = new LocalInner();localInner.printMessage();}
}
静态内部类
静态内部类是使用static
关键字修饰的内部类,它只能访问外部类的静态成员。
class Outer {private static int outerStaticField = 20;static class StaticInner {void printOuterStaticField() {System.out.println(outerStaticField);}}
}public class Main {public static void main(String[] args) {Outer.StaticInner staticInner = new Outer.StaticInner();staticInner.printOuterStaticField();}
}
匿名内部类
匿名内部类是一种没有显式类名的内部类,通常用于创建一次性的对象。
interface MyInterface {void doSomething();
}public class Main {public static void main(String[] args) {MyInterface obj = new MyInterface() {@Overridepublic void doSomething() {System.out.println("Doing something...");}};obj.doSomething();}
}
七、异常处理
7.1 异常概述
异常是指程序在运行过程中出现的错误或意外情况,Java 提供了异常处理机制来捕获和处理这些异常,保证程序的健壮性。异常类都继承自Throwable
类,Throwable
类有两个子类:Error
和Exception
。
- Error:表示系统级的错误,通常是由 JVM 或硬件问题引起的,程序无法处理,如
OutOfMemoryError
、StackOverflowError
等。 - Exception:表示程序可以处理的异常,又分为受检查异常(Checked Exception)和运行时异常(Runtime Exception)。
7.2 异常分类
受检查异常(Checked Exception)
受检查异常是指在编译时必须进行捕获或声明抛出的异常,如IOException
、SQLException
等。如果不处理受检查异常,程序将无法通过编译。
运行时异常(Runtime Exception)
运行时异常是指在编译时不需要进行捕获或声明抛出的异常,通常是由程序逻辑错误引起的,如NullPointerException
、ArrayIndexOutOfBoundsException
等。
7.3 异常处理语句
try - catch 语句
try - catch
语句用于捕获和处理异常。try
块中包含可能会抛出异常的代码,catch
块用于捕获并处理相应类型的异常。
try {int[] arr = new int[5];System.out.println(arr[10]); // 可能会抛出 ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {System.out.println("数组越界异常: " + e.getMessage());
}
try - catch - finally 语句
finally
块中的代码无论是否发生异常都会执行,通常用于释放资源,如关闭文件、数据库连接等。
try {int[] arr = new int[5];System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {System.out.println("数组越界异常: " + e.getMessage());
} finally {System.out.println("无论是否发生异常,finally 块都会执行。");
}
throws 关键字
throws
关键字用于声明方法可能会抛出的异常,调用该方法的代码必须处理这些异常。
public void readFile() throws java.io.IOException {java.io.FileReader fr = new java.io.FileReader("test.txt");// 读取文件的代码fr.close();
}
throw 关键字
throw
关键字用于手动抛出异常,通常在方法内部使用。
public void checkAge(int age) {if (age < 0) {throw new IllegalArgumentException("年龄不能为负数。");}
}
7.4 自定义异常
在 Java 中,我们可以通过继承Exception
或RuntimeException
类来创建自定义异常。
class MyException extends Exception {public MyException(String message) {super(message);}
}public class Main {public static void main(String[] args) {try {throw new MyException("这是一个自定义异常。");} catch (MyException e) {System.out.println(e.getMessage());}}
}
八、数组
8.1 数组定义
数组是一种存储相同类型数据的容器,数组的长度在创建时确定,并且不能改变。数组的定义方式有以下几种:
// 声明数组
int[] arr1;
// 创建数组
arr1 = new int[5];// 声明并创建数组
int[] arr2 = new int[5];// 声明、创建并初始化数组
int[] arr3 = {1, 2, 3, 4, 5};
8.2 数组访问
通过下标访问数组元素,下标从 0 开始,最大下标为数组长度减 1。
int[] arr = {1, 2, 3, 4, 5};
// 访问数组元素
int num = arr[2]; // 访问下标为 2 的元素,值为 3
// 修改数组元素
arr[3] = 10;
8.3 多维数组
多维数组是数组的数组,常见的有二维数组。
// 声明并创建二维数组
int[][] matrix = new int[3][4];// 声明、创建并初始化二维数组
int[][] matrix2 = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}
};// 访问二维数组元素
int element = matrix2[1][2]; // 访问第 2 行第 3 列的元素,值为 7
8.4 数组常用操作
遍历数组
int[] arr = {1, 2, 3, 4, 5};
// 使用 for 循环遍历数组
for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);
}// 使用增强 for 循环遍历数组
for (int num : arr) {System.out.println(num);
}
数组排序
import java.util.Arrays;int[] arr = {5, 3, 1, 4, 2};
// 使用 Arrays 类的 sort 方法对数组进行排序
Arrays.sort(arr);
for (int num : arr) {System.out.println(num);
}
九、集合框架
9.1 集合概述
集合是 Java 中用于存储和操作一组对象的容器,与数组相比,集合的长度可以动态变化。Java 集合框架主要分为Collection
和Map
两大接口。
9.2 Collection 接口
Collection
接口是所有集合类的根接口,它有两个重要的子接口:List
和Set
。
List 接口
List
接口表示有序、可重复的集合,常见的实现类有ArrayList
和LinkedList
。
import java.util.ArrayList;
import java.util.List;// 创建 ArrayList 对象
List<String> list = new ArrayList<>();
// 添加元素
list.add("apple");
list.add("banana");
// 访问元素
String element = list.get(0);
// 遍历列表
for (String item : list) {System.out.println(item);
}
Set 接口
Set
接口表示无序、不可重复的集合,常见的实现类有HashSet
和TreeSet
。
import java.util.HashSet;
import java.util.Set;// 创建 HashSet 对象
Set<String> set = new HashSet<>();
// 添加元素
set.add("apple");
set.add("banana");
// 遍历集合
for (String item : set) {System.out.println(item);
}
9.3 Map 接口
Map
接口用于存储键值对,键不可重复,常见的实现类有HashMap
和TreeMap
。
import java.util.HashMap;
import java.util.Map;// 创建 HashMap 对象
Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("one", 1);
map.put("two", 2);
// 获取值
int value = map.get("one");
// 遍历 Map
for (Map.Entry<String, Integer> entry : map.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());
}
9.4 集合的常用方法
- 添加元素:
add()
、put()
- 删除元素:
remove()
- 判断元素是否存在:
contains()
- 获取集合大小:
size()
- 清空集合:
clear()
十、输入输出流
10.1 流的分类
- 按方向分:输入流和输出流。输入流用于从数据源读取数据,输出流用于向目的地写入数据。
- 按处理数据单位分:字节流和字符流。字节流以字节为单位处理数据,字符流以字符为单位处理数据。
10.2 字节流
字节流的抽象基类是InputStream
和OutputStream
。常见的字节流类有FileInputStream
、FileOutputStream
等。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;public class ByteStreamExample {public static void main(String[] args) {try (FileInputStream fis = new FileInputStream("input.txt");FileOutputStream fos = new FileOutputStream("output.txt")) {int c;while ((c = fis.read()) != -1) {fos.write(c);}} catch (IOException e) {e.printStackTrace();}}
}
10.3 字符流
字符流的抽象基类是Reader
和Writer
。常见的字符流类有FileReader
、FileWriter
等。
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;public class CharacterStreamExample {public static void main(String[] args) {try (FileReader fr = new FileReader("input.txt");FileWriter fw = new FileWriter("output.txt")) {int c;while ((c = fr.read()) != -1) {fw.write(c);}} catch (IOException e) {e.printStackTrace();}}
}
10.4 缓冲流
缓冲流是对字节流和字符流的包装,提供了缓冲功能,提高了读写效率。常见的缓冲流类有BufferedInputStream
、BufferedOutputStream
、BufferedReader
、BufferedWriter
等。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;public class BufferedStreamExample {public static void main(String[] args) {try (BufferedReader br = new BufferedReader(new FileReader("input.txt"));BufferedWriter bw = new BufferedWriter(new FileWriter("output.txt"))) {String line;while ((line = br.readLine()) != null) {bw.write(line);bw.newLine();}} catch (IOException e) {e.printStackTrace();}}
}
10.5 对象序列化和反序列化
对象序列化是指将对象转换为字节序列的过程,反序列化是指将字节序列转换为对象的过程。要实现对象序列化,类必须实现Serializable
接口。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;class Person implements Serializable {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}
}public class SerializationExample {public static void main(String[] args) {// 序列化try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {Person person = new Person("John", 20);oos.writeObject(person);} catch (IOException e) {e.printStackTrace();}// 反序列化try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {Person person = (Person) ois.readObject();System.out.println("Name: " + person.getName() + ", Age: " + person.getAge());} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}
}
十一、多线程
11.1 线程概述
线程是程序执行的最小单位,一个进程可以包含多个线程。多线程可以提高程序的并发性能,使得程序可以同时执行多个任务。
11.2 创建线程的方式
继承 Thread 类
class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + ": " + i);}}
}public class Main {public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
}
实现 Runnable 接口
class MyRunnable implements Runnable {@Overridepublic void run() {for
继续生成未生成的内容
11.2 创建线程的方式(续)
实现 Callable 接口
Callable
接口与 Runnable
接口类似,但 Callable
的 call()
方法可以有返回值,并且可以抛出异常。通常需要结合 FutureTask
类来获取返回值。
import java.util.concurrent.*;class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {int sum = 0;for (int i = 1; i <= 10; i++) {sum += i;}return sum;}
}public class CallableExample {public static void main(String[] args) throws ExecutionException, InterruptedException {MyCallable callable = new MyCallable();FutureTask<Integer> futureTask = new FutureTask<>(callable);Thread thread = new Thread(futureTask);thread.start();// 获取线程执行结果Integer result = futureTask.get();System.out.println("线程执行结果: " + result);}
}
11.3 线程的生命周期
线程的生命周期包含以下几个状态:
- 新建(New):当创建一个
Thread
对象时,线程处于新建状态。
Thread thread = new Thread(() -> System.out.println("Hello"));
- 就绪(Runnable):调用
start()
方法后,线程进入就绪状态,等待 CPU 调度执行。
thread.start();
- 运行(Running):当 CPU 调度该线程时,线程进入运行状态,执行
run()
方法中的代码。 - 阻塞(Blocked):线程在某些情况下会进入阻塞状态,如等待 I/O 操作、获取锁失败等。当阻塞条件解除后,线程会重新进入就绪状态。
- 等待(Waiting):线程调用
wait()
、join()
或LockSupport.park()
方法后会进入等待状态,需要其他线程进行相应的唤醒操作。 - 计时等待(Timed Waiting):线程调用
sleep(long millis)
、wait(long timeout)
、join(long millis)
等带有时间参数的方法后会进入计时等待状态,当时间到期或被其他线程唤醒时,线程会重新进入就绪状态。 - 终止(Terminated):线程的
run()
方法执行完毕或因异常退出时,线程进入终止状态。
11.4 线程同步
多个线程同时访问共享资源时可能会出现数据不一致的问题,需要进行线程同步来保证数据的一致性和完整性。
synchronized 关键字
- 同步方法:使用
synchronized
修饰方法,同一时间只有一个线程可以访问该方法。
class Counter {private int count = 0;public synchronized void increment() {count++;}public synchronized int getCount() {return count;}
}
- 同步代码块:使用
synchronized
关键字指定同步的对象,同一时间只有一个线程可以访问该同步代码块。
class Counter {private int count = 0;private final Object lock = new Object();public void increment() {synchronized (lock) {count++;}}public int getCount() {synchronized (lock) {return count;}}
}
Lock 接口
Lock
接口提供了比 synchronized
更灵活的锁机制,常见的实现类有 ReentrantLock
。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;class Counter {private int count = 0;private final Lock lock = new ReentrantLock();public void increment() {lock.lock();try {count++;} finally {lock.unlock();}}public int getCount() {lock.lock();try {return count;} finally {lock.unlock();}}
}
11.5 线程通信
线程通信是指多个线程之间通过某种机制进行信息交换和协调工作,常见的方法有 wait()
、notify()
和 notifyAll()
。
class Message {private String content;private boolean available = false;public synchronized String read() {while (!available) {try {wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();}}available = false;notifyAll();return content;}public synchronized void write(String content) {while (available) {try {wait();} catch (InterruptedException e) {Thread.currentThread().interrupt();}}this.content = content;available = true;notifyAll();}
}public class ThreadCommunicationExample {public static void main(String[] args) {Message message = new Message();new Thread(() -> {message.write("Hello, World!");}).start();new Thread(() -> {System.out.println(message.read());}).start();}
}
十二、反射
12.1 反射概述
反射是指在运行时动态获取类的信息并操作类的属性和方法的机制。通过反射,我们可以在运行时创建对象、调用方法、访问属性等,提高了程序的灵活性和可扩展性。
12.2 反射的基本操作
获取 Class 对象
- 通过类名的
class
属性
Class<?> clazz1 = String.class;
- 通过对象的
getClass()
方法
String str = "Hello";
Class<?> clazz2 = str.getClass();
- 通过
Class.forName()
方法
try {Class<?> clazz3 = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {e.printStackTrace();
}
创建对象
try {Class<?> clazz = Class.forName("java.util.ArrayList");Object obj = clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {e.printStackTrace();
}
调用方法
import java.lang.reflect.Method;class MyClass {public void sayHello() {System.out.println("Hello!");}
}public class ReflectionMethodExample {public static void main(String[] args) throws Exception {Class<?> clazz = MyClass.class;Object obj = clazz.getDeclaredConstructor().newInstance();Method method = clazz.getMethod("sayHello");method.invoke(obj);}
}
访问属性
import java.lang.reflect.Field;class MyClass {private String name = "John";
}public class ReflectionFieldExample {public static void main(String[] args) throws Exception {Class<?> clazz = MyClass.class;Object obj = clazz.getDeclaredConstructor().newInstance();Field field = clazz.getDeclaredField("name");field.setAccessible(true);String value = (String) field.get(obj);System.out.println(value);}
}
12.3 反射的优缺点
优点
- 灵活性高:可以在运行时动态地创建对象、调用方法和访问属性,提高了程序的灵活性。
- 可扩展性强:可以通过反射实现插件化开发,方便地扩展程序的功能。
缺点
- 性能开销大:反射涉及到动态解析和调用,会比直接调用方法和访问属性的性能低。
- 安全性问题:反射可以访问和修改类的私有成员,可能会破坏类的封装性和安全性。
十三、注解
13.1 注解概述
注解(Annotation)是 Java 5 引入的一种元数据机制,它可以为程序元素(类、方法、字段等)添加额外的信息,这些信息可以在编译时、运行时被读取和处理。
13.2 内置注解
Java 提供了一些内置注解,常见的有:
@Override
:用于标记方法是重写父类的方法,如果不符合重写规则,编译器会报错。
class Parent {public void print() {System.out.println("Parent");}
}class Child extends Parent {@Overridepublic void print() {System.out.println("Child");}
}
@Deprecated
:用于标记某个元素(类、方法等)已经过时,不建议使用。
@Deprecated
public void oldMethod() {// 旧方法的实现
}
@SuppressWarnings
:用于抑制编译器的警告信息。
@SuppressWarnings("unchecked")
List list = new ArrayList();
13.3 自定义注解
自定义注解使用 @interface
关键字定义,注解中可以定义成员变量。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface MyAnnotation {String value() default "";
}// 使用注解
class MyClass {@MyAnnotation("Hello")public void myMethod() {// 方法实现}
}
13.4 注解处理器
注解处理器可以在编译时或运行时读取和处理注解信息。以下是一个简单的运行时注解处理器示例:
import java.lang.reflect.Method;public class AnnotationProcessor {public static void processAnnotations(Object obj) throws Exception {Class<?> clazz = obj.getClass();Method[] methods = clazz.getMethods();for (Method method : methods) {if (method.isAnnotationPresent(MyAnnotation.class)) {MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);System.out.println("Annotation value: " + annotation.value());method.invoke(obj);}}}public static void main(String[] args) throws Exception {MyClass myClass = new MyClass();processAnnotations(myClass);}
}
十四、泛型
14.1 泛型概述
泛型是 Java 5 引入的一种类型参数化机制,它允许在定义类、接口和方法时使用类型参数,使得代码可以处理不同类型的数据,提高了代码的复用性和类型安全性。
14.2 泛型类
class Box<T> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}public class GenericClassExample {public static void main(String[] args) {Box<String> stringBox = new Box<>();stringBox.setContent("Hello");String str = stringBox.getContent();System.out.println(str);}
}
14.3 泛型接口
interface Generator<T> {T generate();
}class IntegerGenerator implements Generator<Integer> {@Overridepublic Integer generate() {return (int) (Math.random() * 100);}
}public class GenericInterfaceExample {public static void main(String[] args) {Generator<Integer> generator = new IntegerGenerator();Integer num = generator.generate();System.out.println(num);}
}
14.4 泛型方法
class GenericMethods {public <T> void printArray(T[] array) {for (T element : array) {System.out.print(element + " ");}System.out.println();}
}public class GenericMethodExample {public static void main(String[] args) {GenericMethods gm = new GenericMethods();Integer[] intArray = {1, 2, 3};String[] strArray = {"Hello", "World"};gm.printArray(intArray);gm.printArray(strArray);}
}
14.5 泛型的通配符
? extends T
:表示上界通配符,即泛型类型必须是T
或T
的子类。? super T
:表示下界通配符,即泛型类型必须是T
或T
的父类。
import java.util.ArrayList;
import java.util.List;class Animal {}
class Dog extends Animal {}public class WildcardExample {public static void printAnimals(List<? extends Animal> animals) {for (Animal animal : animals) {System.out.println(animal);}}public static void addDog(List<? super Dog> dogs) {dogs.add(new Dog());}public static void main(String[] args) {List<Dog> dogList = new ArrayList<>();printAnimals(dogList);addDog(dogList);}
}
继续生成未生成的内容
十五、枚举类型
15.1 枚举概述
枚举类型(enum
)是 Java 5 引入的一种特殊类,用于定义一组固定的常量。枚举类型可以使代码更具可读性和可维护性,同时避免了使用普通常量可能带来的错误。
15.2 枚举的基本定义和使用
// 定义一个表示星期的枚举类型
enum Weekday {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}public class EnumExample {public static void main(String[] args) {// 使用枚举常量Weekday today = Weekday.MONDAY;System.out.println("Today is " + today);// 遍历枚举常量for (Weekday day : Weekday.values()) {System.out.println(day);}}
}
15.3 枚举的属性和方法
枚举类型可以有自己的属性和方法,类似于普通类。
enum Color {RED(255, 0, 0), GREEN(0, 255, 0), BLUE(0, 0, 255);private int red;private int green;private int blue;// 构造方法Color(int red, int green, int blue) {this.red = red;this.green = green;this.blue = blue;}// 获取 RGB 值的方法public String getRGB() {return "RGB: (" + red + ", " + green + ", " + blue + ")";}
}public class EnumWithPropertiesExample {public static void main(String[] args) {Color color = Color.RED;System.out.println(color.getRGB());}
}
15.4 枚举的 switch
语句
枚举类型非常适合在 switch
语句中使用,能使代码更加清晰。
enum Season {SPRING, SUMMER, AUTUMN, WINTER
}public class EnumSwitchExample {public static void main(String[] args) {Season currentSeason = Season.SPRING;switch (currentSeason) {case SPRING:System.out.println("It's spring, flowers are blooming.");break;case SUMMER:System.out.println("It's summer, it's very hot.");break;case AUTUMN:System.out.println("It's autumn, leaves are falling.");break;case WINTER:System.out.println("It's winter, it's cold outside.");break;}}
}
十六、字符串处理
16.1 String
类
String
类是 Java 中用于处理字符串的常用类,它是不可变的,即一旦创建,其值不能被改变。
// 创建字符串对象
String str1 = "Hello";
String str2 = new String("World");// 字符串拼接
String str3 = str1 + " " + str2;
System.out.println(str3);// 获取字符串长度
int length = str3.length();
System.out.println("Length: " + length);// 字符串比较
boolean isEqual = str1.equals("Hello");
System.out.println("Is equal: " + isEqual);// 字符串查找
int index = str3.indexOf("World");
System.out.println("Index of 'World': " + index);
16.2 StringBuilder
和 StringBuffer
由于 String
类是不可变的,频繁拼接字符串会产生大量的临时对象,影响性能。StringBuilder
和 StringBuffer
是可变的字符串序列,用于高效地拼接字符串。
StringBuilder
StringBuilder
是非线程安全的,性能较高,适用于单线程环境。
StringBuilder sb = new StringBuilder();
sb.append("Hello");
sb.append(" ");
sb.append("World");
String result = sb.toString();
System.out.println(result);
StringBuffer
StringBuffer
是线程安全的,性能相对较低,适用于多线程环境。
StringBuffer sbf = new StringBuffer();
sbf.append("Hello");
sbf.append(" ");
sbf.append("World");
String result2 = sbf.toString();
System.out.println(result2);
16.3 字符串格式化
Java 提供了 String.format()
方法和 Formatter
类用于字符串格式化。
// 使用 String.format() 方法
String name = "John";
int age = 20;
String formatted = String.format("My name is %s and I'm %d years old.", name, age);
System.out.println(formatted);// 使用 Formatter 类
import java.util.Formatter;
Formatter formatter = new Formatter();
formatter.format("The price is %.2f dollars.", 9.99);
System.out.println(formatter.toString());
formatter.close();
16.4 字符串分割和替换
// 字符串分割
String str = "apple,banana,orange";
String[] fruits = str.split(",");
for (String fruit : fruits) {System.out.println(fruit);
}// 字符串替换
String replaced = str.replace("apple", "grape");
System.out.println(replaced);
十七、日期和时间处理
17.1 旧的日期和时间 API(Java 8 之前)
Date
类
Date
类用于表示特定的瞬间,精确到毫秒。
import java.util.Date;Date now = new Date();
System.out.println("Current date: " + now);
SimpleDateFormat
类
SimpleDateFormat
类用于格式化和解析日期字符串。
import java.text.SimpleDateFormat;
import java.util.Date;Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = sdf.format(date);
System.out.println("Formatted date: " + formattedDate);try {Date parsedDate = sdf.parse("2023-10-01 12:00:00");System.out.println("Parsed date: " + parsedDate);
} catch (Exception e) {e.printStackTrace();
}
17.2 新的日期和时间 API(Java 8 及以后)
Java 8 引入了新的日期和时间 API,位于 java.time
包下,提供了更丰富、更易用的日期和时间处理功能。
LocalDate
、LocalTime
和 LocalDateTime
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;// 获取当前日期
LocalDate currentDate = LocalDate.now();
System.out.println("Current date: " + currentDate);// 获取当前时间
LocalTime currentTime = LocalTime.now();
System.out.println("Current time: " + currentTime);// 获取当前日期和时间
LocalDateTime currentDateTime = LocalDateTime.now();
System.out.println("Current date and time: " + currentDateTime);
DateTimeFormatter
DateTimeFormatter
类用于格式化和解析日期时间对象。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = dateTime.format(formatter);
System.out.println("Formatted date and time: " + formatted);LocalDateTime parsedDateTime = LocalDateTime.parse("2023-10-01 12:00:00", formatter);
System.out.println("Parsed date and time: " + parsedDateTime);
Duration
和 Period
Duration
用于表示两个时间点之间的时长,Period
用于表示两个日期之间的时间段。
import java.time.Duration;
import java.time.LocalTime;
import java.time.Period;
import java.time.LocalDate;// 使用 Duration
LocalTime start = LocalTime.of(10, 0);
LocalTime end = LocalTime.of(12, 30);
Duration duration = Duration.between(start, end);
System.out.println("Duration: " + duration.toMinutes() + " minutes");// 使用 Period
LocalDate startDate = LocalDate.of(2023, 1, 1);
LocalDate endDate = LocalDate.of(2023, 12, 31);
Period period = Period.between(startDate, endDate);
System.out.println("Period: " + period.getMonths() + " months and " + period.getDays() + " days");
十八、正则表达式
18.1 正则表达式概述
正则表达式是一种用于描述字符串模式的工具,通过特定的字符和语法规则,可以方便地进行字符串的匹配、查找、替换等操作。
18.2 正则表达式的基本语法
- 字符类:
[abc]
表示匹配a
、b
或c
中的任意一个字符;[^abc]
表示匹配除a
、b
、c
之外的任意一个字符。 - 预定义字符类:
.
表示匹配任意一个字符;\d
表示匹配一个数字字符,等价于[0-9]
;\w
表示匹配一个单词字符,等价于[a-zA-Z_0-9]
。 - 数量词:
*
表示匹配前面的元素零次或多次;+
表示匹配前面的元素一次或多次;?
表示匹配前面的元素零次或一次。
18.3 Java 中使用正则表达式
import java.util.regex.Matcher;
import java.util.regex.Pattern;// 定义正则表达式
String regex = "\\d+";
// 编译正则表达式
Pattern pattern = Pattern.compile(regex);
// 创建 Matcher 对象
Matcher matcher = pattern.matcher("There are 123 apples.");// 查找匹配的字符串
while (matcher.find()) {System.out.println("Found: " + matcher.group());
}// 替换匹配的字符串
String replaced = pattern.matcher("There are 123 apples.").replaceAll("XXX");
System.out.println("Replaced: " + replaced);
十九、文件和目录操作
19.1 File
类
File
类用于表示文件和目录的抽象路径名,可以进行文件和目录的创建、删除、重命名等操作。
import java.io.File;// 创建 File 对象
File file = new File("test.txt");// 判断文件是否存在
if (file.exists()) {System.out.println("File exists.");
} else {try {// 创建新文件boolean created = file.createNewFile();if (created) {System.out.println("File created.");}} catch (Exception e) {e.printStackTrace();}
}// 删除文件
boolean deleted = file.delete();
if (deleted) {System.out.println("File deleted.");
}// 操作目录
File dir = new File("mydir");
if (!dir.exists()) {// 创建目录boolean dirCreated = dir.mkdir();if (dirCreated) {System.out.println("Directory created.");}
}// 列出目录下的文件和子目录
File[] files = dir.listFiles();
if (files != null) {for (File f : files) {System.out.println(f.getName());}
}
19.2 Path
和 Paths
类(Java 7 及以后)
Java 7 引入了 java.nio.file
包,提供了更强大的文件和目录操作功能,Path
和 Paths
是其中的重要类。
import java.nio.file.Path;
import java.nio.file.Paths;// 创建 Path 对象
Path path = Paths.get("test.txt");
System.out.println("Path: " + path);// 获取文件名
String fileName = path.getFileName().toString();
System.out.println("File name: " + fileName);// 获取父目录
Path parent = path.getParent();
if (parent != null) {System.out.println("Parent directory: " + parent);
}
19.3 文件复制和移动
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;public class FileCopyMoveExample {public static void main(String[] args) {Path source = Paths.get("source.txt");Path destination = Paths.get("destination.txt");try {// 复制文件Files.copy(source, destination);System.out.println("File copied.");// 移动文件Files.move(destination, Paths.get("newdestination.txt"));System.out.println("File moved.");} catch (IOException e) {e.printStackTrace();}}
}
以上涵盖了 Java 基础知识的主要方面,在实际开发中,这些知识是进一步学习和应用 Java 高级特性的基础。
还有吗,有的话继续列出来,只要java基础知识。