【Java】韩顺平Java学习日志10——面向对象编程高级级部分——第四部分——集合与泛型

集合

基本介绍

1.可以动态保存任意多个对象,使用比较方便
2.提供了一系列方便操作对象的方法

框架体系图

集合主要分为两大类:单列集合和双列集合
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Collection

基本介绍

public interface Collection<E> extends Iterable<E>

1.collection是心啊子类可以存放多个元素,每个元素可以是Object
2.有些Collection的实现类,可以存放重复的元素,有些不可以
3.有些Collection的实现类,有些事有序的,有些不是有序的
4.Collection接口没有直接的实现子类,是通过它的子类接口Set和List来实现的

常用方法

在这里插入图片描述
在这里插入图片描述

遍历元素的方式1.使用迭代器Iterator

基本介绍

1.Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
2.所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即返回一个迭代器
3.Iterator的结构

4.Iterator仅限于集合遍历,Iterator本身并不存放对象

迭代器执行原理

在这里插入图片描述

public class Co {
    public static void main(String[] args) {
        ArrayList<Object> list = new ArrayList<>();
        list.add("jack");
        list.add(35);
        Iterator iterator=list.iterator();//得到一个集合的迭代器
        while(iterator.hasNext()){//判断是否有下一个元素
            iterator.next();//指针下移,将下移后集合位置上的元素返回
            System.out.println(iterator.next());
        }
    }
}
常用方法

在这里插入图片描述
在这里插入图片描述
注意:
1.在调用iterator.next()方法之前必须调用iterator.hasNext()进行检测,若不调用,且下一条记录无效,直接调用it.next()会抛出异常
2.当退出循环后,iterator迭代器指向最后的元素
3.如果希望再次遍历,需要重置迭代器

遍历元素的方式1.for循环增强

基本介绍

增强for循环可以代替迭代器
特点:增强for循环就是简化版的iterator,本质相同,只能用于遍历集合或数组
基本语法:

for(元素类型 元素名:集合名或数组名){
访问元素
}

List

基本介绍

1.List集合类中元素有序(即添加顺序和取出顺序一致,且可以重复
2.List集合中的每个元素都有其对应的顺序索引,即支持索引(索引从0开始)
3.List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素
4.常用类:
在这里插入图片描述

常用方法

在这里插入图片描述

三种遍历方式

iterator
while (iterator.hasNext()) {
            Object next =  iterator.next();
}
增强for循环
 for (Object o :col) {
            }
普通for循环
for (int i = 0; i < col.size(); i++) {
            Object o=col.get(i);
        }

ArrayList

基本介绍

1.允许存放所有的元素,包括null,并且允许加入多个
2.ArrayList是由数组来实现数据存储的
3.ArrayList基本等同于Vector,处理ArrayList线程不安全(执行效率高),多线程情况下,不建议使用ArrayList

底层分析

1.ArrayList中维护了一个Object类型的数组elementData
2.当创建ArrayList对象时,如果使用的是无参构造,则初始elementData容量为0,第一次添加,扩容elementData为10,如果需要再次扩容,则扩容elementData的1.5倍
3.如果使用的是指定大小的构造器,则初始elementData容量为只当大小,如果需要扩容,则直接扩容elementData的1.5倍
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Vector

基本介绍

1.类的定义说明:
在这里插入图片描述
2.Vector底层也是一个对象数组 protected Object[] elementData
3.Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized

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

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

与ArrayList 的比较

在这里插入图片描述

LinkedList

基本介绍

1.LinkedList实现了双向链表和双端队列特点
2.可以添加任意元素(元素可以重复),包括null
3.线程不安全,没有实现线程同步

底层分析

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

与ArrayList的比较

在这里插入图片描述

选择判断

1.如果我们改查的操作多,选择ArrayList
2.如果我们增删的操作多,选择LinkedList
3.大部分情况下选择LinkedList
4.根据业务灵活选择

Set

基本介绍

1.无序(添加和去除的顺序不一致),没有索引
2.不允许重复元素,所以最多包含一个null
3.实现类有:
在这里插入图片描述

常用方法和与遍历方式

常用方法与Collection相同
遍历方式与Collection相同,可以使用迭代器和增强for循环,但是注意不能使用索引当时来获取

HashSet

基本介绍

1.HashSet实现了Set接口
2.HashSet实际上是HashMap,HashMap底层是(数组+链表+红黑树)

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

3.可以存放null值,但是只能存放一个null值
4.Hash不保证元素是有序的,取决于hash后,再确定索引的结果(即不保证存放元素的顺序和取出的顺序一致)
5.不能有重复元素/对象
6.在执行add方法后返回一个boolean值,添加成功返回true,否则返回false

底层分析

在这里插入图片描述
在这里插入图片描述

LinkedHashSet

基本介绍

1.是HashSet的子类
2.LinkedHashSet底层是一个LinkedHashMap,地城维护了一个数组+双向链表
3.LinkedHashSet根据元素的hashCode值来决定存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的
4.不允许添加重复元素
在这里插入图片描述

TreeSet

可以实现排序
TreeSet提供一个构造器,可以传入比较器
使用匿名类,实现比较器的自定义

public class Hashset {
    public static void main(String[] args) {
        TreeSet treeSet=new TreeSet<>(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).compareTo((String) o2);
            }
        });
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("sp");
        treeSet.add("a");
        System.out.println(treeSet);
    }
}

