后端开发学习日志(集合篇)

目录

集合的框架体系

Collection

Collection接口和常用方法

使用迭代器遍历

List接口方法

List三种遍历方式

ArrayList 注意事项  

ArrayList底层结构和源码分析

List实现类–Vector

Vector与ArrayList的比较

List实现类-LinkedList

LinkedList基本介绍

LinkedList底层结构

ArrayList和LinkedList比较

Set接口方法

Set接口基本介绍

Set接口的常用方法

Set接口的遍历方式

Set接口常用方法

Set接口遍历方式

Set实现类–HashSet

 Set实现类–LinkedHashSet

Set实现类–TreeSet

基本介绍

Map接口

Map中的EntrySet

Map接口常用方法

遍历方式

HashMap

底层机制​编辑

扩容机制

HashTable

Properties

基本介绍

TreeMap

基本介绍

如何选择集合实现类


集合类的特点:提供一种存储空间的存储模型,存储的数据容量可以随时发生改变

集合与数组区别
数组:
长度开始时必须指定,而且一旦指定,不能修改
保存的必须为同一类型的元素
使用数组进行增加/删除元素比较麻烦
集合:
可以动态保存任意多个对象,使用比较方便
提供了一系列方便操作对象的方法: add、remove、set、get
使用集合添加,删除新元素的代码简洁明了

集合的框架体系

单列集合

双列集合

 解读:

1。集合主要是两组(单列集合,双列集合)
2.Collection接口有两个重要的子接口 List Set,他们的实现子类都是单列集合
3. Map接口的实现子类是双列集合,存放的K-V

Collection

Collection接口实现类的特点

public interface Collection<E> extends Iterable<E>

特点:

1.collection实现子类可以存放多个元素,每个元素可以是Object

2.有些Collection的实现类,可以存放重复的元素,有些不可以

3.有些Collection的实现类,有些是有序的(List),有些不是有序的(Set)

有序:指存取顺序一致

4.Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的

Collection接口和常用方法

Collection接口常用方法,以实现子类ArrayList来演示. collectionMethod.java 

1) add:添加单个元素
2) remove:删除指定元素
3) contains:查找元素是否存在
4) size:获取元素个数
5) isEmpty:判断是否为空
6) clear:清空
7)addAll:添加多个元素
8) containsAl:查找多个元素是否都存在
9) removeAll:删除多个元素
10)说明:以ArrayList实现类来演示.

import java.sql.Array;
import java.util.ArrayList;
import java.util.List;

public class CollectionMethod {
    public static void main(String[] args) {
        List list = new ArrayList();
        //  1) add:添加单个元素
        list.add("Jack");
        list.add(10);//list.add(new Integer(10))
        list.add(true);
        System.out.println("list="+list);


       // list.remove(0);  删除第一个元素`
        list.remove(true);//删除指定的元素
        System.out.println("list="+list);
        //  3) contains:查找元素是否存在
        System.out.println(list.contains("Jack"));//查找元素是否存在
        //4) size:获取元素个数
        System.out.println(list.size());
        //5) isEmpty:判断是否为空
        System.out.println(list.isEmpty());
        //6) clear:清空
        list.clear();
        System.out.println("list="+list);
        //7)addAll:添加多个元素
        ArrayList list2 = new ArrayList();
        list2.add("红楼梦");
        list2.add("三国演义");
        list.addAll(list2);
        System.out.println("list="+list);
        //8) containsAl:查找多个元素是否都存在
        System.out.println(list.containsAll(list2));
        //9) removeAll:删除多个元素
        list.removeAll(list2);
        System.out.println("list="+list);
    }
}

输出结果为: 

list=[Jack, 10, true]
list=[Jack, 10]
true
2
false
list=[]
list=[红楼梦, 三国演义]
true
list=[]

使用迭代器遍历

基本介绍

Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
Iterator 的结构
Iterator 仅用于遍历集合,Iterator 本身并不存放对象。

迭代器的执行原理

