存放数据的集合,底层是数组、链表或红黑树实现。因为应用场景的需求,Java提供了不同的接口以及实现类。
集合中存储的是元素的地址信息。
Collection是泛型接口,其集合体系如下图
有序:元素存入顺序和取出顺序一致
重复:可以放入相同元素在不同位置
索引:能否通过索引操作集合中的元素
public class CollectionTest1 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>(); // 有序,可重复,有索引
list.add("1");
list.add("2");
list.add("1");
list.add("2");
System.out.println(list);
HashSet<String> set = new HashSet<>(); // 无序,无重复,无索引
set.add("1");
set.add("2");
set.add("1");
System.out.println(set);
}
}
public class CollectionTest1 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
// add()添加
c.add("1");
c.add("2");
System.out.println(c);
// clear()清空集合的元素
// c.clear();
System.out.println(c);
// isEmpty()判断集合是否为空
System.out.println(c.isEmpty());
// size()获取集合大小
System.out.println(c.size());
// contains()判断集合中是否包含某个元素——精确匹配
System.out.println(c.contains("1"));
// remove()删除,如果重复,只删除第一个
System.out.println(c.remove("1"));
// toArray()把集合转化成数组,返回的是Object类型,因为泛型在后续就没有了,这样可以兼容任意类型的数据
Object[] arr = c.toArray();
System.out.println(Arrays.toString(arr));
// 若想指定数组类型
String[] arr2 = c.toArray(new String[c.size()]);
System.out.println(Arrays.toString(arr2));
// 把一个集合的全部数据倒入另一个集合中去——批量添加
Collection<String> c1 = new ArrayList<>();
c1.add("1");
c1.add("2");
Collection<String> c2 = new ArrayList<>();
c2.add("3");
c2.add("4");
c1.addAll(c2);
System.out.println(c1); // [1, 2, 3, 4]
System.out.println(c2); // [3, 4]
}
}
Collection不支持使用for循环进行遍历,因为for循环遍历的情况应该支持索引,但是Collection中的不一定都支持索引,比如Set。
分类:
public class CollectionTest2 {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
c.add("1");
c.add("2");
c.add("3");
c.add("4");
c.add("5");
System.out.println(c);
// // 使用迭代器遍历,千万不能越界咯,越界会出现不存在元素的异常
// Iterator it = c.iterator();
System.out.println(it.next());
System.out.println(it.next());
// // hashNext()的底层是看指针是否等于集合的长度
// while (it.hasNext()) {
// // 如果重复使用这个元素的话,不记住这个元素就会存在问题
// // 多次next他会一致往后走
// // 询问一次走一次,变量记住比较合理
// System.out.println(it.next());
// }
// // 增强for循环——可以遍历集合也可以遍历数组
// // for (元素类型 变量名:数组或集合) {
// // }
// for(String x: c) {
// System.out.println(x);
// }
// String[] name = {"11", "22", "33"};
// for (String x:name) {
// System.out.println(x);
// }
// Lambda表达式
// forEach()
c.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
c.forEach(s-> System.out.println(s));
c.forEach(System.out::println);
}
}
特点: 有序、可重复、有索引
特有方法: 因为支持索引,所以多了很多与索引相关的方法
public class ListTest1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>(); // 经典代码
list.add("1");
list.add("2");
list.add("3");
list.add("2");
System.out.println(list);
// 在某个位置插入元素。注意这里的index不能大于长度
list.add(4, "4");
System.out.println(list);
// 根据索引删除元素,并返回被删除元素
System.out.println(list.remove(0));
System.out.println(list);
// 获得某个索引位置处的值
System.out.println(list.get(0));
// 修改某个索引位置处的值
System.out.println(list.set(0, "9"));
}
}
遍历: 一共四种,增加了for循环
public class ListTest2 {
public static void main(String[] args) {
List<String> list = new ArrayList<>(); // 经典代码
list.add("1");
list.add("2");
list.add("3");
list.add("2");
System.out.println(list);
// for
for (int i = 0; i < list.size(); i++) {
String temp = list.get(i);
System.out.println(temp);
}
// iterator
Iterator it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
// foreach
for (String s : list) {
System.out.println(s);
}
// lambda
list.forEach(System.out::println);
}
}
两个实现类: ArrayList、LinkedList——>底层实现不同,业务场景也不同
适合的应用场景:
ArrayList
public class ArrayListDemo1 {
public static void main(String[] args) {
// 1. 创建一个ArrayList的集合对象
ArrayList list = new ArrayList();
list.add("黑马");
list.add(666);
list.add('a');
System.out.println(list);
// 2. 约束集合存储的范围
ArrayList<String> list1 = new ArrayList<String>(10);
System.out.println(list1);
ArrayList<String> list2 = new ArrayList<>(); // JDK1.7后支持
list1.add("2");
list1.add("xx");
// System.out.println(list1[0]); // 0没有这种中操作
// 3. 在集合中的某个索引位置添加一个数据——这个位置处要有值
// list1.add(3, "aaa"); // 报错,意思就是超过范围了
System.out.println(list1);
// 4. 根据索引获取集合中某个索引位置处的值
System.out.println(list1.get(0));
System.out.println(list1.size());
// 5. 删除元素
// 5.1 根据索引删除某个元素,并返回被删除的元素
System.out.println(list1.remove(1));
// 5.2 根据元素删除
System.out.println(list1.remove("2"));
// 尖括号中必须是引用数据类型,若要存入int、char等基本数据类型,要使用包装类
ArrayList<Integer> list3 = new ArrayList<>();
list3.add(1);
list3.add(2);
list3.add(3);
System.out.println(list3.get(0));
System.out.println(list3.remove(0));
// list3.remove(2); // 想要删除的是特定对象,是引用数据类型,跟元素的具体内容无关,而是需要地址一致
}
}
LinkedList
public class LinkedListTest {
public static void main(String[] args) {
// 创建队列
LinkedList<String> queue = new LinkedList<>();
// 入队操作
queue.addLast("1");
queue.addLast("2");
queue.addLast("3");
queue.addLast("4");
System.out.println(queue);
// 出队操作
System.out.println(queue.removeFirst());
System.out.println(queue);
// 创建栈
LinkedList<String> stack = new LinkedList<>();
// 压栈(push)
stack.addFirst("1"); // pop
stack.addFirst("2");
stack.addFirst("3");
stack.addFirst("4");
stack.push("5");
System.out.println(stack); // [4, 3, 2, 1]——实现了倒序
// 出栈(pop)
System.out.println(stack.pop());
System.out.println(stack.removeFirst()); // 4
System.out.println(stack.removeFirst()); // 3
System.out.println(stack); // [2, 1]这里要非常注意
}
}
是一个接口
特点:——无序、不重复、无索引
实现类:
public class SetTest1 {
public static void main(String[] args) {
// 创建一个对象
// Set set = new HashSet<>(); // 创建一个HashSet的集合对象。经典代码 // [1, 2, 3, 4, 5]HashSet [888, 777, 666, 555],根据底层原理,这里的结果可以解释为由哈希值计算出来的顺序决定,不是表面上看到的升序还是降序
// Set set = new LinkedHashSet<>(); // 创建一个LinkedHashSet的集合对象 // [5, 2, 1, 3, 4]
Set<Integer> set = new TreeSet<>(); // 创建一个TreeSet的集合对象 // [1, 2, 3, 4, 5]默认升序排序 [555, 666, 777, 888]
// set.add(5);
// set.add(2);
// set.add(1);
// set.add(3);
// set.add(4);
// set.add(1);
set.add(666);
set.add(555);
set.add(555);
set.add(888);
set.add(888);
set.add(777);
set.add(777);
System.out.println(set);
// Set常营的方法,基本上是Collection提供的!!自己几乎没有新增方法
}
}
哈希值:
底层原理: 底层有索引,只不过外界用不了
基于哈希表实现——增删改查数据性能都较好的数据结构
JDK8之前,哈希表=数组+链表
JDK8开始,哈希表=数组+链表+红黑树(可以子平衡的二叉树)
HashSet集合去重复的机制
HashSet集合默认不能对内容一样的两个不同对象去重复(两个内容一样的学生能够对象,不能去重复!)
想要去重复的话——必须重写对象的hashCode()和equals()方法
有序、不重复、无索引
底层原理:
排序(默认升序排序)、不重复、无索引
底层原理: 红黑树
注意:
排序数字和字符串都可以
自定义对象:①让自定义类实现Comparable接口,重写里面的CompareTo方法;②通过调用TreeSet集合有参构造器,设置Comparator对象,指定比较规则
并发:多件事进行
例如:遍历集合时,同时删除集合中的数据,程序就会出现并发修改异常的错误——使用迭代器的方法删除元素/for循环i–/for循环反向循环
增强for循环和Lambda表达式无法解决并发修改异常
可变参数
Collections
概念: 操作集合的工具类
常用静态方法:
public class CollectionsTest1 {
public static void main(String[] args) {
// 1. addAll(Collection super T> c, T...elements)
List<String> names = new ArrayList<>();
Collections.addAll(names, "11", "22", "33");
System.out.println(names);
List<String> names2 = new ArrayList<>();
names2.add("44");
// names2.addAll("55", "66"); // 会报错!!可以添加对象,但不可以这样直接赋值,要使用Clllections工具类里面的addAll()方法
System.out.println(names2);
names.addAll(names2);
System.out.println(names);
// 2. shuffle(List> list)打乱List集合中的元素顺序
Collections.shuffle(names);
System.out.println(names);
// 3. sort(List list)对List集合中的元素进行升序排序
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(2);
list.add(1);
Collections.sort(list);
System.out.println(list);
// 4. 自定义类型的对象比较,重写Comparator()
}
}
双列集合,格式:{key1=value1, key2=value2, key3=value3……},一次需要存一对数据作为一个元素
“key=value”称为一个键值对/键值对对象/一个Entry对象,Map集合也被叫做“键值对集合”
Map集合的所有键不允许重复,值可以重复,键和值是一一对应的
应用场景:
需要存储一一对应的数据时,就可以使用Map集合
Map集合的体系(特点:特点都是由键决定的)
特点:
public class MapTest1 {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>(); // 经典代码:无序、不重复、无索引 {null=null, 手表=220, Java=2, 手机=2}
// Map map = new LinkedHashMap<>(); // 有序、不重复、无索引 {手表=220, 手机=2, Java=2, null=null}
// Map map = new TreeMap<>(); // 可排序序、不重复、无索引 键是数值可排序的
map.put("手表", 100);
map.put("手表", 220); // 键不可以重复,后面的会覆盖前面的
map.put("手机", 2);
map.put("Java", 2); // 值可以重复
map.put(null, null); // 可以存放null值
System.out.println(map);
}
}
常用方法:
public class MapTest2 {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>(); // 经典代码:无序、不重复、无索引 {null=null, 手表=220, Java=2, 手机=2}
map.put("手表", 100);
map.put("手表", 220); // 键不可以重复,后面的会覆盖前面的
map.put("手机", 2);
map.put("Java", 2); // 值可以重复
map.put(null, null); // 可以存放null值
System.out.println(map);
// size():获取集合的大小
System.out.println(map.size());
// clear():清空集合
// map.clear();
// System.out.println(map);
// isEmpty():判断集合是否为空,为空返回true
// System.out.println(map.isEmpty());
// get(Object key):根据键获取对应值
System.out.println(map.get("手机"));
System.out.println(map.get("")); // null
// remove(Object key):根据键删除整个元素(会返回键的值)
System.out.println(map.remove("手表"));
System.out.println(map);
// containsKey(Object key):判断是否包含某个键,包含返回true
System.out.println(map.containsKey("手表"));
System.out.println(map.containsKey("java")); // 精确匹配
// containsValue(Object value):判断是否包含某个值,包含返回true
System.out.println(map.containsValue(2));
// keySet():获取map集合全部键
Set<String> set = map.keySet();
System.out.println(set);
// values():获取全部值,返回是Cllection集合,值可重复
Collection<Integer> values = map.values();
System.out.println(values);
// 把其他map集合数据倒入自己map集合
Map<String, Integer> map1 = new HashMap<>();
map1.put("java1", 10);
map1.put("java2", 20);
Map<String, Integer> map2 = new HashMap<>();
map2.put("java2", 30);
map2.put("java3", 40);
map1.putAll(map2);
System.out.println(map1); // {java3=40, java2=30, java1=10}
System.out.println(map2); // {java3=40, java2=30}
}
}
Map集合的遍历方式
键找值:先获取Map集合全部键,再通过遍历键来找值
键值对:把“键值对”看成一个整体进行遍历
Lambda表达式:JDK1.8之后有的
public class MapTest3 {
public static void main(String[] args) {
// 准备一个map集合
Map<String, Double> map = new HashMap<>();
map.put("蜘蛛精", 166.3);
map.put("蜘蛛精", 169.7);
map.put("紫霞", 165.8);
map.put("至尊宝", 169.5);
map.put("牛魔王", 183.5);
System.out.println(map);
// 键找值遍历
Set<String> keys = new HashSet<>();
keys = map.keySet();
System.out.println(keys);
for (String key : keys) {
double values = map.get(key);
System.out.println(key + "====>" + values);
}
// 键值对entry对象
Set<Map.Entry<String, Double>> entries = map.entrySet();
for (Map.Entry<String, Double> entry : entries) {
String name = entry.getKey();
double height = entry.getValue();
System.out.println(name + ":" + height);
}
// Lambda
map.forEach((k, v) -> {
System.out.println(k + "--->" + v);
});
}
}
底层原理:
哈希表,Set集合的底层是基于Map实现的,只是Set集合中的元素只要键数据,不要值数据
HashMap的键依赖hashCode方法和equals方法保证键的唯一
底层原理:
哈希表+双向链表
底层原理:
基于红黑叔实现的排序
集合中的嵌套还是一个嵌套