LinkedList集合:
java.util.LinkedList 集合数据存储的结构底层是一个链表结构,是一个双向链表结构,方便元素的添加和删除。开发中对链表集合的元素大量的都是采用首尾结点操作(添加和删除):常用的API方法如下:
- public void addFirst(E e):将指定元素插入到首节点位置
- public void addLast(E e):将指定的元素插入到尾节点的位置上
- public E getFirst():获取首节点的元素
- public E getLast():获取尾节点的元素
- public E removeFirst():删除首节点元素
- public E removeLast():删除尾节点元素
- public E pop():从此列表所表示的堆栈中弹出一个元素(首元素)
- public void push(E e):将元素推入到此列表所表示的堆栈当中(尾元素)
- public boolean isEmpty():如果此列表为空返回true.
-
public static void demo1() { // public void addFirst(E e):将指定元素插入到首节点位置 // public void addLast(E e):将指定的元素插入到尾节点的位置上 // public void push(E e):将元素推入到此列表所表示的堆栈当中(首元素) LinkedList<String> strings = new LinkedList<>(); strings.addFirst("a"); strings.addFirst("b"); strings.addFirst("c"); System.out.println(strings);//[c, b, a] strings.addFirst("d"); System.out.println(strings);//[d, c, b, a] strings.addLast("g"); System.out.println(strings);//[d, c, b, a] strings.push("t"); System.out.println(strings);//[t, d, c, b, a, g] } public static void demo2(){ //public E removeFirst():删除首节点元素 //public E removeLast():删除尾节点元素 //public E pop():从此列表所表示的堆栈中弹出一个元素(首元素) LinkedList<String> strings = new LinkedList<>(); strings.addFirst("a"); strings.addFirst("b"); strings.addFirst("c"); System.out.println(strings);//[c, b, a] System.out.println(strings.getFirst());//c System.out.println(strings.getLast());//a System.out.println(strings.pop());//c System.out.println(strings.getFirst());//b //strings.clear(); // 清空集合当中的元素,再次获取直接抛出java.util.NoSuchElementException // java.util.NoSuchElementException } public static void demo3(){ //public E removeFirst():删除首节点元素 //public E removeLast():删除尾节点元素 //public boolean isEmpty():如果此列表为空返回true. LinkedList<String> strings = new LinkedList<>(); strings.addFirst("a"); strings.addFirst("b"); strings.addFirst("c"); System.out.println(strings);//[c, b, a] System.out.println(strings.removeFirst());//c System.out.println(strings.removeLast());//a System.out.println(strings);//b System.out.println(strings.isEmpty());//false System.out.println(strings.removeFirst());//b //System.out.println(strings.removeLast());//a System.out.println(strings.isEmpty());//true }
Linkedlist集合的特点:
- 底层是链表结构,增删快,查询慢
- 里面包含了大量的首尾节点的操作
- 允许所有元素(包括 null)
- 此实现不是同步的。如果多个线程同时访问一个链接列表,而其中至少一个线程从结构上修改了该列表,则它必须保持外部同步
- 元素是有序的。
LinkedList是List的子类,List当中的方法LinkedList都是可以使用的。我们只了解LinkedList独有的方法,
在开发当中,LinkedList集合也可以作为堆栈、队列结构使用(了解)
Set接口:
java.util.Set接口和 java.util.List接口是一样的,都是继承自Collection接口,它与Collection接口中的方法基本一样,没有对Collection接口进行功能上的扩展,只是比Collection接口更加严格,与List接口不同的是,Set接口中的元素是无序的,并且都是以某种规则保证存入的元素不重复。
Set接口有很多个子类,我们主要介绍两个重要的子类:java.util.HashSet和java.util.LinkedHashSet
Set接口特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通的for循环进行遍历,可用迭代器和增强for循环进行元素的获得。
HahSet集合的特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通的for循环进行遍历
3.是一个无序的集合,存储的元素顺序和取出元素的顺序可能不一致
4.底层是一个哈希表结构(查询速度非常的快)java.util.HashMap支持的。
5.根据对象的哈希值来确定元素在集合当中的存储位置,因此它具有良好的存取和查找的性能。保证元素唯一性的方式依赖于hashCode和equals
哈希值:
是十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)。是由Object类中有一个方法,可以获取对象的哈希值int hashCode()返回对象的哈希码值。
查看源码:public native int hashCode();
native:代表的是该方法调用的是本地操作系统中的方法。
哈希表:
JDK1.8之前:哈希表=数组+链表 即使用链表处理哈希冲突,同一哈希值的链表都存储在一个链表里,但是当 位于一个链中的元素较多时,即hash值相等的元素较多时,通过key值依次查找的效率很低下。
JDK1.8之后:哈希表=数组+链表
哈希表=数组+红黑树;
如果链表的长度超过了8位,那么就会把链表结构转换成红黑树结构。这样的好处是大大减少了查找的时间
JDK1.8之后引入的红黑树结构大大优化了HashMap的性能,那么对于我们来讲保证HashCode元素唯一不重复,其实是根据对象的hashCode和equals方法来决定的,如果我们往集合当中存储的是自定义的对象,需要保证对象的唯一性,就必须重写HashCode和equals方法,来自定义当前对象的比较方式。
HashSet存储自定义类型的元素
一般需要重写对象当中的hashCode和equals方法。建立自己的比较方式。才能保证HashSet集合中元素的唯一性。
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (this == o) {
return true;
}
// 向下转型 类型判断
if (o instanceof Student) {
Student student = (Student)o;
// 同名同年龄的人为同一个人 true
return student.getName().equals(name) && student.getAge() == age;
}
return false;
}
@Override
public int hashCode(){
// 使用Objects类中的hash方法
return Objects.hash(name,age);
}
LinkedHashSet集合:
hashset保证元素的唯一,可是存进去的元素是没有顺序的,那么如何保证存进去的元素是有序的?
在java.util.HashSet类的下面还有一个子类java.util.LinkedHashSet,它是链表和哈希表的组合一个数据存储结构。
LinkedHashSet底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表,用来记录元素的存储的顺序,来保证元素的有序。
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,
后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,
即按照将元素插入到 set 中的顺序(插入顺序)进行迭代。注意,插入顺序不 受在 set 中重新插入的 元素的影响。
public static void main(String[] args) {
// 构建一个HashSet集合对象
HashSet<String> hashSet = new HashSet<>();
hashSet.add("www");
hashSet.add("zhiyou100");
hashSet.add("com");
hashSet.add("abc");
hashSet.add("abc");
System.out.println(hashSet);// [com, abc, www, zhiyou100] 无序的 不重复的
// 构建一个LinkedHashSet集合对象
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("www");
linkedHashSet.add("zhiyou100");
linkedHashSet.add("com");
linkedHashSet.add("abc");
linkedHashSet.add("abc");
linkedHashSet.add("java");
linkedHashSet.add("python");
// [www, zhiyou100, com, abc, java, python]
System.out.println(linkedHashSet);// [www, zhiyou100, com, abc] 有序的,不重复的
}
可变参数:
在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数的数据类型一致,那么我们可以简化成如下格式:
修饰符 返回值类型 方法名(参数类型...形参名){
//...
}
其实上面的格式完全等价于:
修饰符 返回值类型 方法名(参数类型[]...参数名){
//...
}
只是后面的写法,在方法调用的时候,必须传递一个数组类型,而前者可以直接传递参数数据。
JDK1.5之后,出现的这种简化操作。”...“用在参数上,我们称之为可变参数。
可变参数的原理:
可变参数底层是定义了一个数组,根据传递参数的个数不同,会创建不同长度的数组,来存储这些参数
传递的参数个数,可以是0个(不传递),1,2,...多个
同样是代表数组 ,但是在方法上调用这个带有可变参数时,不用创建数组,而是直接将数组当中的元素作为实 际参数进行传递,其实编译生成的class文件,本质是将这些元素封装都数组当中。再进行数据传递,这些动作都在编译生成.class文件的时候,自动完成了。
public static void add(int... arr) {
//System.out.println(arr);// [I@1b6d3586 底层就是一个数组
//System.out.println(arr.length);//0
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println(sum); // 30
/*
可变参数的终极写法 不建议用
int[] 无法转型为 Object[], 因而被当作一个单纯的数组对象 ; Integer[] 可以转型为 Object[], 可以作为一个对象数组。
*/
//public static void methodFinal(Object ... obj){}
}
可变参数的注意事项:
1. 一个方法的参数列表,只能有一个可变参数
2. 如果方法的参数有多个,类型不止一种,那么可变参数必须写在参数列表的末尾位置
3.调用一个被重载的方法时,如果此调用既能够和固定参数的重载方法匹配,也能够与可变长参数的重载方法匹配,则选择固定参数的方法:
Collections集合工具类:
常用功能:
java.util.Collections是集合工具类,用来操作集合对象中的元素,方法如下
|
public static <T> void shuffle(List<?> list) 打乱集合中的元素顺序 |
/*
public static <T> boolean addAll(Collection<? super T> c,T... elements):往集合中一次性添加多个元素。
public static <T> void shuffle(List<?> list) 打乱集合中的元素顺序。
*/
ArrayList<String> strs = new ArrayList<>();
// 往集合当中存储元素
/* strs.add("abc");
strs.add("小孙");
strs.add("小刘");
strs.add("小赵");*/
// 使用一下Collections集合工具类中的addAll()
// 所有通用的 Collection 实现类(通常通过它的一个子接口间接实现 Collection)
Collections.addAll(strs, "abc","小孙","小刘","小赵","a",new String());
System.out.println(strs);// [abc, 小孙, 小刘, 小赵]
System.out.println("====================");
// 打乱顺序 public static <T> void shuffle(List<?> list)
Collections.shuffle(strs);
System.out.println(strs);// [小刘, 123, 小赵, a, 小孙, abc]
|
public static void sort(List<T> list, Comparator<? super T> c)
|
/*
public static <T> void sort(List<T> list):将集合中的元素按照默认规则排序。
public static <T> void sort(List<T> list,Comparator<? super T> c)`:将集合中的元素按照指定的规则进行排序。
*/
public class Demo02Collections {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(123);
list01.add(127);
list01.add(125);
list01.add(126);
System.out.println(list01);// [123, 127, 125, 126]
System.out.println("==============================");
// 使用集合工具类Collections中的sort方法
Collections.sort(list01);
System.out.println(list01);// [123, 125, 126, 127]
System.out.println("==============================");
ArrayList<String> list02 = new ArrayList<>();
Collections.addAll(list02, "a","c","ab","c","d","abc","ac","ba","abcd");
System.out.println(list02);// [a, c, ab, c, d]
Collections.sort(list02);
System.out.println(list02);
System.out.println("---------------------------------------");
ArrayList<Student> list03 = new ArrayList<>();
list03.add(new Student("小孙", 20));
list03.add(new Student("小王", 21));
list03.add(new Student("小赵", 18));
list03.add(new Student("小周", 15));
System.out.println(list03);
Collections.sort(list03);
System.out.println(list03);
//Comparator
// 重写排序规则
@Override
public int compareTo(Student o) {
// return 0:代表的是两个元素相同
// 自定义排序规则:按照年龄进行排序
// this参数,o参数
// this.getAge() - o.getAge()// 升序排序
// o.getAge() - this.getAge() 降序排序
return o.getAge() - this.getAge();// 降序排序
}