lterator iterator = coll.iterator();//得到一个集合的迭代器
//hasNext():判断是否还有下一个元素
while(iterator.hasNext()){
//next():①指针下移②将下移以后集合位置上的元素返回
System.out.println(iterator.next0));}

iterator接口方法

注意:
在调用it.next()方法之前必须要调用it.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。

import java.awt.print.Book;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionIterator {
    public static void main(String[] args) {
        @SuppressWarnings({"all"})//警告抑制
        Collection col = new ArrayList();
        col.add(new book("三国演义","罗贯中",20.2));
        col.add(new book("红楼梦","曹雪芹",150.3));
        col.add(new book("小李飞刀","古龙",25.3));
        //System.out.println("col="+col);
        //遍历col集合
        //1,得到集合对应的迭代器
        Iterator iterator = col.iterator();
        //2,使用while循环遍历
        while (iterator.hasNext()){//判断是否还有数据
            //返回下一个元素,类型是Object
            Object obj = iterator.next();//编译类型是Object,运行类型取决于对象实际类型
            System.out.println("obj=" + obj);
        }
        //快捷键,快速生成while循环 ==>  itit
        //Ctrl + J 显示所有快捷键
//        while (iterator.hasNext()) {
//            Object next =  iterator.next();
//        }
        //3. 当退出while循环后,这是iterator迭代器,指向最后的一个元素
        //iterator.next();//NoSuchElementException
        //4.如果希望再次遍历,
        iterator = col.iterator();
        System.out.println("第二次遍历");
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println("obj=" + next);
        }
    }
}
class book {
    public String name;
    public String author;
    public double price;

    public book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                '}';
    }
}

List接口方法

List接口是 Collection 接口的子接口

List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复。
List集合中的每个元素都有其对应的顺序索引,即支持索引。
List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
List接口常用的实现类有很多,常用的有:ArrayList、LinkedList 和 Vector。

import java.util.ArrayList;
import java.util.List;

public class Demo01 {
    public static void main(String[] args) {
//List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复。
        List list = new ArrayList();
        list.add( "jack");
        list.add( "tom");
        list.add( "mary");
        list.add("hsp");
        list.add("tom ");
        System.out.println("list=" + list);
        //2. List集合中的每个元素都有其对应的顺序索引,即支持索引//索引是从@开始的
        System.out.println(list.get(3));//hsp

    }
}

List 集合里添加了一些根据索引来操作集合元素的方法
1) void add(int index, Object ele):在index位置插入ele元素
2) boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
3) Object get(int index):获取指定index位置的元素
4)int indexOf(Object obj):返回obj在集合中首次出现的位置
5) int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
6) object remove(int index):移除指定index位置的元素,并返回此元素
7) Object set(int index,Object ele):设置指定index位置的元素为ele相当于是替换.
8) List subList(int fromlndex, int tolndex):返回从fromIndex到tolndex位置的子集合

import java.util.ArrayList;
import java.util.List;

public class Demo02 {
    public static void main(String[] args) {
        //1) void add(int index, Object ele):在index位置插入ele元素
        List list = new ArrayList();
        list.add("张三丰");
        list.add("贾宝玉");
        //在index=1的位置插入一个对象
        list.add(1,"韩顺平");
        System.out.println("list="+list);
        //2) boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
        List list2 = new ArrayList();
        list2.add( "jack");
        list2.add( "tom");
        list.addAll(1,list2);
        System.out.println("list="+list);
        //3) Object get(int index):获取指定index位置的元素
        System.out.println(list.get(0));
        //4)int indexOf(Object obj):返回obj在集合中首次出现的位置
        System.out.println(list.indexOf("tom"));
        //5) int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
        list.add("韩顺平");
        System.out.println("list="+list);
        System.out.println(list.lastIndexOf("韩顺平"));
        //6) object remove(int index):移除指定index位置的元素,并返回此元素
        list.remove(0);
        System.out.println("list="+list);
        //7) Object set(int index,Object ele):设置指定index位置的元素为ele相当于是替换.
        list.set(1,"玛丽");
        System.out.println("list="+list);
        //8) List subList(int fromlndex, int tolndex):返回从fromIndex到tolndex位置的子集合
        List returnlist = list.subList(0, 2);
        System.out.println("returnlist"+returnlist);


    }
}