Map

基本介绍

1.Map与Collection并列存在,用于保存具有映射关系的数据:Key-Value
2.Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
3.Map中的key不允许重复,当有相同的key时,等价于替换
4.Map中的value可以重复
5.Map中的key可以为null,value也可以为null,注意key为value只能有一个,value为空可以有多个
6.常用String类作为Map的key
7.key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value值
8.Map存放一对数据的key-value是放在一个Node中的,因为Node实现了Entry接口,也有书上说一对k-v就是一个Entry
在这里插入图片描述
在这里插入图片描述
9.k-v为了方便程序员比哪里,还会 创建EntrySet集合,该集合存放的元素的类型Entry,如图一个Entry对象就有k,v EntrySet<Entry<K,V> 即:transient Set<Map.Entry<K,V>> entrySet
10.在entrySet中定义的类型是Map.Entry,但是实际上存放的还是HasnMapNode,因为static class Node<K,V> implements Map.Entry<K,V>当爸hashMapNode对象存放到entrySet就方便了我们的遍历

Set set=map.entrySet();
        for(Object o:set){
            Map.Entry entry=(Map.Entry) o;
            System.out.println(entry.getKey()+entry.getValue());
        }

常用方法

Map体系继承图:
在这里插入图片描述
常用方法:
在这里插入图片描述
在这里插入图片描述

遍历方式

1.containKey:查找键是否存在
2.keySet:获取所有的键
3.entrySet:获取所有的关系
4.values:获取所有的值

1.先取出所有的key,通过key取出对应的value

Set keyset=map.keySet();
        //(1)增强for循环
        for(Object key:keyset){
            System.out.println(key+"-"+map.get(key));
        }
        //迭代器
        Iterator iterator=keyset.iterator();
        while (iterator.hasNext()) {
            Object key =  iterator.next();
            System.out.println(key+"-"+map.get(key));
        }

2.只取出所有的value

Collection values=map.values();
        //(1)增强for循环
        for (Object value :values) {
            System.out.println(value);
        }
        //2.迭代器
        Iterator iterator1=values.iterator();
        while (iterator1.hasNext()) {
            Object value =  iterator1.next();
            System.out.println(value);
        }

3.使用entryset

