目录
HashSet 扩容机制(首次16,有阈值*0.75,数组大小达到64,并且有节点后面有8个结点(先数组扩容),则进行树化)
为什么需要集合
集合框架图
Java_Collection方法
package com.edu.collection; import com.sun.xml.internal.ws.runtime.config.TubelineFeatureReader; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class Demo01 { public static void main(String[] args) { @SuppressWarnings({"all"}) List list = new ArrayList<>(); //add:添加元素 list.add("jack"); list.add(10);//相当于list.add(new Integer(10)) list.add(true); System.out.println("list= "+list); //list= [jack, 10, true] //remove删除元素 list.remove(0);//按索引删除第一个元素=>list= [10, true] System.out.println("list= "+list); list.remove("jack"); //按对象删除 //查找元素是否存在 contains 返回布尔值 System.out.println(list.contains("jack")); //size:获取元素个数 //isEmpty:判读是否为空 //clear:清空元素 //addAll:添加多个元素 List list2 = new ArrayList(); list2.add(2); list2.add(3); list.addAll(list2); System.out.println("list= "+list); //containsAll 判断多个元素是否存在 list.containsAll(list2); //removeAll 删除多个元素 list.removeAll(list2); } }
迭代器遍历(子接口也可以使用)
package com.edu.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo02 {
public static void main(String[] args) {
Collection col = new ArrayList();
col.add(new Book("三国演义","罗贯中",10.1));
col.add(new Book("小李飞刀","古龙",5.1));
col.add(new Book("红楼梦","曹雪芹",34.6));
//遍历集合
//1、先得到col的迭代器
Iterator iterator = col.iterator();
//2、使用while循环遍历
while (iterator.hasNext()){//判断是否有数据(必需)
Object next = iterator.next();//获取数据
System.out.println(next);
}
//快捷键 itit
//3、退出while循环后,这时iterator迭代器指向最后的元素
//iterator.next() 会抛出异常
//4.再次遍历,则要重置迭代器
iterator = col.iterator();
}
}
class Book{
private String name;
private String author;
private double price;
public Book(String name, String author, double price) {
this.name = name;
this.author = author;
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
}
List接口方法
package com.edu.list;
import java.util.ArrayList;
import java.util.List;
public class Demo01 {
@SuppressWarnings({"all"})
public static void main(String[] args) {
//List集合类中的元素有序(添加顺序和取出顺序一致)、而且可以重复
List arraysList = new ArrayList();
arraysList.add("jack");
arraysList.add("tom");
arraysList.add("mary");
arraysList.add("hasp");
arraysList.add("jack");//可用重复
System.out.println("list= "+arraysList);
//2、List的每个元素都有其对应的顺序索引,即支持索引
System.out.println(arraysList.get(2));
/*
常用方法
*/
List list = new ArrayList<>();
list.add("小张");
list.add("小明");
//在对应索引位置插入
list.add(1,"小李");
//批量加入,对应索引位置插入
list.addAll(1,arraysList);
//get,获取指定索引的元素
//indexOf,获取obj在集合中首次出现的位置
//lastIndexOf,获取最后出现的位置
//list.remove() 可以删对象,可以删索引
//set 指定index位置为ele,相当于替换
list.set(2,"小非");
//获取子集合 从索引1-2;
List list2 = list.subList(1,3);
System.out.println(list2);
}
}
List集合排序
package com.edu.list;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings({"all"})
public class Demo03 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(new Book("红楼梦","曹雪芹",100));
list.add(new Book("西游记","吴承恩",10));
list.add(new Book("水浒传","施耐庵",100));
list.add(new Book("西游记","吴承恩",10));
list.add(new Book("三国演义","罗贯中",20));
for (Object o:list){
System.out.println(o);
}
//对结合进行排序
sort(list);
System.out.println();
for (Object o:list){
System.out.println(o);
}
}
//静态方法
public static void sort(List list){
int listSize = list.size();
for (int i=0;i<listSize-1;i++){
for (int j=0;j<listSize-1-i;j++){
//取出对象
Book book1 = (Book)list.get(j);
Book book2 = (Book)list.get(j+1);
if(book1.getPrice()>book2.getPrice()){
list.set(j,book2);
list.set(j+1,book1);
}
}
}
}
}
class Book{
private String name;
private int price;
private String author;
public Book(String name, String author,int price) {
this.name = name;
this.price = price;
this.author = author;
}
@Override
public String toString() {
return "名称:"+name+"\t\t价格:"+price+"\t\t作者: "+author ;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
注意事项
ArrayList是线程不安全的,底层源码没有关键字修饰,可以加入空值 synchronized
多线程情况下,考虑使用Vector。
底层源码解析(Debug可以看见底层扩容过程!!)
LinkedList链表
package com.edu.list;
import javax.swing.plaf.synth.SynthSplitPaneUI;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.TooManyListenersException;
public class Demo04 {
@SuppressWarnings({"all"})
public static void main(String[] args) {
//模拟简单的双向链表
Node jack = new Node("jack");
Node tom = new Node("tom");
Node hsp = new Node("老汉");
//关联
jack.pre = null;
jack.next = tom;
tom.pre = jack;
tom.next = hsp;
hsp.pre = tom;
hsp.next = null;
//设置头,尾结点
Node first = jack;
Node last = hsp;
//遍历
while (true){
if (first==null){
break;
}
//输出信息
System.out.println(first);
first = first.next;
}
//插入对象
Node smith = new Node("smith");
smith.next = hsp;
smith.pre = tom;
tom.next = smith;
hsp.pre = smith;
first = jack;
while (true){
if (first==null){
break;
}
//输出信息
System.out.println(first);
first = first.next;
}
List list = new LinkedList();
list.add("jack");
list.add("ton");
Iterator iterator = list.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
for (Object i:list){
System.out.println(i);
}
for (int i=0;i<list.size();i++ ){
System.out.println(list.get(i));
}
}
}
//双向链表
class Node{
public Object item; //存数据
public Node next;
public Node pre;
public Node(Object name){
this.item = name;
}
@Override
public String toString() {
return "Node{" +
"item=" + item +
'}';
}
}
注意:LinkedList调用无参构造开辟空间为0,每次添加都是+1
Set接口基本介绍
package com.edu.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@SuppressWarnings({"all"})
public class Demo01 {
public static void main(String[] args) {
//Set常用方法
//无重复元素,而且存取无序,可以存null,每一次运行的取出顺序相同
//添加成功会返回一个boolean值
Set set = new HashSet();
set.add("jonh");
set.add("jonh");
set.add("lucky");
set.add("null");
System.out.println("set: "+set);
System.out.println("set: "+set);
//遍历
//1、迭代器
Iterator iterator = set.iterator();
while (iterator.hasNext()){
Object obj = iterator.next();
System.out.println("obj:"+obj);
}
//2、增强for循环(本质是迭代器)
for (Object j:set){
System.out.println("j:"+j);
}
//无法使用传统for循环,无法通过索引获取
//移除元素
set.remove("john");
//添加类对象,可以加进去
set.add(new Book("A"));
set.add(new Book("A"));
System.out.println("set: "+set);//set: [lucky, null, Book{name='A'}, Book{name='A'}, jonh]
//再加深 ,面试题
set.add(new String("HASP"));//ok
set.add(new String("HASP"));//加入不了, 因为hashSet添加的底层代码原因 String重写了equals方法
}
}
class Book{
private String name;
public Book(String name) {
this.name = name;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
'}';
}
}
HashSet 数组链表模拟
package com.edu.set;
public class Demo02 {
public static void main(String[] args) {
Node[] table = new Node[16];
Node jack = new Node("jack",null);
table[2] = jack;
Node tom = new Node("tom",null);
jack.next = tom;
}
}
class Node{
Object item;
Node next;
public Node(Object item, Node next) {
this.item = item;
this.next = next;
}
}
HashSet 扩容机制(首次添加元素扩容为16,有阈值*0.75,数组大小达到64,并且有节点后面有8个结点(先数组扩容),则进行树化)
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
//定义了一些辅助变量
Node<K,V>[] tab; Node<K,V> p; int n, i;
//判断当前的table是否为空,这个table再new对象时就已经初始化为空了,第一次添加元素时
//肯定为空
if ((tab = table) == null || (n = tab.length) == 0)
//然后进行table的扩容,其实resize()方法会返回一个已经扩容好的table返回
//其实n在第一次添加元素时就是16
n = (tab = resize()).length;
//这人的i = (n - 1) & hash就是通过运算得到一个值作为待存入元素存到table中的位置
//hash就是通过hash方法获得的
//所以再加入元素时先判断一下要加入的这个位置是不是为null,如果是的话就直接存进去
//否则的话就进入else
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
//1. 这下面的代码就是判断是不能加入还是挂载到要加入位置的尾部进行链表的形成
//2. 值得注意的是,当一个位置形成的链表的结点个数达到8并且table的长度大于64
//那么就会进行黑红树的转换
else {
//===================继续阅读之前你需要知道的======================
//1. 能进入到这个else语句那么就表示待添加元素key在table表中的i = (n - 1) & hash位置
//已经不为null了即就是这个位置已经有元素了,才会进入这个语句块进行判断。
//2. 在这儿会判断key与位置i = (n - 1) & hash已经存在的值相同不,如果相同就添加失败,否
//则就添加成功
//===============想必你应该知道了这个程序块大概是做些什么了,那就开始继续==========
//===============================================================================
//定义局部变量,作为辅助,(打过王者的都知道辅组也是很重要的,哈哈哈)
Node<K,V> e; K k;
//1.这个if语句的作用就是判断key即就是待添加的元素是不是与这个位置已经存在的元素是不是
//同的
//2.这个p在上面p = tab[i = (n - 1) & hash]这儿被赋值过,即就是指向位置i = (n - 1) &
//hash这个结点
//先判断hash值与key是否相同 ,不同时在判断key是否为空,且进行equals的判断
//这儿的equals绝对不能简单理解成时内容的判断,这个equals程序员可以添加自己的业务逻辑
//我认为 (k = p.key) == key当key是某个类对象得引用时,比较的是地址是否相同.
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//进行树的转换,转换条件上面有提到
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
//上面两个条件都不满足时,即就是不满足树结构的转换,以及不与位置[i = (n - 1) &
//hash这个结点元素相同
else {
//有一个死循环,退出的条件
//条件1:在要加入的位置i = (n - 1) & hash处所形成的链表没有一个结点与要加入的结点
//相同时,退出循环,此时就加在最末尾。添加成功
//条件2 :在要加入的位置i = (n - 1) & hash处所形成的链表有结点与要加入的结点相同
//此时退出循环,添加失败
for (int binCount = 0; ; ++binCount) {
//这是条件1
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
//这是条件2
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
//添加失败之后返回的oldValue
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
package com.edu.set;
import java.util.HashSet;
import java.util.Objects;
import java.util.Queue;
public class Demo03 {
@SuppressWarnings({"all"})
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Employee("milan",18));
hashSet.add(new Employee("milan2",28));
hashSet.add(new Employee("milan",18));
System.out.println(hashSet);
}
}
class Employee{
private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
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);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.edu.set;
import java.util.HashSet;
import java.util.Objects;
public class Demo04 {
@SuppressWarnings({"all"})
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Employee01("小米",new MyDate(2000,1,1)));
hashSet.add(new Employee01("小米",new MyDate(2000,1,1)));
hashSet.add(new Employee01("小米",new MyDate(2000,1,2)));
System.out.println(hashSet);
}
}
class MyDate{
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
public String toString() {
return "MyDate{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyDate myDate = (MyDate) o;
return year == myDate.year && month == myDate.month && day == myDate.day;
}
@Override
public int hashCode() {
return Objects.hash(year, month, day);
}
}
class Employee01{
private String name;
private MyDate birthday;
public Employee01(String name, MyDate birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee01 that = (Employee01) o;
return Objects.equals(name, that.name) && Objects.equals(birthday, that.birthday);
}
@Override
public int hashCode() {
return Objects.hash(name, birthday);
}
@Override
public String toString() {
return "Employee01{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}';
}
}