List三种遍历方式

三种遍历方式,List下所有的实现类都可以用这三种方式遍历元素。

1.使用iterator

lterator iter = col.iterator();
while(iter.hasNext(0){
object o = iter.next();
}

2.使用增强for

for(Object o:col){}

3.使用普通for

for(int i=0;i<list.size();i++){
Object object = list.get(0);
System.out.println(object);

public class ListFor {
    public static void main(String[] args) {
        //List list = new ArrayList();
        //List list = new Vector();
        List list = new LinkedList();
        

        list.add("jack");
        list.add("tom");
        list.add("鱼香肉丝");
        list.add("北京烤鸭");
        //遍历
//1 . 迭代器
        System.out.println("===迭代器===");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            System.out.println(next);
        }
        //2 . 增强for循环
        System.out.println("===增强for===");
//        list.forEach(System.out::println);
        for (Object o : list) {
            System.out.println("o+"+o);
        }
        //3 . 普通for
        System.out.println("===普通for===");
        for (int i = 0; i < list.size(); i++) {
            System.out.println("对象="+list.get(i));
        }
    }
}

ArrayList 注意事项  

1.ArrayList 可以加入null,并且多个

2.ArrayList是由数组来实现的

3.ArrayList基本等同Vector,除了 ArrayList是线程不安全(执行效率高),在多线程情况下,不建议使用ArrrayList。

import java.util.ArrayList;

@SuppressWarnings({"all"})
public class ArrayListDetail {
    public static void main(String[] args) {

        //ArrayList是线程不安全的,可以看源码  没有  synchronized
        /*
        public boolean add(E e) {
                ensureCapacityInternal(size + 1);// Increments modCount!
                elementData[size++] = e;
         return true;
         }
         */


        ArrayList arrayList = new ArrayList();
        arrayList.add(null);
        arrayList.add("jack");
        arrayList.add(null);
        System.out.println(arrayList);

    }

}

ArrayList底层结构和源码分析

import java.util.ArrayList;

@SuppressWarnings({"all"})
public class ArrayListSource {
    public static void main(String[] args) {

//        源码分析

//        使用无参构造器创建ArrayList对象
        ArrayList list = new ArrayList();

//        使用for循环给list集合添加 1-10 数据
        for (int i = 0; i <= 10; i++) {
            list.add(i);
        }

//        使用for循环给list集合添加 11-15 数据
        for (int i = 11; i<=15;i++){
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);

        for (Object o : list) {
            System.out.println(o);
        }
    }

}

无参构造器源码分析

有参构造器

List实现类–Vector

 1) Vector类的定义说明

public class vector<E>

extends AbstractList<E>
implements List<E>,RandomAccess,cloneable,Serializable

2) Vector底层也是一个对象数组,protected Object[ ]、elementData;
3) Vector是线程同步的,即线程安全, Vector类的操作方法带有synchronized

public synchronized E get(int index) {
if (index >= elementCount)
throw new ArraylndexOutOfBoundsException(index);return elementData(index);
}

4)在开发中,需要线程同步安全时,考虑使用Vector

源码分析

import java.util.Vector;