Set entrySet=map.entrySet();//EntrySet<Map.Entry<k,V>>
        //(1)增强for循环
        for (Object entry :entrySet) {
            //将entry转成Map.entry
            Map.Entry m=(Map.Entry) entry;
            System.out.println(m.getKey()+"-"+m.getValue());
        }
        //2.迭代器
        Iterator iterator2 = entrySet.iterator();
        while (iterator2.hasNext()) {
            Object entry =  iterator2.next();//HasnMap$Bode-实现->Map.Entry(getKey,getValue)
            Map.Entry m=(Map.Entry) entry;
            System.out.println(( m.getKey()+"-"+m.getValue());
        }

实例

public class Hashset {
    public static void main(String[] args) {
        Map hashMap = new HashMap();
        hashMap.put(1,new Emp("jack",3000,1));
        hashMap.put(2,new Emp("tom",1000,2));
        hashMap.put(3,new Emp("milan",5000,3));

        Set keySet=hashMap.keySet();
        for (Object key :keySet) {
            Emp emp =(Emp) hashMap.get(key);
            if(emp.getSal()>1000)
                System.out.println(emp);
        }
        Set entrySet = hashMap.entrySet();
        Iterator iterator=entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry entry =(Map.Entry)  iterator.next();
            Emp emp=(Emp) entry.getValue();
            if(emp.getSal()>1000)
                System.out.println(emp);
        }
    }
}
class Emp{
    String name;
    double sal;
    int id;

    public Emp(String name, double sal, int id) {
        this.name = name;
        this.sal = sal;
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Emp{"+name+sal+id+"}";
    }
}

HashMap

1.Map接口的常用实现类:HashMap,Hash他变了和Properties
2.HashMap是以key-value对的方式来存储数据
3.key不能重复,但是value可以重复,允许null键和null值
4.如果添加相同的key则会覆盖原来的key-val,等同于修改(key不会替换,value会替换)
5.与HashSet也有不保证映射的顺序,因为底层是以hash表的方式来存储的(hashMap 底层 数组+链表+红黑树)
6.HashMap马原实现同步,因此是线程不安全的,方法马原做到同步互斥的操作

TreeMap

实现排序
构造器中存在一个比较器

TreeMap treeMap=new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).compareTo((String) o2);
            }
        });
        treeMap.put("jack","hhh");
        treeMap.put("tom","hh");
        treeMap.put("sp","h");
        treeMap.put("a","mm");
        System.out.println(treeMap);

集合选型机制

1.判断存储类型

(一组对象【单列】或一组键值对【双列】)

2.一组对象:

Collection接口

允许重复:List

增删多:LinkedList(底层维护了一个双向链表)
改查多:ArrayList(底层维护了一个Object类型的可变数组)

不允许重复:Set

无序:HashSet(底层是HashMap,维护了一个哈希表,即数组+链表+红黑树)
排序:TreeSet
插入和取出顺序一致:LinkedHashSet(底层维护了数组+双向链表)

3.一组键值对:Map

键无序:HashMap(底层是哈希表,维护了一个哈希表,即数组+链表+红黑树)
键排序:TreeMap
键插入和取出顺序一致:LInkedHashMap
读取文件 Properties

Collections工具类

基本介绍

1.是一个操作Set,List,Map等集合的工具类
2.Collections中提供了一系列静态的方法对集合元素进行排序,查询,修改等操作

排序操作:(均为static方法)

在这里插入图片描述
在这里插入图片描述

泛型

传统方式

1.不能对加入到集合中的数据类型进行约束,不安全
2.比哪里的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响

泛型的好处

1.编译时,检查添加元素的类型,提高了安全性
2.减少了类型转换的次数,提高效率
使用泛型放入取出时不需要类型转换
3.不再提示编译警告

基本介绍

1.泛型又称参数化类型,解决数据类型的安全性问题
2.在类声明或者实例化时,只要指定号需要的具体类型即可
3.java泛型可以保证如果程序在编译时马原发出警告,运行时就不会产生类型转换的异常,同时代码更加简洁和健壮
4.泛型的作用是:可以在类声明的过程中通过标识表示类中某个属性的类型,或者是某个方法的返回值类型,或者是参数类型

语法

Interface 接口<T>{} 
class<K,V>{}

其中的T,K,V不代表值,而是代表类型
任意字母都可以

实例化

要在类名后面指定类型参数的值(类型)

