add()
, remove()
, set()
, get()
。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cotMTIEA-1640566300154)(E:[HanShunping] Java Collection\笔记\01.png)]
import java.util.ArrayList; import java.util.List; public class CollectionMethod { public static void main(String[] args) { List list = new ArrayList(); //add 添加元素 list.add("jack"); list.add(10); list.add(true); //remove 删除元素 list.remove(0); //删除第一个元素 list.remove(true); System.out.println(list); //contains 查找元素是否存在 System.out.println(list.contains("jack")); //size 获取元素个数 System.out.println(list.size()); //isEmpty 判断是否为空 System.out.println(list.isEmpty()); //clear 清空 list.clear(); //addAll 添加多个元素 List list2 = new ArrayList(); list2.add("wang"); list2.add(100); list.addAll(list2); //cintainsAll 查找多个元素是否都存在 list.containsAll(list2); //removeAll 删除多个元素 list.removeAll(list2); } }
iterator.hasNext()
:判断是否有下一个元素。
import java.util.ArrayList; import java.util.Iterator; public class CollectionIterator { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("Wang"); arrayList.add("Zhao"); arrayList.add("Qian"); //生成迭代器 Iterator iterator = arrayList.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } } }
for
循环增强 for
底层仍然是迭代器。
for(Object obj : arrayList){ System.out.println(obj); }
List
接口方法ArrayList
线程不安全,效率高Vector
线程安全LinkedList
线程不安全add(int index, Object ele)
:在 index 位置插入 ele 元素
addAll(int index, Collection eles)
:从 index 位置开始将 eles 中所有元素添加进去
get(int index)
:获取指定位置的元素
indexOf(Object obj)
:返回 obj 首次出现的位置
lastIndexOf()
:
remove(int index)
:删除指定位置的元素,并返回此元素
set(int index, Object ele)
:设置指定位置的元素为 ele
subList(int fromIndex, int toIndex)
:返回从 fromIndex 到 toIndex 位置的子集合
ArrayList
底层结构和源码分析ArrayList
中维护了一个Object
类型的数组elementData
, transient Object[] elementData
。ArrayList
对象时,如果使用的是无参构造器,则初始elementData
容量为0,第一次添加数据时扩容elementData
为10,如需要再次扩容,则按照 1.5倍 增加。elementData
容量为指定大小,如需要扩容,则按照 1.5倍 增加。Vector
底层结构和源码分析Vector
中维护了一个Object
类型的数组elementData
, transient Object[] elementData
。Vector
对象时,如果使用的是无参构造器,则默认elementData
容量为10,如需要扩容,则按照 2倍 增加。elementData
容量为指定大小,如需要扩容,则按照 2倍 增加。LinkedList
底层结构和源码分析LinkedList
的底层操作机制LinkedList
底层维护了一个双向链表first
和last
分别指向首节点和尾节点Node对象
里面又维护了prev
,next
,item
三个属性,其中通过prev
指向前一个,next
指向后一个节点,最终实现双向链表LinkedList
的元素的添加和删除不是通过数组完成的,相对说效率较高Set
接口和常用方法HashSet
HashSet
实现了Set
接口HashSet
实际上是HashMap
null
值,但只能有一个HashSet
不保证元素是有序的,取决于hash
后,再确定索引结果Java
面试题:Set set = new HashSet(); set.add(new Dog("tom")); //Ok set.add(new Dog("tom")); //Ok set.add(new String("hsp")); //Ok set.add(new String("hsp")); //false
Node[] table = new Node[16]; Node john = new Node("john", null); table[2] = john; Node jack = new Node("jack", null); john.next = jack; //jack挂载到john后 class Node{ Object item; Node next; //单向链表 public Node(Object item, Node next){ this.item = item; this.next = next; } }
HashSet
扩容机制分析HashSet
的添加元素底层是如何实现的(hash()+equals()
)
HashSet
底层是HashMap
hash
值,然后转成索引值table
,看这个索引值位置是否已经存放有元素equals
比较,如果相同就放弃添加,若果不同,则向后添加java8
中,如果一条链表的元素个数超过默认8,且table的大小大于等于默认64时,则进行树化(红黑树)分析HashSet
的扩容和转成红黑树的机制
HashSet
底层是HashMap
,第一次添加时,table
数组扩容到16,临界值是16*0.75(加载因子)=12table
数组到了临界值12,就会扩容到16×2(2倍扩容)=32,新的临界值就是24,以此类推java8
中,只有一条链表的元素个数超过默认8,且table
的大小大于等于默认64时,才会进行树化(红黑树),否则仍采用数组扩容机制加载因子为何是0.75?
hash
表(table
)数据密度越大,发生碰撞的几率越高,数组(table
)中的链表越容易长,造成查询或插入时的比较次数增多,性能会下降。hash
桶中遵循泊松分布,当桶中元素到达8个的时候,概率已经变得非常小,也就是说用0.75作为加载因子,每个碰撞位置的链表长度超过8个是几乎不可能的。HashSet
最佳实战import java.util.HashSet; import java.util.Objects; public class HashSetExc { public static void main(String[] args) { HashSet hashSet = new HashSet(); hashSet.add(new Employee("milan",18)); hashSet.add(new Employee("jackie",28)); hashSet.add(new Employee("milan",18)); // 若果不重写equals方法,则三个对象是不同对象都能被添加 // 重写后名字年龄相同的对象视为相同对象,则第三个对象无法添加 System.out.println("hashSet == "+ hashSet); } } class Employee{ private String name; private int age; public Employee() { } public Employee(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 boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Employee employee = (Employee) o; return age == employee.age && Objects.equals(name, employee.name); } @Override public int hashCode() { return Objects.hash(name, age); } }
Map
接口特点Map
用于保存具有映射关系的数据:Key-Value
Map
中的Key
和Value
可以是任何引用类型的数据Map
中的Key
不允许重复,原因和HashSet
一样Map
中的Value
可以重复Map
中的Key
可以为null
,value
也可以为null
,注意key
为null
只能有一个String
类作为Map
中的key
key
和value
存在单向一一对应关系,即通过指定key
总能找到对应的value
Map
的k-v
存放在Node
中Map
的常用方法put
:添加remove
:根据key
删除映射关系get
:根据key
获取值size
:获取元素个数isEmpty
:判断是否为空clear
:清除containsKey
:查找key
是否存在HashMap
扩容机制HashSet
相同
HashMap
底层维护了Node
类型的数组table
,默认为null
HashMap
对象时,将加载因子(loadfactor
)初始化为0.75k-v
时,通过key
的hash
值得到在table
的索引,然后判断该索引处是否有元素,如果么有则直接添加;如果有则继续判断该元素的key
是否和准备加入的元素key
相等,如果相等则替换value
,如果不相等需要判断是树结构还是链表结构做出相应处理。如果添加时发现容量不够,则需要扩容table
容量为16,临界值12java8
中,如果一条链表的元素个数超过默认8,且table
的大小大于等于默认64时,则进行树化(红黑树)HashTable
基本介绍k-v
null
HashMap
基本一致HashMap
线程不安全,HashTable
线程安全(加了同步synchronized
)HashTable
扩容Hashtable$Entry[]
,初始化大小为1111*0.75=8
2倍+1
***的方式扩容HashMap
与HashTable
的对比:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W4RRxSla-1640566300157)(https://www.bilibili.com/video/BV1YA411T76k?p=43)]
Collection
接口
List
(有序可重复)
LinkedList
【底层维护了一个双向链表】ArrayList
【底层维护了Object
类型的可变数组】Set
(无序不可重复)
HashSet
【底层是HashMap
,维护了哈希表,即数组+链表+红黑树】TreeSet
LinkedHashSet
【维护了数组+双向链表】Map
HashMap
【底层是哈希表(jdk1.7
:数组+链表,jdk1.8
:数组+链表+红黑树)】TreeMap
LinkedHashMap
Properties
TreeSet
介绍new TreeSet()
时,仍然是无序的TreeSet
提供的一个构造器,可以传入比较器,从而使得其有序TreeMap
介绍与TreeSet
基本一致,区别在于TreeMap
存入的是键值对k-v
new TreeSet()
时,仍然是无序的TreeSet
提供的一个构造器,可以传入比较器,从而使得其有序Collections
工具类Collections
是一个操作Set,List,Map
等集合的工具类import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; public class Collections_ { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add("Jack"); arrayList.add("Tom"); arrayList.add("Moon"); arrayList.add("McGrady"); System.out.println(arrayList); //reverse(List):翻转其中元素 Collections.reverse(arrayList); System.out.println(arrayList); //shuffle(List):随机排序 Collections.shuffle(arrayList); System.out.println(arrayList); //sort(List):根据元素自然顺序排序 Collections.sort(arrayList); System.out.println(arrayList); //sort(List,Comparator):根据指定的比较器对其排序 Collections.sort(arrayList, new Comparator() { @Override public int compare(Object o1, Object o2) { return ((String)o1).length() - ((String)o2).length(); } }); System.out.println("按字符串长度排序:"+arrayList); //swap(List,int,int):交换i和j处的元素 Collections.swap(arrayList,0,3); System.out.println(arrayList); //Object max(Collection):根据元素自然排序,返回集合中最大元素 //Object max(Collection,Comparator): //Object min(Collection): //Object min(Collection,Comparator): //int frequency(Collection,Object):返回指定元素的出现次数 //void copy(List dest,List src):将src内容复制到dest中,注意dest必须大于等于src的长度 //boolean replaceAll(List list, Object oldVal, Object newVal):用新值替换list中的旧值 } }
import java.util.ArrayList; @SuppressWarnings({"all"}) public class Homework01 { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); arrayList.add(new News("新冠确诊病例超千万,数百万印度教信徒赴恒河\"圣浴\"引民众担忧")); arrayList.add(new News("男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生")); int size = arrayList.size(); //倒序遍历 for (int i = size - 1; i >= 0; i--) { //System.out.println(arrayList.get(i)); News news = (News)arrayList.get(i); System.out.println(processTitle(news.getTitle())); } } //专门写一个方法,处理现实新闻标题 process处理 public static String processTitle(String title) { if(title == null) { return ""; } if(title.length() > 15) { return title.substring(0, 15) + "..."; //[0,15) } else { return title; } } } /** * 按要求实现: * (1) 封装一个新闻类,包含标题和内容属性,提供get、set方法,重写toString方法,打印对象时只打印标题; * (2) 只提供一个带参数的构造器,实例化对象时,只初始化标题;并且实例化两个对象: * 新闻一:新冠确诊病例超千万,数百万印度教信徒赴恒河“圣浴”引民众担忧 * 新闻二:男子突然想起2个月前钓的鱼还在网兜里,捞起一看赶紧放生 * (3) 将新闻对象添加到ArrayList集合中,并且进行倒序遍历; * (4) 在遍历集合过程中,对新闻标题进行处理,超过15字的只保留前15个,然后在后边加“…” * (5) 在控制台打印遍历出经过处理的新闻标题; */ class News { private String title; private String content; public News(String title) { this.title = title; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } @Override public String toString() { return "News{" + "title='" + title + '\'' + '}'; } }
import java.util.ArrayList; import java.util.Iterator; @SuppressWarnings({"all"}) public class Homework02 { public static void main(String[] args) { ArrayList arrayList = new ArrayList(); Car car = new Car("宝马", 400000); Car car2 = new Car("宾利",5000000); //1.add:添加单个元素 arrayList.add(car); arrayList.add(car2); System.out.println(arrayList); //* 2.remove:删除指定元素 arrayList.remove(car); System.out.println(arrayList); //* 3.contains:查找元素是否存在 System.out.println(arrayList.contains(car));//F //* 4.size:获取元素个数 System.out.println(arrayList.size());//1 //* 5.isEmpty:判断是否为空 System.out.println(arrayList.isEmpty());//F //* 6.clear:清空 //System.out.println(arrayList.clear();); //* 7.addAll:添加多个元素 System.out.println(arrayList); arrayList.addAll(arrayList);//2个宾利 System.out.println(arrayList); //* 8.containsAll:查找多个元素是否都存在 arrayList.containsAll(arrayList);//T //* 9.removeAll:删除多个元素 //arrayList.removeAll(arrayList); //相当于清空 //* 使用增强for和 迭代器来遍历所有的car , 需要重写 Car 的toString方法 for (Object o : arrayList) { System.out.println(o);// } System.out.println("===迭代器==="); Iterator iterator = arrayList.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); System.out.println(next); } } } /** * 使用ArrayList 完成对 对象 Car {name, price} 的各种操作 * 1.add:添加单个元素 * 2.remove:删除指定元素 * 3.contains:查找元素是否存在 * 4.size:获取元素个数 * 5.isEmpty:判断是否为空 * 6.clear:清空 * 7.addAll:添加多个元素 * 8.containsAll:查找多个元素是否都存在 * 9.removeAll:删除多个元素 * 使用增强for和 迭代器来遍历所有的car , 需要重写 Car 的toString方法 */ class Car { private String name; private double price; public Car(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } @Override public String toString() { return "Car{" + "name='" + name + '\'' + ", price=" + price + '}'; } }
import java.util.*; @SuppressWarnings({"all"}) public class Homework03 { public static void main(String[] args) { Map m = new HashMap(); m.put("jack", 650);//int->Integer m.put("tom", 1200);//int->Integer m.put("smith", 2900);//int->Integer System.out.println(m); m.put("jack", 2600);//替换,更新 System.out.println(m); //为所有员工工资加薪100元; //keySet Set keySet = m.keySet(); for (Object key : keySet) { //更新 m.put(key, (Integer)m.get(key) + 100); } System.out.println(m); System.out.println("=============遍历============="); //遍历 EntrySet Set entrySet = m.entrySet(); //迭代器 Iterator iterator = entrySet.iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry)iterator.next(); System.out.println(entry.getKey() + "-" + entry.getValue()); } System.out.println("====遍历所有的工资===="); Collection values = m.values(); for (Object value : values) { System.out.println("工资=" + value); } } } /** * 按要求完成下列任务 * 1)使用HashMap类实例化一个Map类型的对象m,键(String)和值(int)分别用于存储员工的姓名和工资, * 存入数据如下: jack—650元;tom—1200元;smith——2900元; * 2)将jack的工资更改为2600元 * 3)为所有员工工资加薪100元; * 4)遍历集合中所有的员工 * 5)遍历集合中所有的工资 */
HashSet
和TreeSet
分别如何实现去重?HashSet
的去重机制:hashcode()+equals()
,底层先通过存入的对象运算得到一个hash
值,通过hash
值得到对应的索引,如果发现table
索引值所在的位置没有数据,就直接存放;如果有数据,就使用equals()
比较,比较后如果不相同就加入,否则不加入。TreeSet
的去重机制:如果传入了一个Comparator
匿名对象,就使用实现的compare()
去重,如果方法返回0,就认为是相同的元素,不添加;如果没有传入Comparator
匿名对象,则以添加的对象实现的Comparable
接口的compareTo()
方法去重。import com.hspedu.map_.TreeMap_; import java.util.TreeMap; import java.util.TreeSet; @SuppressWarnings({"all"}) public class Homework04 { public static void main(String[] args) { TreeSet treeSet = new TreeSet(); treeSet.add("hsp"); treeSet.add("tom"); treeSet.add("king"); treeSet.add("hsp");//加入不了, 因为String的compareTo()方法比较的是内容 System.out.println(treeSet); } }
//import java.util.TreeSet; //@SuppressWarnings({"all"}) //public class Homework05 { // public static void main(String[] args) { // TreeSet treeSet = new TreeSet(); // //分析源码 // //add 方法,因为 TreeSet() 构造器没有传入Comparator接口的匿名内部类 // //所以在底层 Comparable<? super K> k = (Comparable<? super K>) key; // //即 把 Perosn转成 Comparable类型 // treeSet.add(new Person());//ClassCastException. // treeSet.add(new Person());//ClassCastException. // treeSet.add(new Person());//ClassCastException. // treeSet.add(new Person());//ClassCastException. // treeSet.add(new Person());//ClassCastException. // // System.out.println(treeSet); // // } //} // //class Person implements Comparable{ // // @Override // public int compareTo(Object o) { // return 0; // } //}
import java.util.HashSet; import java.util.Objects; @SuppressWarnings({"all"}) public class Homework06 { public static void main(String[] args) { HashSet set = new HashSet();//ok Person p1 = new Person(1001,"AA");//ok Person p2 = new Person(1002,"BB");//ok set.add(p1);//ok set.add(p2);//ok p1.name = "CC"; set.remove(p1); //找不到1001,CC的hash值所表示的索引,因为AA-》CC,不改变1001,AA的hash值 System.out.println(set);//2 set.add(new Person(1001,"CC")); System.out.println(set);//3 set.add(new Person(1001,"AA")); System.out.println(set);//4 } } class Person { public String name; public int id; public Person(int id, String name) { this.name = name; this.id = id; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return id == person.id && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, id); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", id=" + id + '}'; } } //===========================结果================================= /*[Person{name='BB', id=1002}, Person{name='CC', id=1001}] [Person{name='BB', id=1002}, Person{name='CC', id=1001}, Person{name='CC', id=1001}] [Person{name='BB', id=1002}, Person{name='CC', id=1001}, Person{name='CC', id=1001}, Person{name='AA', id=1001}] */