Java中所有常用集合都在java.util包下,所以可以
import java.util.*;
Java中List本身是一个泛型接口,继承自Collection,最常用的实现类是ArrayList。
演示:
千万不要忘了初始化!
ArrayList<Integer> scores = null; //不会是false,而是报错:NullPointerException System.out.println(scores.isEmpty());
其他增删改查方法:
ArrayList<Integer> scores = new ArrayList<>(); System.out.println(scores.size()); scores.add(12); //按下标index依次添加的 scores.add(25); scores.set(0, 21); //只能改,不能加 System.out.println(scores.isEmpty()); System.out.println(scores.size()); //存放元素个数:2 System.out.println(scores.get(0)); System.out.println(scores.get(1)); System.out.println(scores.contains(21)); //true System.out.println(scores.contains(28)); //false System.out.println(scores.indexOf(21)); //返回下标:0 System.out.println(scores.indexOf(28)); //找不到:-1 scores.remove(0); //删除下标为0的元素 scores.remove(12); //删除元素12 scores.clear(); //清除所有元素
为什么要使用集合?数组不够强大,^_^
比如:数组能不能add()?
但为什么ArrayList就能一直add()呢?其实现原理和StringBuilder非常类似:
public ArrayList(int initialCapacity) {
源代码演示内部实现:扩容的方法
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //elementData:数组容器 int newCapacity = oldCapacity + (oldCapacity >> 1);
PS:位运算右移(>>)各二进位全部右移若干位,相当于乘以2(但不建议我们的代码也这么写:降低可读性)
@想一想@:既然ArrayList这么强大,还有必要使用数组么?
因为所有集合都采用迭代器模式,实现了iterable,所以可以用一种统一的模式来遍历集合元素。
Java干脆更进一步,在语法层面提供了foreach迭代:
List<Person> people = new ArrayList<>(); for (Person person : people) { System.out.println(person.Name); }
@想一想@:能不能使用for循环么?
for (int i = 0; i < people.size(); i++) { System.out.println(people.get(i).Name); }
能。但是:
Set和List非常类似,都继承自Collection,所以有相同的增(add)删(remove/clear)查(isEmpty/contains)方法。
Set是一个接口,常用的实现类是HashSet和TreeSet(演示)
但是,因为Set不允许重复,所以重复的元素会被自动合并:
Set<Person> people = new HashSet<>(); Person atai = new Person(); people.add(atai); people.add(atai); people.add(atai); System.out.println(people.size()); //始终是1
@想一想@:抛异常是不是更好一些?所以推荐这种写法:
if (!people.contains(atai)) { //增加代码可读性 people.add(atai); }
此外,因为Set没有索引,所以不能精确查找某个元素,当然也不能更改。一个变通的方法是:先删除,再添加。
//先删除后添加 = 更改 people.remove(atai); Person bo = new Person(); bo.Name = "波仔"; people.add(bo);最后,Set可以foreach遍历,没法for循环:
for (Person person : people) { System.out.println(person.Name); }
Java中Map本身是一个泛型接口,常用的实现类有:HashMap和HashTable。
#常见面试题:两者的区别?#
主要是在线程安全(后文详述)方面:
因为HashMap更新(内部实现了Tree),一般情况推荐使用HashMap,多线程时推荐ConcurrentHashMap。
scores.put("atai", 100.0); //增 scores.remove("atai"); //删:通过key scores.replace("atai", 98.5); //改 //查 System.out.println(scores.get("atai")); System.out.println(scores.getOrDefault("atai", 80.0)); //查不到给默认值 System.out.println(scores.containsKey("atai")); //检查“键” System.out.println(scores.containsValue(100.0)); //检查“值”
注意:Map的key也是不允许重复的,如果put时有重复,和Set一样处理。不报错,后面的键值对覆盖前面的。
因为Map没有继承自iterable,所以是不能直接foreach遍历的!
如果确实要遍历,需要首先进行转化,拿到
for (String student : scores.keySet()) {
for (Double score : scores.values()) {
for (Map.Entry<String, Double> entry : scores.entrySet()) { System.out.println( entry.getKey() + //键 ":" + entry.getValue()); //值 }注意Entry是Map的内部接口,所以只能通过Map点出。
见:J&C:集合概述 / 迭代器模式 / ER模型 / 仓储模式
多快好省!前端后端,线上线下,名师精讲
更多了解 加: