编辑
API 基础概念
API 是预先定义好的类、方法或函数的集合,开发者通过调用这些接口实现特定功能,避免重复造轮子。例如 Java 中的 Scanner 用于输入操作,Random 用于生成随机数。
查阅 Java API 文档
Java 官方文档(JDK 11)可通过以下链接访问: www.runoob.com/manual/jdk1…
文档结构通常包含:
- 包(Package)分类
- 类(Class)列表
- 方法(Method)详细说明
常用 API 示例
Scanner 类
用于控制台输入数据:
import java.util.Scanner;
Scanner sc = new Scanner(System.in);
int num = sc.nextInt();
Random 类
生成伪随机数:
import java.util.Random;
Random rd = new Random();
int randomNum = rd.nextInt(100); // 0-99
文档使用技巧
- 通过包名定位目标类(如
java.util) - 在类页面查看构造方法和方法摘要
- 注意方法参数类型和返回值说明
- 搜索功能快速定位关键词
实践建议
- 遇到不熟悉的类时优先查阅文档
- 结合 IDE 的代码提示功能辅助记忆
- 通过简单示例测试 API 的实际效果
String
String 不可变特性
字符串对象一旦创建,其内容不可修改。每次修改操作都会生成新的字符串对象,原对象保持不变。这种设计保证了线程安全性,但频繁修改时效率较低。
常用方法
equals 方法
字符串内容完全一致时返回 true,否则返回 false。区分大小写。
String str1 = "hello";
String str2 = "HELLO";
System.out.println(str1.equals(str2)); // false
split 方法
根据正则表达式规则切割字符串,返回字符串数组。
String str = "a,b,c";
String[] arr = str.split(","); // ["a", "b", "c"]
replace 方法
替换字符串中的指定内容,返回新字符串。
String input = "TMD is bad";
String output = input.replace("TMD", "***"); // "*** is bad"
toCharArray 方法
将字符串转换为字符数组。
String str = "hello";
char[] chars = str.toCharArray(); // ['h','e','l','l','o']
charAt 方法
获取指定索引位置的字符。
String str = "java";
char ch = str.charAt(2); // 'v'
length 方法
返回字符串长度。
String str = "hello";
int len = str.length(); // 5
substring 方法
截取子字符串,支持两种形式。
String str = "hello world";
String sub1 = str.substring(6); // "world"
String sub2 = str.substring(0,5); // "hello"
注意事项
- 字符串索引从 0 开始
- substring 方法的 endIndex 参数不包含在结果中
- replace 方法不会修改原字符串,而是返回新字符串
- 字符串比较应使用 equals 而非 ==
StringBuilder 和 StringBuffer 概述
StringBuilder 和 StringBuffer 是 Java 中用于处理可变字符串的两个类,位于 java.lang 包中。它们的主要功能是通过动态调整内部字符数组来高效地进行字符串拼接、插入、删除等操作,避免了 String 类不可变特性带来的性能问题。
核心区别
线程安全性:
- StringBuffer 是线程安全的,所有公开方法均使用
synchronized关键字修饰,适合多线程环境。 - StringBuilder 非线程安全,但单线程下性能更高,是 Java 5 引入的优化替代方案。
性能:
- StringBuilder 在单线程场景下比 StringBuffer 快约 10%-15%,因避免了同步开销。
- 两者均通过动态扩容(默认容量 16,扩容规则为
(旧容量+1)*2)减少内存复制次数。
共同特性
继承关系: 均继承自 AbstractStringBuilder,共享以下核心方法:
append():追加字符串或基本类型insert():在指定位置插入delete():删除子串reverse():反转字符串setCharAt():修改指定字符
初始化方式:
// 默认容量16
StringBuilder sb1 = new StringBuilder();
// 指定初始容量
StringBuffer sbf = new StringBuffer(100);
// 从字符串初始化
StringBuilder sb2 = new StringBuilder("Hello");
典型使用场景
StringBuilder 适用场景:
- 单线程环境下的高频字符串操作
- 日志拼接、SQL 语句动态生成等性能敏感场景
StringBuffer 适用场景:
- 多线程共享的字符串操作
- 需要保证线程安全的文本处理模块
性能优化建议
-
预分配容量: 预估最终字符串长度,初始化时指定足够容量避免多次扩容:
StringBuilder sb = new StringBuilder(1024); -
链式调用: 利用方法返回
this的特性减少临时对象:sb.append("a").append(123).insert(1, "_"); -
避免混合使用 String: 减少与 String 的隐式转换,例如:
// 反例:产生临时String对象 sb.append(str1 + str2); // 正例:直接追加 sb.append(str1).append(str2);
底层实现原理
两者均通过字符数组实现:
char[] value; // 存储字符的数组
int count; // 实际使用的字符数
扩容时调用 Arrays.copyOf() 创建新数组,时间复杂度为 O(n)。关键操作的时间复杂度:
- 追加:平均 O(1),最坏 O(n)
- 插入/删除:O(n)(需要移动后续字符)
版本兼容性
- StringBuffer 从 Java 1.0 开始存在
- StringBuilder 在 Java 5 引入,API 与 StringBuffer 完全兼容
- 现代 Java 开发中,除非需要线程安全,否则优先选择 StringBuilder
ArrayList集合
集合的概述:
集合是一种容器,用来装数据的,类似于数组。,但数组的长度创建之后就固定了,集合不会,集合可以任意改变大小
为何要学集合,与数组的区别
集合与数组的核心区别
集合和数组都是用于存储数据的容器,但它们在设计目的和特性上有显著差异。
数组的特性
- 长度固定,创建后无法动态扩展或收缩
- 通过索引直接访问元素,访问速度快
- 内存连续分配,适合存储固定数量的同类型元素
集合的特性
- 长度动态可变,可随时增删元素
- 提供丰富的操作方法(如排序、查找)
- 通常实现为类库,包含多种具体实现(如List、Set等)
选择使用建议
需要快速随机访问且数据量固定时优先考虑数组。需要动态调整容量或使用高级功能时选择集合。现代编程中,集合因其灵活性更常被使用。
ArrayList集合的创建方法
初始化空ArrayList
ArrayList<String> list = new ArrayList<>();
指定初始容量创建
ArrayList<Integer> numbers = new ArrayList<>(20);
通过已有集合创建
List<String> existingList = Arrays.asList("A", "B");
ArrayList<String> newList = new ArrayList<>(existingList);
使用Arrays.asList初始化
ArrayList<String> colors = new ArrayList<>(Arrays.asList("Red", "Green"));
使用List.of初始化(Java 9+)
ArrayList<String> fruits = new ArrayList<>(List.of("Apple", "Banana"));
使用双括号初始化
ArrayList<String> cities = new ArrayList<String>() {{
add("Beijing");
add("Shanghai");
}};
注意事项
- 泛型类型需在尖括号中指定
- 初始容量参数可选,默认10
- Java 7开始右侧可省略泛型类型(菱形语法)
ArrayList集合的增删改查操作
ArrayList 的基本操作
ArrayList 是 Java 中常用的动态数组实现,基于 List 接口,支持动态扩容。以下是其核心操作方法:
添加元素
-
add(E element)
将元素追加到列表末尾。ArrayList<String> list = new ArrayList<>(); list.add("Apple"); list.add("Banana"); -
add(int index, E element)
在指定索引位置插入元素,后续元素右移。list.add(1, "Orange"); // ["Apple", "Orange", "Banana"]
删除元素
-
remove(int index)
删除指定索引位置的元素,返回被删除的元素。String removed = list.remove(0); // 删除 "Apple" -
remove(Object o)
删除首次出现的指定对象(需重写equals方法)。list.remove("Banana"); // 删除 "Banana"
修改元素
-
set(int index, E element)
替换指定索引位置的元素,返回原元素。String oldValue = list.set(0, "Grape"); // 将 "Orange" 替换为 "Grape"
查询元素
-
get(int index)
获取指定索引位置的元素。String fruit = list.get(0); // 返回 "Grape" -
size()
返回列表当前元素数量。int count = list.size(); // 返回 1
遍历 ArrayList
-
for 循环
for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } -
增强 for 循环
for (String item : list) { System.out.println(item); } -
迭代器
Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { System.out.println(iterator.next()); }
注意事项
-
索引越界:操作索引时需确保
0 ≤ index < size(),否则抛出IndexOutOfBoundsException。 -
性能:
- 随机访问(
get/set)效率高(O(1))。 - 插入/删除中间元素效率低(O(n)),因需移动后续元素。
- 随机访问(
-
线程安全:ArrayList 非线程安全,多线程环境下建议使用
Collections.synchronizedList或CopyOnWriteArrayList。
示例代码
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(10);
numbers.add(20);
numbers.add(1, 15); // [10, 15, 20]
numbers.set(2, 25); // [10, 15, 25]
numbers.remove(0); // [15, 25]
int num = numbers.get(1); // 25
用一个面试题结尾
说一下:String/StringBuilder/StringBuffer的区别
面试官,你好,这是我对于String,StringBuilder和StringBuffer的区别的理解:
首先我想用一句话来概括一下这3点的区别。
第一:String是不可变字符串,每次修改都会产生新的字符串,所以它效率比较低,但它线程是非常安全的
第二:StringBuilder的是可变字符串,它修改不产生新对象,效率最高,但它线程并不安全。
第三:StringBuffer是可变字符串效率中的线程安全方法,自带锁(synchronized)
然后我来详细对比一下他们的区别
第一就是可变可不变的区别:
String的底层用final char[]来修饰。我们都知道final。修饰变量,方法,对象就是最终值,所以他是不可变的,所以他每次拼接修改都会产生新的对象,频繁操作会产生大量无用的对象,所以它的性能就比较差。
而Stringbuilder和Stringbuffer的底层都是用普通char[]来实现,所以它是可变的,可以直接在原数组上会不会新建对象,也就少了很多无用对象的产生,所以它的性能就远高于String。
第二,我们来说一下线程安全的问题,这也是我们做项目之中非常关键的一个问题
因为string是不可变的,所以它的线程天然就很安全,因为无法对它产生修改,
而StringBuffer因为所有方法都加了sybchronized。同步锁,所以它的线程也是安全的。
而StringBuilder。并没有加锁,。可以对他任意进行修改,所以它的线程并不安全
。
第三,我们从它的性能来说String Builder大于StringBuffer大于String因为string builder,不需要创建新的对象并且无锁,所以最快,然后StringBuffer。同样无需创建新对象,但有锁略慢。而String每次要新建对象,所以他是最慢的。
第四,我们来说一下它们分别的使用场景
在我们少量操作一些数据字符或者简单赋值的时候就用String。
那我们在单线程的情况下。用String builder,注意是。单线程。用大量字符串拼接,因为它的效率是最高的,而单线程也并不用担心安全性的问题
。那我们在多线程环境下并发操作字符串的时候,那就需要用到,因为在多线程环境下用string虽然它安全,但是它的性能太差,并且运行时长也过长,会造成很多的效率问题。而用StringBuffer,因为它带了同步锁锁住了,所以它的安全性值得保障,并且它的操作速度也仅是略慢于String Builder。
最后来一个整体的总结,String不可变,适合少量操作。
StringBuilder可变线程不安全,但它性能最高,单线程的话,不考虑安全问题的情况下优先使用,
StringBuffer可变线程,安全性能稍低,多线程环境使用最好。
面试官,我的回答到此结束。