欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java的collection集合/set容器/list容器/map容器

程序员文章站 2022-06-16 23:38:36
...

一、collection集合【父类】

collection是父类 父类的方法子类全都可以使用

集合和数组的区别

1、数组 长度固定
集合 长度不固定

2、数组中存储的数据是同一类型的
集合存储的一定是对象 不过对象是任意类型的
list.add(“abc”)

什么时候用集合?
当对象很多的时候(对象很多?不存在的…

collection集合的方法
①、如何知道添加完到底有没有?直接输出对象

Collection c=new ArrayList();

以前直接输出对象 然后输出结果是类名@内存地址
这里是打印集合 把集合中的元素以数组形式打印出来

②、一般方法(不带All的方法)
add() 添加 可以添加任意类型的对象
remove() 删除
contains() 判断集合中是否包含某个对象 返回boolean
size() 返回此列表的元素数

③、全部方法(带All的方法)
addAll() 添加全部 将collection2的所有元素添加到collection1的尾部 并且内容允许重复
containsAll() A.containsAll(B)判断集合A里是否包含集合B中的所有元素 返回boolean
removeAll() A.removeAll(B)移除A中包含在B中的所有元素 即 移除集合A和集合B共同的元素
retainAll() A.retainAll(B)保留A中包含在B中的所有元素 即 保留集合A和集合B共同的元素

二、list【子类,继承自collection】

List容器的特点

1、元素存储和取出顺序是有序的
2、有角标 可以进行精确地定位
3、允许重复的元素

这是List集合的特有方法★因为能精确定位

list.size() 获取该list集合的总长度
for (int i=0;i<list.size();i++)
{
    System.out.println(list.get(i));
}

List接口支持对元素进行curd(create update read delete)操作
注:只有List集合可以增删改查 因为它有角标

经典for循环用迭代器遍历集合元素示例:
for (Iterator<MyStudent> it = list.iterator(); it.hasNext();)
{
    MyStudent s=it.next();
    System.out.println(s);
}

1、ArrayList

ArrayList特点★
1、定位一个元素很快 因为有索引
2、增加和删除一个元素很慢 因为底层是数组实现 效率较低
它采用的是数组结构
方法:
获取元素 get(int index) :
只是获取 不进行修改

MyStudent a=list.get(0);

修改元素 set(int index,E element) :
(获取为get 修改为set)

list.set(0,new MyStudent("学生M",17));

2、LinkedList

LinkedList特点★ LinkedList:链接链表 简称链表
数据域→指针域
1、查找操作费时
2、添加和删除操作 简单
它采用的是链表结构
方法:
addFirst(E e) 将指定元素插入此列表的开头:

link.addFirst("aaa");

addFirst(E e) 将指定元素插入此列表的末尾:

link.addLast("zzz");

获取第一个数据:

link.getFirst();

获取最后一个数据:

link.getLast();

获取元素 get(int index) 只是获取 不进行修改:

MyStudent a=list.get(0);

修改元素 set(int index,E element) :
(获取为get 修改为set)

list.set(0,new MyStudent("学生M",17));

三、set【子类,继承自collection】

Set容器的特点

1、元素存储和取出顺序是无序的
2、没有角标 不能进行精确地定位
3、不允许重复的元素 内容相同的只保留一个 它是通过复写equals()方法来判断是否的重复元素

Set容器和List容器一样 同样支持迭代和增强for循环

1、HashSet

返回哈希值

int hashCode=stu1.hashCode();

小案例

需求:同姓名同年龄视为同一个人

前置:
        set.add(new Student("treeset",16));
        set.add(new Student("B",21));
        set.add(new Student("C",24));
        set.add(new Student("treeset",16));

首先调用hashCode() 判断两个对象的哈希值是否一样(算法可以凭自己喜好写)

重写hashCode()方法★
重写hashCode()方法的目的就是要让同姓名同年龄的hashCode相同
因为原装的hashCode的算法结果 同姓名同年龄的hashCode不同 无法达到需求

public int hashCode()
{
        return name.hashCode()+age;
 }

若两个对象的hashCode()不相同 则:存这个对象
若两个对象的hashCode()相同 则:调用equals()方法 判断内容也是否一样
若不一样 采用拉链法 存储
若一样 视为重复 不存储

重写equals()方法★

public boolean equals(Object obj) {
        if (this==obj)//若传进来的和当前引用对象为同一个对象(即:自己和自己比较)
        {
            return true;
        }
        if (obj==null)//若传空值
        {
            return false;
        }
        if (obj instanceof Student)//若传进来的不为Student类或其子类
        {
            Student s=(Student)obj;//强制类型转换
            return name.equals(s.name) && this.age==s.age;//判断姓名和年龄是否相等
        }
        return super.equals(obj);
}

以上如此 即可实现需求

2、TreeSet

排序有两种方式:
1、实现Compareable接口 并且复写CompareTo()方法
2、TreeSet(Comparator<? super E> comparator)
构造一个新的空TreeSet 它根据指定比较器进行排序

①、compareTo()方法

用此方法时 传入的自定义的类必须实现Comparable接口 并且复写compareTo方法 二者缺一不可★

比较方法一:根据姓名排序★

@Override
public int compareTo(StudentX s)
{
    //在此比较时 必须明确主次 主要条件相等 再进行次要条件比较
    int temp=this.name.compareTo(s.name);
    return temp==0?/*若姓名相同*/ this.age-s.age:temp/*若姓名相同 返回年龄,若姓名不相同 返回0*/          /*再按照姓名排序*/;
}

比较方法二:根据年龄排序★

@Override
public int compareTo(StudentX s)
{
    //在此比较时 必须明确主次 主要条件相等 再进行次要条件比较
    int temp=this.age-s.age;
    return temp==0?/*若年龄相同*/ this.name.compareTo(s.name):temp/*再按照姓名排序*/;
}

②、compare()方法★★★
用此方法时 传入的自定义的类无须实现Comparable接口 无须复写compareTo方法★
但要在比较器里实现Comparator接口 复写compare方法★
语法:TreeSet(Comparator<? super E> comparator)
构造一个新的空TreeSet 它根据指定比较器进行排序
例:Set<StudentXX> set=new TreeSet<StudentXX>(new TreeSetCompareByName())

用于中文比较的类

Collator collator=Collator.getInstance(Locale.CHINA);

小案例:

要求:姓名和年龄相同 视为同一个对象
按照姓名排序:当姓名相同 再根据年龄排序

自己创建个比较器 用于执行固定的功能

public class TreeSetCompareByName implements Comparator<StudentXX> 
{
    @Override
    public int compare(StudentXX o1, StudentXX o2) {
        //如果是汉字,字符串比较不包含中文
        Collator collator=Collator.getInstance(Locale.CHINA);//用于中文比较的类★★★
        int temp=collator.compare(o1.name,o2.name);
        return temp==0? o1.age-o2.age:temp;//若o1.age大于o2.age 返回一个正数 则代表o1的age比o2的age大 且它们两个不相等
}

要求:姓名和年龄相同 视为同一个对象
按照年龄排序:当年龄相同 再根据姓名排序

自己创建个比较器 用于执行固定的功能

public class TreeSetCompareByAge implements Comparator<StudentXX> 
{
    @Override
    public int compare(StudentXX o1, StudentXX o2) {
        //如果是汉字,字符串比较不包含中文
        Collator collator=Collator.getInstance(Locale.CHINA);//用于中文比较的类★★★
        int temp=o1.age-o2.age;//若o1.age大于o2.age 返回一个正数 则代表o1的age比o2的age大 且它们两个不相等
        return temp==0? collator.compare(o1.name,o2.name):temp;
    }
}

总结:

Set两个实现类:

一、hashset

底层结构:哈希表(数组+链表)
如果自定义一个类
自定义:对象是否是同一个对象 就要重写HashCode()方法和equals()方法

二、TreeSet

底层结构:二叉树结构
1、让自定义的类去实现comparable接口 重写compareTo()方法
自定义排序需求(根据年龄、姓名…)

2、写一个比较器 实现comparator 重写compare()方法
自定义排序需求(根据年龄、姓名…)

TreeSet比HashSet多了排序功能

四、map【子类,继承自collection】

不关心实现类到底是谁 只关心顶层方法
存储特点:
存储重复键 对应的值会被覆盖

方法:

put(K key, V value)   往map里添加键值对

get(Object key)  返回指定键所映射的值,如果此映射不包含该键的映射关系 则返回null

remove(Object key)  如果存在一个键的映射关系,则将其从此映射中移除

Integer a=map.remove("bbb");//移除一个key键 并返回这个键对应的value值

keySet() 返回此映射中所有的键

K→getKey() 返回与此项对应的键

V→getValue() 返回与此项对应的值

Set<Map,Entry<K,V>>entrySet() 返回此映射中包含的映射关系的Set视图
返回map中键值对的映射关系 这个键值对的映射关系由Set保存

拆箱:将Integer类型自动转化成int类型

例:

Map<String,Integer> map=new HashMap<String,Integer>();
map.put("aaa",1);
int i=map.get("aaa");

Map集合的遍历方式:

方法一、通过键找值 ★
步骤:
1、调用集合的keySet()方法 获得集合所有的键
2、遍历所有的键 调用集合的get(Object obj) 通过指定的键找到对应的值

方法:
keySet() 返回此映射中所有的键
例:

Map<String,Integer> map=new HashMap<String,Integer>();

map.put("aaa",1);
map.put("bbb",2);
map.put("ccc",99999);
map.put("ccc",3);

Set<String> mySet=map.keySet();//通过map集合的keySet()方法获得集合中的全部的键key

or (Iterator<String> it=mySet.iterator();it.hasNext();)
{
      String myKey=it.next();
      Integer myValue=map.get(myKey);//通过key找到对应的value值
      System.out.println("Key="+myKey+" Value="+myValue);
}

方法二、通过map.entrySet()方法 ★
思考方式:

public interface Map
{
        class Entry
        {

        }
}

Map.Entry<K,V>这里面存的是键值对的映射关系 把键值对的映射关系封装成一个类

Entry反映的是键值关系 里面保存的是键值对 所以里面要注明K和V的类型
Set<Map.Entry<K,V>> → 这里的Map.Entry<K,V>相当于Student 也是一个类而已
方法:
K→getKey() 返回与此项对应的键
V→getValue() 返回与此项对应的值
Set<Map,Entry<K,V>>→entrySet() 返回此映射中包含的映射关系的Set视图
返回map中键值对的映射关系 这个键值对的映射关系由Set保存

步骤:
1、调用map集合方法中的entrySet() 将集合中的映射关系对象存储到set集合中
2、迭代set集合
3、获取set集合中的映射关系对象元素
4、通过映射对象方法getKey()和getValue()来获取键值对

例:

Map<String,Integer> map=new HashMap<String,Integer>();

        map.put("aaa",1);
        map.put("bbb",2);
        map.put("ccc",99999);
        map.put("ccc",3);

Set<Map.Entry<String,Integer>> mySet=map.entrySet();//调用entrySet()方法获得集合中的全部的键和值

        遍历方法一、用迭代器遍历★
        Iterator<Map.Entry<String,Integer>> it=mySet.iterator();//创建迭代器
        while (it.hasNext())
        {
            Map.Entry<String,Integer> myEntry=it.next();
            System.out.println("Key="+myEntry.getKey()+" Value="+myEntry.getValue());//这里的每个myEntry都是一组key键和value值
        }

        //遍历方法二、用增强for循环遍历★
        for (Map.Entry<String,Integer> myEntry:mySet)
        {
            System.out.println("Key="+myEntry.getKey()+" Value="+myEntry.getValue());//这里的每个myEntry都是一组key键和value值
        }