public class ListVector {
        public static void main(String[] args) {
            //无参构造器
            Vector vector = new Vector();
            Vector vector1 = new Vector(10);
            //1. new Vector()底层
        /*
            无参构造:
            public Vector() {
                this(10);
            }
            有参构造:
            public Vector(int initialCapacity) {
                this(initialCapacity, 0);
            }
         */
            for (int i = 0; i < 10; i++) {
                vector.add(i);
            }
            //2. vector.add()
        /*
            2.1 add方法添加数据到vector集合
            public synchronized boolean add(E e) {
                modCount++;
                ensureCapacityHelper(elementCount + 1);
                elementData[elementCount++] = e;
                return true;
            }
            2.2 确定是否需要扩容,判断条件:  if (minCapacity - elementData.length > 0)
            private void ensureCapacityHelper(int minCapacity) {
                // overflow-conscious code
                if (minCapacity - elementData.length > 0)
                    grow(minCapacity);
            }
         */
            vector.add(100);
            //3.需要扩容的vector 两倍扩容
            // capacityIncrement:指定扩容大小,默认为0
            //扩容算法:int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
        /*
            private void grow(int minCapacity) {
                // overflow-conscious code
                int oldCapacity = elementData.length;
                int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                                 capacityIncrement : oldCapacity);
                if (newCapacity - minCapacity < 0)
                    newCapacity = minCapacity;
                if (newCapacity - MAX_ARRAY_SIZE > 0)
                    newCapacity = hugeCapacity(minCapacity);
                elementData = Arrays.copyOf(elementData, newCapacity);
            }
         */
        }
    }

Vector与ArrayList的比较

Vector:
线程安全(同步)效率:安全,效率不高
扩容倍数:如果有参构造1.5倍,如果是无参,那么为第一次10,从第二次开始按1.5倍扩容

ArrayList:
线程安全(同步)效率:不安全,效率高
扩容倍数:如果是无参,默认10,满后,就按2倍扩容。如果指定大小,则每次直接按2倍扩容

List实现类-LinkedList

LinkedList基本介绍

1.LinkedList底层实现了双向链表和双端队列特点

2.可以添加任意元素(元素可以重复),包括null

3.线程不安全,没有实现同步

LinkedList底层结构

1.LinkedList 底层维护了一个双向链表
2.LinkedList中维护了两个属性 first 和 last 分别指向 首节点和尾节点
3.每个节点(Node对象),里面又维护了prev、next、item、三个属性,其中通过prev指向前一个通过next指向后一个节点。最终实现双向链表。
4.LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
 

mport java.util.Iterator;
import java.util.LinkedList;

public class LinkedListDemo {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();st="+linkedList);
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        System.out.println("linkedList="+linkedList);
        linkedList.remove();
        System.out.println("linkedList="+linkedList);
        Object set = linkedList.set(0, 666);
        System.out.println(set);
        System.out.println("linklist="+linkedList);
        Object o = linkedList.get(1);
        System.out.println(o);
        System.out.println("====linkedList迭代器遍历");
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);
        }
        System.out.println("====增强for循环遍历");
        for (Object o1 : linkedList) {
            System.out.println(o1);
        }
        System.out.println("====传统for循环");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }

    }
}

输出结果为:

linkedList=[1, 2, 3]
linkedList=[2, 3]
2
linklist=[666, 3]
3
====linkedList迭代器遍历
666
3
====增强for循环遍历
666
3
====传统for循环
666

ArrayList和LinkedList比较

底层结构增删的效率改查的效率
ArrayList可变数组

较低

数组扩容

较高
LinkedList双向链表较高,通过链表追加.较低

如何选择ArrayList和LinkedList:
1)如果我们改查的操作多,选择ArrayList
2)如果我们增删的操作多,选择LinkedList
3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另
外一个模块是LinkedList,也就是说,要根据业务来进行选择

Set接口方法

Set接口基本介绍

1.无序(添加和取出的顺序不一致),没有索引

2.不允许重复元素,所以最多包含一个null

3.JDK API中Set接口的实现类有

Set接口的常用方法

和List接口一样, Set接口也是Collection的子接口,因此,常用方法和Collection接口一样。

Set接口的遍历方式

同Collection的遍历方法一样,因为set接口是Collection接口的子接口。

1.可以使用迭代器

2.增强for

3.不能使用索引的方式遍历

Set接口常用方法

Method and DescriptionModifier and Type
size()int
isEmpty()boolean
contains()boolean
iterator()lterator<E>
toArray()object[]
toArray(T[])T[]
add(E)boolean
remove(Object)boolean
containsAll(Collection<?>)boolean
addAll(Collection<? extends E>)boolean
retainAll(Collection<?>)boolean
removeAll(Collection<?>)boolean
clear()void
equals(Object)boolean
hashCode()int
spliterator()Spliterator<E>


Set接口遍历方式

1.以Set 接口的实现类 HashSet 来讲解Set接口的方法
2. set接口的实现类的对象(Set接口对象),不能存放重复的元素,可以添加一个null
3.set接口对象存放数据是无序的(添加的顺序和取出的顺序不一致
4.取出的顺序虽然不是添加的顺序,但是它是固定的

@SuppressWarnings({"all"})
public class SetMethod {
    public static void main(String[] args) {

        Set set = new HashSet();
        set.add( "john");
        set.add("lucy" );
        set.add( "john");//重复
        set.add( "jack");
        set.add(null);
        set.add(null);//再次添加null
        for (int i = 0; i < 5; i++) {
            System.out.println("set = "+set);
        }

        //遍历
        //方法1:使用迭代器
        System.out.println("======使用迭代器======");
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            Object obj = iterator.next();
            System.out.println("obj=" +obj);
        }

        set.remove(null);

        //方法2:增强for
        System.out.println("========使用增强for=====");
        for (Object o :set){
            System.out.println("o="+o);
        }

        //set接口对象  不能通过索引来获取


    }
}

Set实现类–HashSet

1.HashSet 实现了Set接口

2.HashSet 实际上是HashMap(源码如下)

public HashSet() {
    map = new HashMap<>();
}

3.只能存放一个null值

4.HashSet不保证元素是有序的,取决于hash值,再确定索引的结果

5.不能有重复元素/对象

HashSet set = new HashSet();


        //1.在执行add方法后,会返回一个boolean值
        //2.如果添加成功,返回true,否则返回false
        //3.可以通过remove指定删除哪个对象
        System.out.println(set.add("Tom")); // true
        System.out.println(set.add("Mike"));  // true
        System.out.println(set.add("john"));  // true
        System.out.println(set.add("Tom"));  // false
        System.out.println(set.add("Jerry")); //true
        set.remove("Tom");
        System.out.println(set);//[Mike, john, Jerry]


        set = new HashSet();
        System.out.println("set="+set);
        //hashSet 不能添加相同的元素数据
        set.add("lucy");  // true
        set.add("lucy");  // false
        set.add(new Dog("tom"));  //true
        set.add(new Dog("tom"));  //true
        System.out.println(set);


        System.out.println(set.add(new String("kobe")));//true
        System.out.println(set.add(new String("kobe")));//false
    }
}
class Dog{//定义Dog类
    private String name;

    public Dog(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                '}';

 Set实现类–LinkedHashSet

基本介绍
LinkedHashSet 是 HashSet的子类
LinkedHashSet 底层是一个LinkedHashMap,底层维护了一个 数组 + 双向链表
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存得。
LinkedHashSet 不允许添加重复元素

在LinkedHashSet中维护了一个hash表和双向链表(LinkedHashSet 有 head和tail)
每一个节点有 before和after属性,这样可以形成双向链表
在添加一个元素时,先求hash值,在求索引,确定该元素在table的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加【原则和hashset一样】)
这样遍历LinkedHashSet 也能确保插入顺序和遍历顺序一致

代码示例

public class LinkedHashSet_ {
    public static void main(String[] args) {
        LinkedHashSet set = new LinkedHashSet();
        set.add(new String("AA"));
        set.add(456);
        set.add(456);
        set.add(new Customer("刘",1001));
        set.add(123);
        set.add("kobe");
        for (int i = 0; i < 3; i++) {
            set.add(new Customer("kobe",24));
        }
        System.out.println(set);

    }
}
    class Customer{
        private String name;
        private int no;