List<String > stringList=new ArrayList<String>();
Iterator<Customer> iterator=customers.iterator();

实例

public class Hashset {
    public static void main(String[] args) {
        HashSet<Student> students = new HashSet<>();
        students.add(new Student("jack",18));
        students.add(new Student("tom",28));
        students.add(new Student("mary",38));\
        for (Student student :students) {
            System.out.println(student);
        }
        HashMap<String, Student> hm = new HashMap<>();
        hm.put("tom",new Student("tom",28));
        hm.put("jack",new Student("jack",18));

        Set<Map.Entry<String, Student>> entrySet = hm.entrySet();
        Iterator<Map.Entry<String, Student>> iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Student> next =  iterator.next();
            System.out.println(next.getKey()+"-"+next.getValue());
        }
    }
}
class Student{
    String name;
    int age;

    public Student(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 String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

使用细节

1.Interface 接口{} 或class类<K,V>{}中的T,K,V等只能是引用类型,而不能是基本数据类型
2.在指定泛型的具体类型后, 可以传入该类型或者其子类类型
3.List list=new ArrayList();不指定泛型类型则默认泛型是Object

练习

import java.util.*;

public class Hashset {
    public static void main(String[] args) {
        ArrayList<Emplpyee> emplpyees = new ArrayList<>();
        emplpyees.add(new Emplpyee("tom",2000,new MyDate(2000,11,20)));
        emplpyees.add(new Emplpyee("jack",1000,new MyDate(2001,11,2)));
        emplpyees.add(new Emplpyee("hsp",5000,new MyDate(2005,10,2)));
        System.out.println(emplpyees);
        emplpyees.sort(new Comparator<Emplpyee>() {
            @Override
            public int compare(Emplpyee o1, Emplpyee o2) {
                if(!(o1 instanceof Emplpyee&& o2 instanceof Emplpyee))
                    return 0;
                int i = o1.getName().compareTo(o2.getName());
                if(i!=0)return i;
                o1.getBirthday().compareTo(o2.getBirthday());
            }
        });
    }
}
class Emplpyee{
    String name;
    double sal;
    MyDate birthday;

    public Emplpyee(String name, double sal, MyDate birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "\nEmplpyee{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }
}
class MyDate implements Comparable<MyDate>{
    int year;
    int month;
    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 int compareTo(MyDate o) {
        int yearMins = year -o.getYear();
        if(yearMins!=0)return yearMins;
        int monthMins=month-o.getMonth();
        if(monthMins!=0)return monthMins;
        return day-o.getDay();
    }
}

自定义泛型

自定义泛型类

基本语法

class<K,V....>{成员}

注意细节

1.普通成员可以使用泛型(属性,方法)
2.使用泛型的数组,不能初始化
3.静态方法中不能使用类的泛型
4.泛型类的类型是在创建对象时去欸的那个的(因为创建对象时,需要指定确定类型)
5.如果创建对象时没有指定类型,默认为Object

自定义泛型接口

基本语法

interface 接口名<K,V....>{}

注意细节

1.接口中,静态成员也不能使用泛型(接口中的属性是静态的,方法是public的,抽象方法可以省略关键字)
2.泛型接口的类型,在继承接口或者实现接口时确定
3.没有只当类型,默认为Odject

自定义泛型方法

基本语法

修饰符 <K,V....>返回类型 方法名(参数列表){}

注意细节

1.泛型方法可以定义子啊普通类中,也可以定义在泛型类中
2.当泛型方法被调用时,传入参数,编译器就会对类型进行确定
3.public void eat(E e){} 修饰符后面没有<T,R> eat方法不是泛型方法,而是使用了泛型作为参数

泛型的继承和通配符

1.泛型不具备继承性

List<Object> list=new ArrayList<String>();//flase 不允许继承

2.<?>支持任意泛型类型
3.<? extends A>支持A类以及A类的子类,规定了泛型的上限
4.<? super A>支持A类以及A类的父类,不限于直接父类,规定了泛型的下限

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值