11. Java中的 throw 和 throws 有什么区别?
在Java中,throw
和 throws
都与异常处理相关,但它们的用途和行为有显著区别。
11.1 throw
关键字
-
作用:
-
用于在代码中显式抛出一个异常。
-
通常用于在满足某些条件时主动抛出异常。
-
-
语法:
throw 异常对象;
-
示例:
public class Main {public static void main(String[] args) {int age = -5;if (age < 0) {throw new IllegalArgumentException("年龄不能为负数"); // 抛出异常}} }
-
特点:
-
throw
用于方法内部。 -
抛出的异常必须是
Throwable
或其子类的实例。 -
抛出异常后,程序会立即停止当前方法的执行,并将异常传递给调用者。
-
11.2 throws
关键字
-
作用:
-
用于方法签名中,声明该方法可能抛出的异常类型。
-
调用该方法时,必须处理这些异常(使用
try-catch
或继续向上抛出)。
-
-
语法:
返回类型 方法名(参数列表) throws 异常类型1, 异常类型2, ... {// 方法体 }
-
示例:
public class Main {public static void main(String[] args) {try {readFile("file.txt");} catch (IOException e) {System.out.println("捕获异常: " + e.getMessage());}}static void readFile(String fileName) throws IOException {if (!fileName.equals("file.txt")) {throw new IOException("文件未找到"); // 抛出异常}} }
-
特点:
-
throws
用于方法签名中。 -
可以声明多个异常类型,用逗号分隔。
-
调用者必须处理这些异常,否则程序会编译失败。
-
11.3 throw
和 throws
的区别
特性 | throw | throws |
用途 | 显式抛出一个异常 | 声明方法可能抛出的异常类型 |
位置 | 方法内部 | 方法签名中 |
异常对象 | 必须是一个具体的异常对象 | 只需要指定异常类型 |
调用者处理 | 不需要在方法签名中声明 | 调用者必须处理或继续抛出 |
示例 | throw new Exception("错误"); | void method() throws Exception; |
11.4 使用场景
(1)
throw
的使用场景
当方法内部检测到某些条件不满足时,主动抛出异常。
例如,参数校验、业务逻辑检查等。
(2)
throws
的使用场景
当方法内部可能抛出受检异常(checked exception),但不想在方法内部处理时,使用
throws
将异常传递给调用者。例如,文件操作、网络操作等可能抛出
IOException
的场景。
11.5 注意事项
受检异常 vs 非受检异常:
受检异常(checked exception):必须使用
throws
声明或在方法内部处理(如IOException
)。非受检异常(unchecked exception):不需要使用
throws
声明(如NullPointerException
、IllegalArgumentException
)。方法重写时的
throws
:
子类重写父类方法时,
throws
声明的异常类型不能比父类方法更宽泛。例如,父类方法声明
throws IOException
,子类方法可以声明throws FileNotFoundException
(FileNotFoundException
是IOException
的子类),但不能声明throws Exception
。
throw
和throws
的结合使用:
可以在方法内部使用
throw
抛出异常,同时在方法签名中使用throws
声明异常类型。
总结
-
throw
:用于在代码中显式抛出一个异常。 -
throws
:用于方法签名中,声明该方法可能抛出的异常类型。
12. Java中的 interface 和 abstract class 有什么区别?
在Java中,interface
和 abstract class
都是用于实现抽象和多态的重要机制,但它们在设计和使用上有显著的区别。
12.1 定义
接口(Interface):
是一种完全抽象的类,只能包含抽象方法(Java 8 之前)。
从 Java 8 开始,接口可以包含默认方法(
default
方法)和静态方法。从 Java 9 开始,接口可以包含私有方法。
抽象类(Abstract Class):
是一种部分抽象的类,可以包含抽象方法和具体方法。
可以定义成员变量、构造器、普通方法和抽象方法。
12.2 主要区别
特性 | 接口(Interface) | 抽象类(Abstract Class) |
方法实现 | Java 8 之前只能包含抽象方法;Java 8 开始可以包含默认方法和静态方法 | 可以包含抽象方法和具体方法 |
成员变量 | 只能包含常量(默认是 public static final ) | 可以包含普通成员变量和常量 |
构造器 | 不能定义构造器 | 可以定义构造器 |
多继承 | 支持多继承(一个类可以实现多个接口) | 不支持多继承(一个类只能继承一个抽象类) |
默认访问修饰符 | 方法默认是 public abstract | 方法可以是 public 、protected 或默认访问修饰符 |
设计目的 | 定义行为规范(“能做什么”) | 定义类的部分实现(“是什么”和“能做什么”) |
12.3 使用场景
(1)接口的使用场景
定义一组行为规范,强调“能做什么”。
需要多继承时(一个类可以实现多个接口)。
适用于定义通用的功能,例如:
Runnable
接口定义线程任务。
Comparable
接口定义对象的比较规则。(2)抽象类的使用场景
定义部分实现,强调“是什么”和“能做什么”。
需要共享代码或状态时(抽象类可以包含成员变量和具体方法)。
适用于定义具有共同特征的类,例如:
动物类(
Animal
)可以定义抽象方法sound()
,子类(如Dog
、Cat
)实现具体的叫声。
12.4 示例代码
接口示例
interface Flyable {void fly(); // 抽象方法default void land() { // 默认方法System.out.println("正在降落");}static void altitude() { // 静态方法System.out.println("飞行高度");}
}class Bird implements Flyable {public void fly() {System.out.println("鸟在飞翔");}
}public class Main {public static void main(String[] args) {Bird bird = new Bird();bird.fly(); // 输出: 鸟在飞翔bird.land(); // 输出: 正在降落Flyable.altitude(); // 输出: 飞行高度}
}
抽象类示例
abstract class Animal {String name;Animal(String name) {this.name = name;}abstract void sound(); // 抽象方法void sleep() { // 具体方法System.out.println(name + " 正在睡觉");}
}class Dog extends Animal {Dog(String name) {super(name);}void sound() {System.out.println(name + " 汪汪叫");}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("小黑");dog.sound(); // 输出: 小黑 汪汪叫dog.sleep(); // 输出: 小黑 正在睡觉}
}
12.6 如何选择接口还是抽象类?
-
使用接口:
-
需要定义一组行为规范。
-
需要多继承。
-
不关心具体实现细节。
-
-
使用抽象类:
-
需要共享代码或状态。
-
需要定义部分实现。
-
需要构造器或非静态成员变量。
-
13. Java中的 volatile 关键字有什么作用?
在 Java 中,volatile
关键字用于修饰变量,主要作用是确保变量的可见性和禁止指令重排序。
13.1 可见性
作用:当一个线程修改了
volatile
变量的值,其他线程能立即看到最新的值。机制:
volatile
变量不会被线程缓存,所有读写操作都直接在主内存中进行,保证了多线程环境下的可见性。
13.2 禁止指令重排序
作用:防止 JVM 和处理器对指令进行重排序,确保代码执行顺序与编写顺序一致。
机制:
volatile
变量的读写操作前后会插入内存屏障,防止重排序。
使用场景
-
状态标志:用于标记线程是否继续运行。
volatile boolean running = true;public void run() {while (running) {// 执行任务} }public void stop() {running = false; }
-
双重检查锁定(Double-Checked Locking):用于单例模式中,确保实例的唯一性。
class Singleton {private volatile static Singleton instance;public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;} }
注意事项
不保证原子性:
volatile
不能保证复合操作的原子性,如i++
。性能影响:频繁读写
volatile
变量可能影响性能,因为每次操作都直接访问主内存。
总结
volatile
关键字主要用于确保变量的可见性和防止指令重排序,适用于状态标志和双重检查锁定等场景,但不适用于需要原子性操作的场合。
14. Java中的 synchronized 关键字有什么作用?
在 Java 中,synchronized
关键字用于实现线程同步,确保多个线程在访问共享资源时的线程安全。
14.1 互斥性(Mutual Exclusion)
作用:
synchronized
修饰的代码块或方法在同一时间只能被一个线程执行。机制:通过获取对象的锁(monitor lock)来实现互斥。当一个线程进入
synchronized
代码块时,其他线程必须等待锁释放后才能进入。
14.2 可见性(Visibility)
作用:确保线程对共享变量的修改对其他线程可见。
机制:在
synchronized
代码块或方法执行完成后,会将线程本地内存中的变量值刷新到主内存中;在进入synchronized
代码块或方法时,会从主内存中读取最新的变量值。
使用方式
synchronized
可以修饰以下两种形式:
1. 修饰实例方法
-
锁对象是当前实例(
this
)。 -
示例:
public synchronized void method() {// 线程安全的代码 }
2. 修饰静态方法
-
锁对象是当前类的
Class
对象。 -
示例:
public static synchronized void staticMethod() {// 线程安全的代码 }
3. 修饰代码块
-
需要显式指定锁对象。
-
示例:
public void method() {synchronized (this) { // 锁对象是当前实例// 线程安全的代码} }
使用场景
-
保护共享资源:
-
当多个线程需要访问或修改共享资源时,使用
synchronized
可以避免数据不一致问题。 -
示例:
public class Counter {private int count = 0;public synchronized void increment() {count++;}public synchronized int getCount() {return count;} }
-
-
实现线程安全的单例模式:
-
使用
synchronized
确保单例对象的唯一性。 -
示例:
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;} }
-
-
线程间通信:
-
结合
wait()
和notify()
方法,实现线程间的协作。 -
示例:
public class SharedResource {private boolean isReady = false;public synchronized void waitUntilReady() throws InterruptedException {while (!isReady) {wait(); // 释放锁并等待}}public synchronized void setReady() {isReady = true;notifyAll(); // 唤醒等待的线程} }
注意事项
-
性能开销:
-
synchronized
会引入锁竞争,可能导致线程阻塞,影响性能。 -
在高并发场景下,可以考虑使用更高效的并发工具(如
ReentrantLock
或java.util.concurrent
包中的类)。
-
-
死锁风险:
-
如果多个线程互相持有对方需要的锁,可能导致死锁。
-
示例:
// 线程1 synchronized (lockA) {synchronized (lockB) {// 操作} }// 线程2 synchronized (lockB) {synchronized (lockA) {// 操作} }
-
-
锁的范围:
-
尽量缩小同步代码块的范围,避免不必要的性能损耗。
-
-
总结
synchronized
关键字是 Java 中最基本的线程同步机制,用于实现互斥性和可见性。它适用于保护共享资源、实现线程安全的单例模式以及线程间通信等场景。但在高并发场景下,需要注意性能开销和死锁风险,必要时可以使用更高级的并发工具。
15. Java中的 transient 关键字有什么作用?
在 Java 中,transient
关键字用于修饰类的成员变量,其主要作用是阻止该变量被序列化。具体来说,当一个对象被序列化时,transient
修饰的变量不会被包含在序列化的数据中。
15.1 作用
阻止序列化:
transient
修饰的变量在对象序列化时会被忽略,不会被保存到文件或通过网络传输。默认值:在反序列化时,
transient
变量的值会被设置为默认值(如int
类型为0
,对象类型为null
)。
15.2 使用场景
-
敏感信息:
-
如果某些变量包含敏感信息(如密码、密钥等),可以使用
transient
修饰,避免序列化时泄露。 -
示例:
public class User implements Serializable {private String username;private transient String password; // 不会被序列化// 构造方法、getter 和 setter }
-
-
临时数据:
-
如果某些变量是临时数据或可以通过其他数据计算得出,可以使用
transient
修饰,避免不必要的序列化。 -
示例:
public class Data implements Serializable {private int value;private transient int cachedResult; // 临时缓存,不需要序列化public int computeResult() {if (cachedResult == 0) {cachedResult = value * 2; // 假设这是一个计算过程}return cachedResult;} }
-
-
不可序列化的对象:
-
如果某个成员变量是不可序列化的对象(如
Thread
或InputStream
),可以使用transient
修饰,避免序列化时抛出NotSerializableException
。 -
示例:
public class AppState implements Serializable {private String appName;private transient Thread workerThread; // 不可序列化的对象 }
-
15.3 注意事项
-
反序列化时的初始化:
-
反序列化时,
transient
变量的值会被设置为默认值。如果需要恢复这些变量的值,可以自定义readObject
方法。 -
示例:
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {in.defaultReadObject(); // 默认反序列化this.password = "defaultPassword"; // 手动初始化 transient 变量 }
-
-
与静态变量的区别:
-
transient
修饰的是实例变量,而静态变量(static
)本身就不会被序列化,因此不需要使用transient
修饰。
-
总结
transient
关键字用于阻止变量被序列化,适用于保护敏感信息、避免序列化临时数据或不可序列化的对象。反序列化时,transient
变量的值会被设置为默认值,如果需要恢复其值,可以自定义 readObject
方法。
16. Java中的 Comparable 和 Comparator 有什么区别?
在 Java 中,Comparable
和 Comparator
都是用于对象排序的接口,但它们的用途和实现方式有所不同。
16.1 Comparable
-
定义:
Comparable
是一个接口,定义在java.lang
包中。 -
作用:用于实现对象的自然排序(即默认排序规则)。
-
方法:需要实现
compareTo(T o)
方法。 -
使用场景:当一个类有明确的自然排序规则时,可以实现
Comparable
接口。 -
示例:
public class Person implements Comparable<Person> {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic int compareTo(Person other) {return this.age - other.age; // 按年龄排序}@Overridepublic String toString() {return name + " (" + age + ")";}public static void main(String[] args) {List<Person> people = new ArrayList<>();people.add(new Person("Alice", 30));people.add(new Person("Bob", 25));people.add(new Person("Charlie", 35));Collections.sort(people); // 使用自然排序System.out.println(people); // 输出:[Bob (25), Alice (30), Charlie (35)]}
}
16.2 Comparator
-
定义:
Comparator
是一个接口,定义在java.util
包中。 -
作用:用于实现对象的定制排序(即灵活的排序规则)。
-
方法:需要实现
compare(T o1, T o2)
方法。 -
使用场景:
-
当一个类没有实现
Comparable
接口时,可以通过Comparator
进行排序。 -
当需要多种排序规则时,可以使用
Comparator
。
-
-
示例:
import java.util.*;public class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return name + " (" + age + ")";}public static void main(String[] args) {List<Person> people = new ArrayList<>();people.add(new Person("Alice", 30));people.add(new Person("Bob", 25));people.add(new Person("Charlie", 35));// 使用 Comparator 按姓名排序Comparator<Person> nameComparator = new Comparator<Person>() {@Overridepublic int compare(Person p1, Person p2) {return p1.name.compareTo(p2.name);}};Collections.sort(people, nameComparator);System.out.println(people); // 输出:[Alice (30), Bob (25), Charlie (35)]}
}
16.3 区别对比
特性 | Comparable | Comparator |
包名 | java.lang | java.util |
方法 | compareTo(To) | compare(To1, To2) |
排序规则 | 自然排序(默认排序规则) | 定制排序(灵活排序规则) |
实现位置 | 在类内部实现 | 在类外部实现 |
使用场景 | 单一排序规则 | 多种排序规则 |
修改排序规则 | 需要修改类的代码 | 不需要修改类的代码 |
示例 | Collections.sort(list) | Collections.sort(list, comparator) |
16.4 使用建议
-
使用
Comparable
:-
当类有明确的自然排序规则时。
-
例如,
String
和Integer
类都实现了Comparable
,因为它们有明确的排序规则。
-
-
使用
Comparator
:-
当需要多种排序规则时。
-
当无法修改类的源代码时(例如,使用第三方库的类)。
-
当需要临时定义排序规则时。
-
总结
-
Comparable
用于定义对象的自然排序规则,适合单一排序场景。 -
Comparator
用于定义灵活的排序规则,适合多种排序场景。
17. Java中的 instanceof 关键字有什么作用?
在 Java 中,instanceof
是一个二元操作符,用于检查一个对象是否是指定类型(类、接口或子类)的实例。
17.1 作用
类型检查:判断一个对象是否属于某个类或其子类、接口的实现类。
避免类型转换异常:在类型转换之前使用
instanceof
进行检查,可以避免ClassCastException
。
17.2 语法
object instanceof Type
object
:需要检查的对象。
Type
:目标类型(类、接口或子类)。返回值:
true
或false
。
17.3 使用场景
1. 类型检查
-
在需要判断对象的实际类型时使用。
-
示例:
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}public class Main {public static void main(String[] args) {Animal myDog = new Dog();Animal myCat = new Cat();System.out.println(myDog instanceof Dog); // trueSystem.out.println(myDog instanceof Animal); // trueSystem.out.println(myCat instanceof Dog); // false}
}
2. 避免类型转换异常
-
在类型转换之前使用
instanceof
进行检查,确保转换的安全性。 -
示例:
Animal animal = new Dog();if (animal instanceof Dog) {Dog dog = (Dog) animal; // 安全转换System.out.println("This is a Dog.");
} else {System.out.println("This is not a Dog.");
}
3. 多态场景下的类型判断
-
在处理多态对象时,
instanceof
可以帮助确定对象的实际类型。 -
示例:
public void checkAnimal(Animal animal) {if (animal instanceof Dog) {System.out.println("This is a Dog.");} else if (animal instanceof Cat) {System.out.println("This is a Cat.");} else {System.out.println("This is an unknown Animal.");}
}
4. 接口实现检查
-
检查对象是否实现了某个接口。
-
示例:
interface Swimmable {}
class Fish implements Swimmable {}
class Bird {}public class Main {public static void main(String[] args) {Swimmable fish = new Fish();Bird bird = new Bird();System.out.println(fish instanceof Swimmable); // trueSystem.out.println(bird instanceof Swimmable); // false}
}
17.4 注意事项
-
null 检查:
-
如果对象为
null
,instanceof
会返回false
。 -
示例:
Animal animal = null; System.out.println(animal instanceof Animal); // false
-
-
泛型类型擦除:
-
由于 Java 泛型的类型擦除机制,
instanceof
不能直接用于泛型类型。 -
示例:
List<String> list = new ArrayList<>(); // 以下代码无法通过编译 // System.out.println(list instanceof List<String>);
-
-
性能影响:
-
instanceof
的性能通常较好,但在高频调用时可能会影响性能。
-
总结
instanceof
关键字用于检查对象是否属于某个类型,常用于类型检查、避免类型转换异常以及多态场景下的类型判断。它是 Java 中实现类型安全的重要工具,但在使用时需要注意 null
值和泛型类型擦除的限制。
18. Java中的 break 和 continue 有什么区别?
在 Java 中,break
和 continue
都是用于控制循环流程的关键字,但它们的作用和行为有所不同。
18.1 break
-
作用:立即终止当前循环(
for
、while
、do-while
或switch
语句),并跳出循环体。 -
使用场景:
-
当满足某个条件时,提前结束循环。
-
在
switch
语句中,用于跳出case
分支。
-
-
示例:
for (int i = 1; i <= 10; i++) {if (i == 5) {break; // 当 i 等于 5 时,终止循环}System.out.println(i); } // 输出:1 2 3 4
18.2 continue
-
作用:跳过当前循环的剩余代码,直接进入下一次循环迭代。
-
使用场景:
-
当满足某个条件时,跳过当前迭代,继续执行下一次循环。
-
-
示例:
for (int i = 1; i <= 5; i++) {if (i == 3) {continue; // 当 i 等于 3 时,跳过本次循环}System.out.println(i);
}
// 输出:1 2 4 5
18.3 区别对比
特性 | break | continue |
作用 | 终止整个循环 | 跳过当前迭代,继续下一次循环 |
使用场景 | 提前结束循环 | 跳过某些特定条件的迭代 |
循环行为 | 循环完全结束 | 循环继续执行,但跳过当前迭代 |
适用语句 | for 、while 、do-while 、switch | for 、while 、do-while |
18.4 嵌套循环中的使用
-
break
:默认只跳出当前所在的循环。如果需要跳出外层循环,可以使用带标签的break
。 -
continue
:默认只跳过当前循环的当前迭代。如果需要跳过外层循环的当前迭代,可以使用带标签的continue
。
带标签的 break
示例:
outerLoop:
for (int i = 1; i <= 3; i++) {for (int j = 1; j <= 3; j++) {if (i == 2 && j == 2) {break outerLoop; // 跳出外层循环}System.out.println("i=" + i + ", j=" + j);}
}
// 输出:
// i=1, j=1
// i=1, j=2
// i=1, j=3
// i=2, j=1
带标签的 continue
示例:
outerLoop:
for (int i = 1; i <= 3; i++) {for (int j = 1; j <= 3; j++) {if (i == 2 && j == 2) {continue outerLoop; // 跳过外层循环的当前迭代}System.out.println("i=" + i + ", j=" + j);}
}
// 输出:
// i=1, j=1
// i=1, j=2
// i=1, j=3
// i=2, j=1
// i=3, j=1
// i=3, j=2
// i=3, j=3
总结
-
break
:用于完全终止循环,适用于提前结束循环或跳出switch
语句。 -
continue
:用于跳过当前迭代,继续执行下一次循环,适用于跳过某些特定条件的迭代。 -
在嵌套循环中,可以使用带标签的
break
和continue
来控制外层循环的行为。
19. Java中的 Math 类有哪些常用方法?
Java 中的 Math
类提供了许多用于数学运算的静态方法。
19.1 基本运算
abs(int a)
,abs(long a)
,abs(float a)
,abs(double a)
返回参数的绝对值。
max(int a, int b)
,max(long a, long b)
,max(float a, float b)
,max(double a, double b)
返回两个参数中的较大值。
min(int a, int b)
,min(long a, long b)
,min(float a, float b)
,min(double a, double b)
返回两个参数中的较小值。
19.2 指数和对数
pow(double a, double b)
返回a
的b
次方。
sqrt(double a)
返回a
的平方根。
exp(double a)
返回自然对数底数e
的a
次方。
log(double a)
返回a
的自然对数(以e
为底)。
log10(double a)
返回a
的以 10 为底的对数。
19.3 三角函数
sin(double a)
返回角度的正弦值(角度以弧度表示)。
cos(double a)
返回角度的余弦值(角度以弧度表示)。
tan(double a)
返回角度的正切值(角度以弧度表示)。
asin(double a)
返回a
的反正弦值(结果以弧度表示)。
acos(double a)
返回a
的反余弦值(结果以弧度表示)。
atan(double a)
返回a
的反正切值(结果以弧度表示)。
atan2(double y, double x)
返回从直角坐标(x, y)
到极坐标(r, theta)
的转换角度theta
。
19.4 舍入运算
ceil(double a)
返回大于或等于a
的最小整数(向上取整)。
floor(double a)
返回小于或等于a
的最大整数(向下取整)。
round(float a)
,round(double a)
返回最接近a
的整数(四舍五入)。
19.5 随机数
-
random()
返回一个[0.0, 1.0)
范围内的伪随机double
值。
19.6 其他
toRadians(double angdeg)
将角度转换为弧度。
toDegrees(double angrad)
将弧度转换为角度。
hypot(double x, double y)
返回sqrt(x² + y²)
,即直角三角形的斜边长度。
copySign(double magnitude, double sign)
返回一个与sign
同符号的magnitude
值。
nextAfter(double start, double direction)
返回与start
相邻的、朝向direction
的浮点数。
nextUp(double d)
返回比d
大的最小浮点数。
nextDown(double d)
返回比d
小的最大浮点数。
20. Java中的 Arrays 类有哪些常用方法?
java.util.Arrays
类是 Java 中用于操作数组的工具类,提供了许多静态方法来处理数组。
20.1 排序
-
sort(array)
: 对数组进行升序排序。int[] arr = {5, 3, 1, 4, 2}; Arrays.sort(arr); // arr 现在是 [1, 2, 3, 4, 5]
-
sort(array, fromIndex, toIndex)
: 对数组的指定范围进行排序。int[] arr = {5, 3, 1, 4, 2}; Arrays.sort(arr, 1, 4); // arr 现在是 [5, 1, 3, 4, 2]
20.2 二分查找
-
binarySearch(array, key)
: 在已排序的数组中使用二分查找法查找指定元素,返回索引。如果未找到,返回负数。int[] arr = {1, 2, 3, 4, 5}; int index = Arrays.binarySearch(arr, 3); // index 是 2
-
binarySearch(array, fromIndex, toIndex, key)
: 在数组的指定范围内进行二分查找。int[] arr = {1, 2, 3, 4, 5}; int index = Arrays.binarySearch(arr, 1, 4, 3); // index 是 2
20.3 比较
-
equals(array1, array2)
: 比较两个数组是否相等(元素顺序和值相同)。int[] arr1 = {1, 2, 3}; int[] arr2 = {1, 2, 3}; boolean isEqual = Arrays.equals(arr1, arr2); // isEqual 是 true
20.4 填充
-
fill(array, value)
: 将数组的所有元素填充为指定值。int[] arr = new int[5]; Arrays.fill(arr, 10); // arr 现在是 [10, 10, 10, 10, 10]
-
fill(array, fromIndex, toIndex, value)
: 将数组的指定范围填充为指定值。int[] arr = new int[5]; Arrays.fill(arr, 1, 4, 10); // arr 现在是 [0, 10, 10, 10, 0]
20.5 复制
-
copyOf(original, newLength)
: 复制数组,指定新数组的长度。int[] arr = {1, 2, 3}; int[] newArr = Arrays.copyOf(arr, 5); // newArr 现在是 [1, 2, 3, 0, 0]
-
copyOfRange(original, from, to)
: 复制数组的指定范围。int[] arr = {1, 2, 3, 4, 5}; int[] newArr = Arrays.copyOfRange(arr, 1, 4); // newArr 现在是 [2, 3, 4]
20.6 转换为字符串
-
toString(array)
: 将数组转换为字符串表示形式。int[] arr = {1, 2, 3}; String str = Arrays.toString(arr); // str 是 "[1, 2, 3]"
20.7 哈希码
-
hashCode(array)
: 返回数组的哈希码。int[] arr = {1, 2, 3}; int hashCode = Arrays.hashCode(arr);
20.8 流操作
-
stream(array)
: 将数组转换为流。int[] arr = {1, 2, 3}; IntStream stream = Arrays.stream(arr);
20.9 并行排序
-
parallelSort(array)
: 对数组进行并行排序。int[] arr = {5, 3, 1, 4, 2}; Arrays.parallelSort(arr); // arr 现在是 [1, 2, 3, 4, 5]
-
parallelSort(array, fromIndex, toIndex)
: 对数组的指定范围进行并行排序。int[] arr = {5, 3, 1, 4, 2}; Arrays.parallelSort(arr, 1, 4); // arr 现在是 [5, 1, 3, 4, 2]
20.10 比较器排序
-
sort(array, comparator)
: 使用自定义比较器对数组进行排序。String[] arr = {"apple", "banana", "cherry"}; Arrays.sort(arr, (a, b) -> b.compareTo(a)); // arr 现在是 ["cherry", "banana", "apple"]
20.11 并行前缀计算
-
parallelPrefix(array, op)
: 对数组进行并行前缀计算。int[] arr = {1, 2, 3, 4}; Arrays.parallelPrefix(arr, (a, b) -> a + b); // arr 现在是 [1, 3, 6, 10]
20.12 集合转换
-
asList(array)
: 将数组转换为固定大小的列表。
String[] arr = {"a", "b", "c"};
List<String> list = Arrays.asList(arr);
// list 是 ["a", "b", "c"]
21. Java中的 Collections 类有哪些常用方法?
java.util.Collections
类是 Java 中用于操作集合(如 List
、Set
、Map
等)的工具类,提供了许多静态方法来处理集合。
21.1 排序
-
sort(list)
: 对列表进行升序排序。List<Integer> list = Arrays.asList(5, 3, 1, 4, 2); Collections.sort(list); // list 现在是 [1, 2, 3, 4, 5]
-
sort(list, comparator)
: 使用自定义比较器对列表进行排序。List<String> list = Arrays.asList("apple", "banana", "cherry"); Collections.sort(list, (a, b) -> b.compareTo(a)); // list 现在是 ["cherry", "banana", "apple"]
21.2 二分查找
-
binarySearch(list, key)
: 在已排序的列表中使用二分查找法查找指定元素,返回索引。如果未找到,返回负数。List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); int index = Collections.binarySearch(list, 3); // index 是 2
-
binarySearch(list, key, comparator)
: 使用自定义比较器在已排序的列表中进行二分查找。List<String> list = Arrays.asList("cherry", "banana", "apple"); int index = Collections.binarySearch(list, "banana", (a, b) -> b.compareTo(a)); // index 是 1
21.3 反转
-
reverse(list)
: 反转列表中的元素顺序。List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Collections.reverse(list); // list 现在是 [5, 4, 3, 2, 1]
21.4 随机打乱
-
shuffle(list)
: 随机打乱列表中的元素顺序。List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Collections.shuffle(list); // list 现在是随机顺序,例如 [3, 1, 5, 2, 4]
-
shuffle(list, random)
: 使用指定的随机源打乱列表中的元素顺序。List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Collections.shuffle(list, new Random()); // list 现在是随机顺序,例如 [4, 2, 1, 5, 3]
21.5 填充
-
fill(list, value)
: 将列表的所有元素填充为指定值。List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); Collections.fill(list, 10); // list 现在是 [10, 10, 10, 10, 10]
21.6 复制
-
copy(dest, src)
: 将源列表中的元素复制到目标列表中。List<Integer> src = Arrays.asList(1, 2, 3); List<Integer> dest = Arrays.asList(4, 5, 6, 7, 8); Collections.copy(dest, src); // dest 现在是 [1, 2, 3, 7, 8]
21.7 最小值和最大值
-
min(collection)
: 返回集合中的最小元素。List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); int min = Collections.min(list); // min 是 1
-
max(collection)
: 返回集合中的最大元素。List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); int max = Collections.max(list); // max 是 5
-
min(collection, comparator)
: 使用自定义比较器返回集合中的最小元素。List<String> list = Arrays.asList("apple", "banana", "cherry"); String min = Collections.min(list, (a, b) -> b.compareTo(a)); // min 是 "cherry"
-
max(collection, comparator)
: 使用自定义比较器返回集合中的最大元素。List<String> list = Arrays.asList("apple", "banana", "cherry"); String max = Collections.max(list, (a, b) -> b.compareTo(a)); // max 是 "apple"
21.8 替换
-
replaceAll(list, oldVal, newVal)
: 将列表中的所有旧值替换为新值。List<String> list = Arrays.asList("apple", "banana", "apple"); Collections.replaceAll(list, "apple", "orange"); // list 现在是 ["orange", "banana", "orange"]
21.9 频率
-
frequency(collection, obj)
: 返回集合中指定元素的出现次数。List<String> list = Arrays.asList("apple", "banana", "apple"); int freq = Collections.frequency(list, "apple"); // freq 是 2
21.10 不可变集合
-
unmodifiableCollection(collection)
: 返回一个不可修改的集合视图。List<String> list = Arrays.asList("apple", "banana", "cherry"); Collection<String> unmodifiableList = Collections.unmodifiableCollection(list); // unmodifiableList 是不可修改的
-
unmodifiableList(list)
: 返回一个不可修改的列表视图。List<String> list = Arrays.asList("apple", "banana", "cherry"); List<String> unmodifiableList = Collections.unmodifiableList(list); // unmodifiableList 是不可修改的
-
unmodifiableSet(set)
: 返回一个不可修改的集合视图。Set<String> set = new HashSet<>(Arrays.asList("apple", "banana", "cherry")); Set<String> unmodifiableSet = Collections.unmodifiableSet(set); // unmodifiableSet 是不可修改的
-
unmodifiableMap(map)
: 返回一个不可修改的映射视图。Map<String, Integer> map = new HashMap<>(); map.put("apple", 1); map.put("banana", 2); Map<String, Integer> unmodifiableMap = Collections.unmodifiableMap(map); // unmodifiableMap 是不可修改的
21.11 同步集合
-
synchronizedCollection(collection)
: 返回一个线程安全的集合。Collection<String> collection = new ArrayList<>(); Collection<String> syncCollection = Collections.synchronizedCollection(collection); // syncCollection 是线程安全的
-
synchronizedList(list)
: 返回一个线程安全的列表。List<String> list = new ArrayList<>(); List<String> syncList = Collections.synchronizedList(list); // syncList 是线程安全的
-
synchronizedSet(set)
: 返回一个线程安全的集合。Set<String> set = new HashSet<>(); Set<String> syncSet = Collections.synchronizedSet(set); // syncSet 是线程安全的
-
synchronizedMap(map)
: 返回一个线程安全的映射。Map<String, Integer> map = new HashMap<>(); Map<String, Integer> syncMap = Collections.synchronizedMap(map); // syncMap 是线程安全的
21.12 单元素集合
-
singletonList(obj)
: 返回一个只包含指定对象的不可变列表。List<String> list = Collections.singletonList("apple"); // list 是 ["apple"]
-
singletonSet(obj)
: 返回一个只包含指定对象的不可变集合。Set<String> set = Collections.singletonSet("apple"); // set 是 ["apple"]
-
singletonMap(key, value)
: 返回一个只包含指定键值对的不可变映射。Map<String, Integer> map = Collections.singletonMap("apple", 1); // map 是 {"apple": 1}
21.13 空集合
-
emptyList()
: 返回一个空的不可变列表。List<String> list = Collections.emptyList(); // list 是 []
-
emptySet()
: 返回一个空的不可变集合。Set<String> set = Collections.emptySet(); // set 是 []
-
emptyMap()
: 返回一个空的不可变映射。Map<String, Integer> map = Collections.emptyMap(); // map 是 {}
21.14 检查集合是否为空
-
isEmpty(collection)
: 检查集合是否为空。List<String> list = new ArrayList<>(); boolean isEmpty = Collections.isEmpty(list); // isEmpty 是 true
21.15 反转比较器
-
reverseOrder()
: 返回一个反转自然顺序的比较器。List<String> list = Arrays.asList("apple", "banana", "cherry"); Collections.sort(list, Collections.reverseOrder()); // list 现在是 ["cherry", "banana", "apple"]
-
reverseOrder(comparator)
: 返回一个反转指定比较器顺序的比较器。List<String> list = Arrays.asList("apple", "banana", "cherry"); Collections.sort(list, Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER)); // list 现在是 ["cherry", "banana", "apple"]