        public Customer(String name, int no) {
            this.name = name;
            this.no = no;
        }

        @Override
        public String toString() {
            return "Customer{" +
                    "name='" + name + '\'' +
                    ", no=" + no +
                    '}';
        }

        @Override
        public int hashCode() {
            return 1;
        }
    }

Set实现类–TreeSet

基本介绍

不允许添加重复元素,不允许添加 null

无序(没有按照输入顺序进行输出)

遍历结果有顺序

底层为排序二叉树(红黑树),且采用中序遍历得到结果 (左节点,根节点,右节点)

代码示例

public class TreeSet_ {
    public static void main(String[] args) {

        //TreeSet treeSet = new TreeSet();
        //使用匿名内部类实现Comparator接口,并重写compare方法,指定排序方法
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length() - ((String)o2).length();
            }
        });

        //添加数据
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("sp");
        treeSet.add("abc");//tom 和 abc 长度相等,key相等,添加失败
        System.out.println(treeSet);//[sp, tom, jack]


        treeSet = new TreeSet();
        treeSet.add(new C(1));
        treeSet.add(new C(2));
        treeSet.add(new C(1));
        System.out.println(treeSet);
    }
}
    class C  implements Comparable<C>{
        int num;


        public C(int num) {
            this.num = num;
        }

        public int compareTo( C c) {
            return this.num - c.num;
        }

        @Override
        public String toString() {
            return "C{" +
                    "num=" + num +
                    '}';
        }
    }

Map接口

                                                                    Map体系的继承图

特点:

1.Map用于保存具有映射关系的数据:key-value(双列元素)

2.Map中的 key 和 value 可以是任何引用类型的数据,会封装到 HashMap$Node对象中

3.Map 中的 Key 不允许重复,原因和HashSet 一样,当有相同的key时,等价于替换

4.Map 中的 value 可以重复

5.Map 的key 可以为 null,value 也可以为null,注意 key 为null的只能有一个。

6.常用String类作为Map 的key,因为String类重写了HashCode()和equals().具体情况具体分析可以使用任意类型。

7.key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value

8.Map存放数据的 key-value 示意图,一对 k-v 是放在一个Node中的,又因为Node实现了 Entry接口,有些书上也说,一对k-v是一个Entry

代码示例

public class Map_ {
        public static void main(String[] args) {
            Map map = new HashMap();
            map.put("no1","小贤");
            map.put("no2","小芸");
            map.put("no1","g");
            map.put("no3","g");
            map.put(null, null);//OK
            map.put(null,"456");//等价于替换
            map.put("no4",null);//OK
            map.put(1,"张三");
            map.put(new Object(),"李四");
            System.out.println("map="+map);
            System.out.println(map.get("no3"));
        }
    }

Map中的EntrySet

帮助理解Map的第8个特点(Map中只有Entry内部类,EntrySet 、KeySet、Values是其实现类HashMap中的内部类):

1.k-v 最后是 HashMap$Node node = newNode(hash, key, value, null);
2.k-v 为了方便程序员的遍历,还会创建EntrySet 集合,该集合存放的元素的类型 Entry,而一个3.Entry对象就有k,v 即: transient Set<Map.Entry<K,V>> entrySet;
4.在entrySet中,定义的类型是Map.Entry ,但是实际上存放的还是 HashMap$Node,这是因为 HashMap$Node implements Map.Entry
5.这样当把HashMap$Node 对象存放在 EntrySet ,就方便我们的遍历 ,因为Map.Entry提供了重要方法K getKey(); V getValue();,Node对象没有这两个方法。

Map接口常用方法

1.put:添加

2.remove:根据键删除映射关系

3.get:根据键获取值

4.size:获取元素个数

5.isEmpty:判断个数是否为0

6.clear:清除

7.containsKey:查找键是否存在

代码示例:

public class MapMethod {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("xian", "芸");
        map.put("no1","RNG");
        map.put("空",null);
        map.put(null,"yy");
        map.put(null,null);
        System.out.println(map);

        map.remove(null);
        System.out.println(map);

        Object val = map.get("no1");
        System.out.println("val="+val);

        System.out.println("k-v="+map.size());

        System.out.println(map.isEmpty());

        map.clear();
        System.out.println("map="+map);

        map.put("xian", "芸");
        map.put("no1","RNG");
        map.put("空",null);
        map.put(null,"yy");
        map.put(null,null);
        System.out.println(map.containsKey("xian"));


    }
}

遍历方式

共有六种,取k-v对有四种,取值有两种

//1.先取出所有的key,通过key取key-value
Set keySet = map.keySet();
//1.1 增强for循环
System.out.println("========第一种方式========");
for (Object key : keySet) {
    System.out.println(key+"-"+map.get(key));
}
//1.2 迭代器
System.out.println("========第二种方式==========");
Iterator iterator = keySet.iterator();
while (iterator.hasNext()) {
    Object key =  iterator.next();
    System.out.println(key+"-"+map.get(key));
}
//2. 把所有的values取出
Collection values = map.values();
//2.1 增强for
System.out.println("=========第三种方式============");
values.forEach(System.out::println);
//2.2 迭代器
System.out.println("============第四种方式===========");
Iterator iterator1 = values.iterator();
while (iterator1.hasNext()) {
    Object next = iterator1.next();
    System.out.println(next);
}
//3. 通过EntrySet来获取k-v
Set entrySet = map.entrySet();
//3.1 增强for
System.out.println("===========第五种方式============");
for (Object entry : entrySet) {
    //转换为Map.Entry对象
    Map.Entry entry1 = (Map.Entry) entry;
    System.out.println(entry1.getKey()+"-"+entry1.getValue());
}
//3.2 迭代器
System.out.println("=========第六种方式=========");
Iterator iterator2 = entrySet.iterator();
while (iterator2.hasNext()) {
    Object next =  iterator2.next();
    System.out.println(next.getClass());//class java.util.HashMap$Node
    Map.Entry entry1 = (Map.Entry) next;
    System.out.println(entry1.getKey()+"-"+entry1.getValue());
}

HashMap

特点:

1.Map接口的常用实现类:HashMap、Hashtable和Properties
2.HashMap是Map接口使用频率最高的实现类。
3.HashMap是以key-value对的方式来存储数据(HashMap$Node类型)。
4.Key不能重复,但是值可以重复,允许使用null键和null值
5.如果添加相同的key,则会覆盖原来的key-value,等同于修改(key不会替换,val会替换)
6.与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的。(数组+链表+红黑树)
7.HashMap没有实现同步,因此是线程不安全的,方法上没有做同步互斥操作,没有synchronized

底层机制

1.(k,v)是一个Node实现了Map.Entry<K,V>,查看 HashMap的源码可以看到

