CONTENTS
-
- [1. String/StringBuffer/StringBuilder](#1. String/StringBuffer/StringBuilder)
- [2. Arrays](#2. Arrays)
- [3. ArrayList](#3. ArrayList)
- [4. LinkedList](#4. LinkedList)
- [5. HashSet](#5. HashSet)
- [6. HashMap](#6. HashMap)
1. String/StringBuffer/StringBuilder
String
类即字符串,在 Java 中 String
类是不可改变 的,如果修改 String
对象,那么其实是开一个新的空间保存,而原空间中的字符串还存在于内存中。String
类的用法如下:
java
// 定义
String str = "Hello World!";
char[] charArray = { 'A', 'B', 'C' };
String strFromChar = new String(charArray);
// 遍历
for (int i = 0; i < str.length(); i++)
System.out.print(str.charAt(i));
System.out.println();
for (char c: str.toCharArray()) // toCharArray将String转为字符数组
System.out.print(c);
System.out.println();
// 常用方法
str.charAt(0); // H,返回第0个字符
str.compareTo("G"); // 1,比较字符串,如果大于返回1,小于返回-1,否则返回0
str.equals("Hello World!"); // true,Java中比较两个字符串值是否相等必须用equals
str.startsWith("He"); // true,判断是否以"He"开头
str.endsWith("d!"); // true,判断是否以"d!"结尾
str.indexOf('o'); // 4,返回'o'第一次出现的位置
str.indexOf('o', 5); // 7,返回'o'从下标5开始第一次出现的位置
str.lastIndexOf('o'); // 7,返回'o'最后出现的位置
str.lastIndexOf('o', 6); // 4,返回'o'在下标6之前的字符串中最后出现的位置
str.replace('o', 'x'); // Hellx Wxrld!,将'o'替换成'x'
str.split(" "); // [Hello, World!],以" "进行分割,返回分割后的数组,支持正则表达式
str.substring(6, 9); // Wor,返回[6, 9)的字串,如果不指定第二个下标默认为末尾
str.toLowerCase(); // hello world!,将所有字母转为小写
str.toUpperCase(); // HELLO WORLD!,将所有字母转为大写
当需要对字符串进行频繁修改时,要用 StringBuffer
或 StringBuilder
类。这两个类的对象能够被多次修改,并且不产生新的未使用对象。
StringBuffer
和 StringBuilder
之间最大的不同在于 StringBuilder
的方法不是线程安全的(不能同步访问)。但是 StringBuilder
相较于 StringBuffer
有速度优势,所以多数情况下建议使用 StringBuilder
类。以 StringBuilder
为例,用法如下:
java
// 定义
StringBuilder strBuilder = new StringBuilder(str);
// 遍历
for (int i = 0; i < strBuilder.length(); i++)
System.out.print(strBuilder.charAt(i));
System.out.println();
// 常用方法
strBuilder.append("A"); // 在末尾追加字符串/字符/数字
strBuilder.reverse(); // 翻转字符串
strBuilder.delete(0, 1); // 删除[0, 1)中的字符串
strBuilder.insert(6, "A"); // 在下标6的位置插入字符串/字符/数字
strBuilder.replace(0, 7, "Hello"); // 将[0, 7)中的字符串替换为"Hello"
strBuilder.toString(); // 转换回String
2. Arrays
Arrays
类定义在 java.util
包中,该类能够方便地操作数组,用法如下:
java
// 定义
int[] arr = { 2, 4, 3, 1, 5 };
int[][] arr2d = {{ 1, 2 }, { 3, 4 }};
Integer[] arrInteger = { 2, 4, 3, 1, 5 };
// 遍历
for (int i = 0; i < arr.length; i++)
System.out.print(arr[i] + " ");
System.out.println();
for (int x: arr)
System.out.print(x + " ");
System.out.println();
// 常用方法
Arrays.sort(arr); // 从小到大排序
Arrays.sort(arrInteger, (x, y) -> y - x); // 从大到小排序,必须用Integer对象
Arrays.binarySearch(arr, 3); // 返回2,对排好序的数组二分查找
Arrays.equals(arr, arr); // 返回true,判断两个数组是否相等
Arrays.fill(arr, 0); // 用0填充数组所有元素
Arrays.toString(arr); // 返回[0, 0, 0, 0, 0],将数组的第一维转换成字符串形式
Arrays.deepToString(arr2d); // 返回[[1, 2], [3, 4]],递归转换数组的每一维,可用于二维及以上的数组
3. ArrayList
Java 的集合框架主要包括两种类型的容器:
- 集合(Collection):存储一个元素集合。
- 图(Map):存储键/值对映射。
其中,Collection
接口又包含了 List
接口和 Set
接口两大分支,前者为允许存在重复元素的有序集合,后者为不允许存在重复元素的无序集合;Map
是一个映射接口,其中的每一个元素包含一个 key
和对应的 value
。
ArrayList
类实现了 List
接口,继承自 AbstractList
类,位于 java.util
包中(迭代器也位于该包中),可以用于动态 地调整存储在其中的元素的大小。ArrayList
类是基于数组的数据结构,它提供了一组用于操作元素的方法,包括添加、删除、插入、搜索和排序等。
ArrayList
用法如下:
java
// 定义
ArrayList<Integer> v = new ArrayList<>(); // <>中只能为引用数据类型
ArrayList<Integer> v = new ArrayList<>(Arrays.asList(1, 2, 3)); // 初始化时赋值,当前为[1, 2, 3]
// 遍历
for (int i = 0; i < v.size(); i++) // 传统for循环
System.out.printf("%d ", v.get(i));
System.out.println();
for (int x: v) // forEach循环,推荐这种写法
System.out.printf("%d ", x);
System.out.println();
for (Iterator<Integer> it = v.iterator(); it.hasNext();) // 迭代器
System.out.printf("%d ", it.next());
System.out.println();
for (ListIterator<Integer> it = v.listIterator(); it.hasNext();) // 列表迭代器
System.out.printf("%d ", it.next());
System.out.println();
v.stream().forEach(x -> System.out.printf("%d ", x)); // Java8的Stream API和Lambda表达式
System.out.println();
// 常用方法
v.add(4); // 在末尾添加4,当前为[1, 2, 3, 4]
v.add(1, 5); // 在下标1处添加5,当前为[1, 5, 2, 3, 4]
v.remove(4); // 删除下标4处的元素,当前为[1, 5, 2, 3]
v.set(0, 4); // 将下标0处的元素置为4,当前为[4, 5, 2, 3]
v.subList(0, 2); // 返回[4, 5],截取[0, 2)的子列表
v.indexOf(5); // 返回1,获取元素5第一次出现的下标,若不存在返回-1
v.isEmpty(); // 返回false,判断是否为空
v.contains(2); // 返回true,判断是否含有元素2
v.sort(Comparator.naturalOrder()); // 从小到大排序
v.sort(Comparator.reverseOrder()); // 从大到小排序
ArrayList<Integer> t = (ArrayList<Integer>)v.clone(); // 复制一份,和原ArrayList不是同一份
Integer a[] = new Integer[v.size()];
v.toArray(a); // 转换为数组
4. LinkedList
Java 的 LinkedList
类是一个实现了 List
接口和 Deque
接口的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
与 ArrayList
相比,LinkedList
的增加和删除的操作效率更高,而查找和修改的操作效率较低。因此需要频繁访问列表中的某一个元素且只需要在列表末尾进行添加和删除元素操作推荐使用 ArrayList
,而需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作推荐使用 LinkedList
。
LinkedList
的定义与遍历方式与 ArrayList
相同,且上述的 ArrayList
常用方法在 LinkedList
中均可使用,额外添加的部分方法如下:
java
// 定义
LinkedList<Integer> v = new LinkedList<>(Arrays.asList(1, 2, 3));
// 常用方法
v.addLast(4); // 在尾部添加4,当前为[1, 2, 3, 4]
v.addFirst(5); // 在首部添加5,当前为[5, 1, 2, 3, 4]
v.removeLast(); // 删除并返回尾部元素,当前为[5, 1, 2, 3]
v.removeFirst(); // 删除并返回首部元素,当前为[1, 2, 3]
v.getFirst(); // 返回首部元素1
v.getLast(); // 返回尾部元素3
5. HashSet
Java 的 HashSet
类是一个实现了 Set
接口的集合类,它使用 HashMap
作为基础,因此其特性和 HashMap
类似:
- 不重复:是一个没有重复元素的集合。
- 无序:它不保证元素的顺序。
- 允许
null
:允许使用null
元素。 - 非同步:即不是线程安全的,如果多个线程尝试同时修改
HashSet
,则最终结果是不确定的。 必须在多线程访问时显式同步对HashSet
的并发访问。
HashSet
用法如下:
java
// 定义
HashSet<Integer> st = new HashSet<>();
HashSet<Integer> st = new HashSet<>(Arrays.asList(1, 2, 3));
// 遍历
for (int x: st) // forEach循环,推荐这种写法
System.out.printf("%d ", x);
System.out.println();
for (Iterator<Integer> it = st.iterator(); it.hasNext();) // 迭代器
System.out.printf("%d ", it.next());
System.out.println();
st.stream().forEach(x -> System.out.printf("%d ", x)); // Java8的Stream API和Lambda表达式
System.out.println();
// 常用方法
st.add(4); // 添加元素,当前为{1, 2, 3, 4}
st.remove(3); // 删除元素,当前为{1, 2, 4}
st.contains(3); // 返回false,判断是否存在3
st.size(); // 返回2,获取集合的元素数量
st.isEmpty(); // 返回false,判断是否为空
st.clear(); // 清空元素
6. HashMap
Java 的 HashMap
是一个实现了 Map
接口的哈希表,它存储的内容是键值对(key-value)映射。HashMap
的特性如下:
- 键值对存储:
HashMap
是以key-value
存储形式存在,主要用来存放键值对。 - 非同步:
HashMap
的实现不是同步的,这意味着它不是线程安全的。 - 允许
null
:它的key
、value
都可以为null
。 - 无序:此外,
HashMap
中的映射不是有序的。
HashMap
的底层数据结构为:
- Java8 之前:
HashMap
由数组+链表组成,数组是HashMap
的主体,链表则主要用于解决哈希碰撞。 - Java8 之后:在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)并且当前数组的长度大于64时,此时此索引位置上的所有数据改为使用红黑树存储。
HashMap
用法如下:
java
// 定义
HashMap<String, Integer> mp = new HashMap<>();
HashMap<String, Integer> mp = new HashMap<String, Integer>() {{ // 可能会导致一些未预期的副作用,因为它实际上创建了一个匿名子类
put("ABC", 1);
put("DEF", 2);
}};
// 遍历
for (String k: mp.keySet()) // 遍历key
System.out.println(k);
for (int v: mp.values()) // 遍历value
System.out.println(v);
for (Map.Entry<String, Integer> e: mp.entrySet()) // 遍历key-value,推荐这种写法
System.out.println(e.getKey() + " " + e.getValue());
for (Iterator it = mp.entrySet().iterator(); it.hasNext();) { // 迭代器
Map.Entry e = (Map.Entry)it.next();
System.out.println(e.getKey() + " " + e.getValue());
}
// 常用方法
mp.put("YYJ", 666); // 添加键值对,如果键已经存在,就替换原来的值
mp.get("YYJ"); // 返回666,获取某个key对应的value,如果key不存在返回null
mp.remove("YYJ"); // 删除指定的key及其对应的value,如果key不存在返回null
mp.containsKey("YYJ"); // 返回false,判断是否包含指定的key
mp.containsValue(1); // 返回true,判断是否包含指定的value
mp.size(); // 返回2,获取键值对的数量
mp.clear(); // 清空键值对
mp.isEmpty(); // 返回true,判断是否为空