public class Demo3 {
public static void main(String[] args) {
//1. 准备一个集合
Collection collection = new ArrayList<>();
collection.add("java");
collection.add("python");
collection.add("c++");
collection.add("c#");
//2. 获取迭代器对象
Iterator iterator = collection.iterator();
//3. 使用迭代器遍历
while (iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
}
}
public class Demo4 {
public static void main(String[] args) {
//1. 准备一个集合
Collection collection = new ArrayList<>();
collection.add("java");
collection.add("python");
collection.add("c++");
collection.add("c#");
//2. 使用增强for循环遍历
for (String s : collection) {
System.out.println(s);
}
//3. 打印原来的
//增强for循环也可以遍历数组
int[] arr = {1,2,3};
for (int i : arr) {
System.out.println(i);
}
}
}
public class Demo5 {
public static void main(String[] args) {
//1. 准备一个集合
Collection collection = new ArrayList<>();
collection.add("java");
collection.add("python");
collection.add("c++");
collection.add("c#");
//2. Lambda表达式方式遍历集合
collection.forEach(e -> {
System.out.println(e);
});
}
}
public class Demo6 {
public static void main(String[] args) {
//1. 创建集合
Collection movies = new ArrayList<>();
movies.add(new Movie("《肖生克的救赎》", 9.7, "罗宾斯"));
movies.add(new Movie("《霸王别姬》", 9.6, "张国荣、张丰毅"));
movies.add(new Movie("《阿甘正传》", 9.5, "汤姆.汉克斯"));
System.out.println(movies);
//2. 遍历输出
//2-1 迭代器
Iterator iterator = movies.iterator();
while (iterator.hasNext()){
Movie next = iterator.next();
System.out.println(next);
}
//2-2 增强for
for (Movie movie : movies) {
System.out.println(movie);
}
//2-3 lambda
movies.forEach(e -> {
System.out.println(e);
});
}
}
使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。
public class Demo7 {
public static void main(String[] args) {
//1. 准备一个集合
ArrayList arrayList = new ArrayList<>();
arrayList.add("Java入门");
arrayList.add("宁夏枸杞");
arrayList.add("黑枸杞");
arrayList.add("人字拖");
arrayList.add("特级枸杞");
arrayList.add("枸杞子");
//删除所有带枸杞的
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if(next.contains("枸杞")){
iterator.remove();
}
}
System.out.println(arrayList);
}
}
特点:有序,可以重复
实现类:Arraylist集合丶LinkedList集合
数据结构:数组
特点:查询快,增加删除慢
使用场景:根据索引查询数据,数据量少
基于双链表实现的
特点:查询慢,增删相对较快,但对首尾元素进行增删改查的速度是极快的。
使用场景:
设计队列: 两端开口, 先进先出
设计栈: 一端开口, 先进后出
特点:无序,不可重复
常用实现类:HashSet(无序,不重复),LinkedHashSet(存取有序),TreeSet(可排序,不重复)
public class Demo1 {
public static void main(String[] args) {
testHashSet();
System.out.println("==========");
testLinkedHashSet();
System.out.println("==========");
testTreeSet();
}
//HashSet: 无序、没有索引、不可重复
private static void testHashSet() {
HashSet hashSet = new HashSet<>();
hashSet.add(44);
hashSet.add(33);
hashSet.add(11);
hashSet.add(22);
hashSet.add(22);
System.out.println(hashSet);//[33, 22, 11, 44]
}
//LinkedHashSet: 存取有序、没有索引、不可重复
private static void testLinkedHashSet() {
LinkedHashSet linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(44);
linkedHashSet.add(33);
linkedHashSet.add(11);
linkedHashSet.add(22);
linkedHashSet.add(22);
System.out.println(linkedHashSet);//[44, 33, 11, 22]
}
//TressSet: 排序、没有索引、不可重复
private static void testTreeSet() {
TreeSet treeSet = new TreeSet<>();
treeSet.add(44);
treeSet.add(33);
treeSet.add(11);
treeSet.add(22);
treeSet.add(22);
System.out.println(treeSet);//[11, 22, 33, 44]
}
}
1. 就是一个int类型的数值,Java中每个对象都有一个哈希值
2.Java中的所有对象,都可以调用Obejct类提供的hashCode方法,返回该对象自己的哈希值。
1.同一个对象多次调用hashCode()方法返回的哈希值是相同的。
2.不同的对象,它们的哈希值一般不相同,但也有可能会相同(哈希碰撞)极少概率。
3.Object的hashCode方法根据"对象地址值"计算哈希值
子类重写后的hashCode方法可以根据"对象属性值"计算哈希值
是由哈希表实现的
JDK8之前:数组+链表
JDK8之后:数组+链表+红黑树
当new HashSet();
1. 创建一个默认长度16的数组,默认加载因子为0.75,数组名为table
2.使用元素的哈希值对数组的长度求余计算出应存入的位置
3.判断当前的位置是否为NULL,如果是NULL之间存入
4.如果不是NULL,表示有元素,调用equals方法比较
如果相等,就不村;不相等,存入数组
JDK8之前,新元素存入数组,占老元素位置,老元素挂在下面
JDK8之后,新元素直接挂在老元素下面
无序:元素在数组的索引位置是由哈希函数计算产生的
不可重复:调用Equals比较
链表会过长,导致查询性能降低.扩容
负载因子 = 哈希表有效元素个数/哈希表长度
这个值越大说明冲突越严重
这个值越小说明冲突越小,数组利用率低
什么情况下需要扩容就根据负载因子决定
数组长度 * 负载因子 <= 保存元素个数 就需要扩容
数组长度16,负载因子 = 0.75(JDKHashMap默认的负载因子)
16 * 0.75 = 12 , 12<= 保存元素个数 就需要扩容
每次扩容为原来的2倍
1.闭散列
2.开散列
若出现哈希冲突,就让冲突变为链表
有一组数据[1,2,3,19,120,121]
1 % 101 = 1
2 % 101 = 2
3 % 101 = 3
19 % 101 = 19
120 % 101 = 19 ,就将120这个元素连接到19的后面
121 % 101 = 20
要是哈希表中某个位置冲突严重,每个元素取模后都是19,数组对应的链表长度过长,查找效率就会降低!!!
解决方法:
链表元素>=8 && 数组长度>=64, 就会将哈希冲突严重的链表变为红黑树!!!
二叉树:无序
小的存左边,大的存右边,相同则不存 如果数据已经排好序,那么存入二又树查找树,会形成类似链表结构,查询效率还是低 如果左、右子树的树高差比较大,那么导致左右子树不平衡,影响查询效率
当数据已经是排好序的,导致查询的性能与单链表一样,查询速度变慢!
有规律且相对平衡的二叉树 当插入一个元素,导致左右子树的树高差大于1。那么就会触发旋转 旋转分为左旋和右旋,用来保证左右子树的相对平衡
特殊的/自平衡的二又查找树,是计算机科学中用到的一种数据结构 1972年出现时被称为平衡二叉树,后来1978年被修改为如今的红黑树 红黑树不是高度平衡的,有自己保证平衡的规则(红黑规则),性能较好,红黑规则如下: 每一个节点都是红色或者黑色的 根节点必须是黑色的 两个红色节点不能相连 如果一个节点没有子节点,则该节点相应的指针属性为Nil (称为叶子结点),叶子结点是黑色的 对于每一个节点,到其所有后代叶节点的简单路径上,包含的黑色 节点数量相同红黑树是一种增删改查数据性能相对都较好的结构。
树的高度低,查找路径短,效率就高
LinkedHashSet是不可重复的,存取有序的,底层是基于哈希表(数组、链表、红黑树)实现的。
但是,它的每个元素都额外的多了一个双链表的机制记录它前后元素的位置。
1.不重复、存取有序
2.底层基于哈希表(数组+链表+红黑树),使用双向链表记录添加顺序。
特点:不重复、无索引、可排序(默认升序排序 ,按照元素的大小,由小到大排序)
底层是基于红黑树实现的排序
TreeSet 可排序、不重复、无索引 底层基于红黑树实现排序,排序规则认为属性是相同的对象则不存 TreeSet的排序 对于数值型Integer、Double,默认按照数值升序排列; 对于String类型数据,默认按照字典排序 对于自定义类,默认是无法排序的,需要我们指定排序规则 自然排序:自定义类实现Comparable接口,重写compareTo方法,指定排序规则 比较器排序:写在TreeSet构造参数中传递Comparator比较器对象,重写compare方法,指定排序规则
public class Demo4 {
public static void main(String[] args) {
//创建TreeSet
TreeSet treeSet = new TreeSet<>(new Comparator() {
@Override
public int compare(Teacher o1, Teacher o2) {
return o1.getAge() - o2.getAge();
}
});
//添加学生
treeSet.add(new Teacher("张三", 19));
treeSet.add(new Teacher("李四", 18));
treeSet.add(new Teacher("王五", 20));
treeSet.add(new Teacher("赵六", 17));
treeSet.add(new Teacher("赵六", 17));
//打印
for (Teacher teacher : treeSet) {
System.out.println(teacher);
}
}
}
class Teacher {
private String name;
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}