2.jdk7.0的hashmap底层实现[数组+链表], jdk8.0底层[数组+链表+红黑树

扩容机制

与HashSet扩容机制相同

1.HashMap底层维护了Node类型的数组table,默认为null
2.当创建对象时,将加载因子(loadfactor)初始化为0.75
3.当添加 key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没4.有元素直接添加。如果该索引处有元素,继续判断该元素的key是否和准备加入的key相同,如果相等,则直接替换value;如果不相等需要判断是树结构还是链表,做出相应处理。如果添加时发现容量不够,则需扩容。
5.第一次添加,则需要扩容table容量为16,临界值(threshold)为12 (16 *0.75)
6.以后再扩容,则需要扩容table容量为原来的2倍,临界值为原来的2倍,即24,依次类推
7.在Java8中,如果一条链表的元素个数超过 TREEIFY_THRESHOLD(默认是8),并且table的大小 >= MIN_TREEIEF_CAPACITY(默认是64),就会进行树化(红黑树)

HashTable

基本介绍
存放的元素是键值对:K-V
Hashtable的键和值都不能为null,否则会抛出NullPointerException
Hashtable使用方法基本上和 hashMap一样
Hashtable是线程安全的(synchorized),hashMap 是线程不安全的

Hashtable table = new Hashtable();
table.put("john",100);
//table.put(null,100);   //NullPointerException
//table.put("join",null);  //NullPointerException
table.put("lucy",100);
table.put("lic",100);
table.put("lic",80); // 替换
table.put("hello1",1);
table.put("hello2",1);
table.put("hello3",1);
table.put("hello4",1);
table.put("hello5",1);
table.put("hello6",1);
table.put("hello7",1);
System.out.println(table);
/*
Hashtable底层:
1. 底层有一个数组 Hashtable$Entry[]  初始化大小为11
2. 临界值 threshold 8 = 11 * 0.75
3. 扩容:按照自己的扩容机制运行
4. put()中发现无相同元素时,执行 addEntry(hash, key, value, index); 添加 k-v 封装到 Entry
5. 当 if(count >= threshold) 满足时,没加之前table的count,就进行扩容
6. 按照 int newCapacity = (oldCapaticy << 1 ) + 1;  即[old*2+1]的大小扩容
*/
————————————————
版权声明:本文为CSDN博主「Shane_Cheng0202」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Shane_Cheng0202/article/details/123338648

Properties

基本介绍

Properties类继承HashTable类并且实现了Map接口,也是使用一种键值对的形式来保存数据。
他的使用特点和Hashtable类似
Properties 还可以从 xxx.properties 文件中,加载数据到Properties类对象,并进行读取和修改
说明:xxx.properties 文件通常作为配置文件
 

Properties properties = new Properties();
properties.put("john",100);
//        properties.put(null,100);  //NullPointerException
//        properties.put("john",null); //NullPointerException
properties.put("lucy",100);
properties.put("lic",100);
properties.put("lic",88);

System.out.println(properties);

//        通过 key 获取对应的值
System.out.println(properties.get("lic"));
//        删除
properties.remove("lic");
System.out.println(properties);

//        修改
properties.put("john","约翰");
System.out.println(properties);

TreeMap

基本介绍

唯一

有序(按照升序或降序排列)

底层:二叉树,key遵照二叉树特点

key对应的类型内部一定要实现比较器(内部比较器,外部比较器自选)

代码示例:

public class TreeMap_ {
    public static void main(String[] args) {

//       使用默认构造器,创建TreeMap
//        TreeMap treeMap = new TreeMap();

//
        TreeMap treeMap = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
//                按照传入的 k(String) 的大小进行排序
//                return ((String) o2).compareTo((String) o1);
//                按照字符串长度大小排序
                return ((String) o1).length() - ((String) o2).length();


            }
        });
        treeMap.put("jack","杰克");
        treeMap.put("tom","汤姆");
        treeMap.put("wkliul","拉拉");
        treeMap.put("smith","史密斯");
        treeMap.put("smith","123");
        System.out.println(treeMap.size());
        System.out.println(treeMap);
    }
}

如何选择集合实现类

在开发中,选择什么集合实现类,主要取决于业务操作特点,然后根据集合实现类特性进行选择,分析如下:

1)先判断存储的类型(一组对象[单列]或一组键值对[双列)

2)一组对象[单列]:Collection接口

允许重复:List
增删多:LinkedList [底层维护了一个双向链表]
改查多:ArrayList [底层维护Object类型的可变数组]
不允许重复: Set
无序:HashSet[底层是HashMap,维护了一个哈希表即(数组+链表+红黑树)]
排序:TreeSet
插入和取出顺序一致: LinkedHashSet,维护数组+双向链表

3)一组键值对: Map

键无序: HashMap [底层是:哈希表 jdk7: 数组+链表,jdk8:数组+链表+红黑树]
键排序:TreeMap
健插入和取出顺序一致:LinkedHashMap
读取文件:Properties

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值