Java中的集合(Collection类)

集合:java中提供的一种容器,可以用来存储数据.  

  与数组的异同:
   1.长度:
        数组长度固定.
         集合长度可变(集合底层还是数组)
   2.存储:
        数组中存储 同一种类型的元素 .
        集合存储的都是对象,而且 对象的类型可以不一样 .
        (当对象多的时候,使用集合来存储)

        (一般都是使用<T>范型指定相同类型的数据存储在一起,如果不指定范型,在取出数据时需要向下转型)

*学习类的时候,从父类开始,学习共有的特性.

集合框架:
  按存储结构来分:
    1.单列集合  java.util.Collection
  继承结构:

    2.双列集合  java.util.Map
 继承结构:


ArrayList集合

对象数组
   数组内放入对象(保存的是地址)

ArrayList
  1.可调整大小的数组集合, 底层是数组
  2.可以不断在其末端添加数据
  3.只能存储引用数据类型(存储基本数据类型的包装类可以)
        
创建ArrayList:
ArrayList<String> list = new ArrayList<>();
ArrayList<E>:
    <E>:表示范型,你可以填入你需要的存储的 引用数据类型(不包括8大基本类型);如果不填写,存储的类型可以是任何类型,但是在取出数据的时候要转换成你存储的数据类型,否则取出数据会报错.
     *当你要存储基本类型时,需要把E转换为他的包装类.(如: int ->Integer)

ArrayList<Integer> list = new ArrayList<>();
//在JDK1.5的时候有了自动拆装箱的新特性,可以使集合的存取更加方便.

创建一个ArrayList:  创建时如果不new一个空间,会报空指针异常的错误(NullpointerException)
ArrayList<String> list = new ArrayList<>();//jdk1.7后,右边的<>里面不用添加数据类型

//添加数据 
list.add("你的数据");
System.out.ptintln(list);//直接打印所有的元素
 

对数据的操作:
    List接口的方法:(实现List接口的类都可以使用,包括ArrayList和LinkedList.)
 

  Collection接口中的方法:(List和Set集合都能使用的方法)

LinkedList集合

         LinkedList是一个双向链表,他的底层是链表.

         链表的特点:    增删快, 查找慢

         ArrayList的特点: 增删慢, 查找快

        (我们可以在合适的场景选择自己需要的数据类型)        

原因:

      1.因为ArrayList的底层是数组,其实现的基本思想是首先创建一个10长度的数组,把我们需要存储的数据存储进去.

         如果满了,则扩容继续存储,存储完了后,通过System.copyarray()方法把这个数组里面的数据存储到一个新的数组中去(就是我们最终得到的ArrayList数组).

         由于每次都要创建数组,所以ArrayList的增删比较慢,但是底层是数组,只要知道其索引就可以轻松找到数据,所以查找快.  

      2.LinkedList的数据结构:

          他是由2部分组成的, 一个是数据域,一个是指针域.

           数据域里面存储数据,指针域里面存储指针.   多个数据就是通过指针连接起来,所以修改其中的一个数据,只要把指针的指向改变就可以完成了,所以增删快;而查找数据则需要通过指针一个一个查找数据,所以查找慢.


Set集合

常用子类:HashSet\LinkedHashSet
  与Collection接口中的方法基本一致,没有对功能进行扩展,只是接收数据更加严格,数据无序并按哈希表排序,存入的元素不会重复.
作用:保证存储的数据的值相同只有一个.(去除相同值的数据)


HashSet集合(哈希表)

学习Set集合前,必须明白什么是哈希表:
  *JDK1.8之前, 数组+链表
  *JDK1.8之后,数组+链表+红黑树(优化迭代性能)
    *当链条超过8个元素的时候,转换为红黑树.
  *数组长度是16(扩扩容)
对象的哈希值:
  *是一个10进制的整数
  *通过调用hashCode()方法获得,如果子类没有重写,返回默认是地址值
  *哈希值是对象存储到哈希表的重要依据.

哈希表存储元素过程:
  1.获得元素的哈希值
  2.使用哈希值对16进行取余(hashcode % 16),得到值index
  3.把元素存入index位置.
  4.如果该位置已经有元素,先比较2个元素的哈希值
  5.如果哈希值不同,把新的元素存入index位置,新的元素记住旧元素的地址.
  6.如果哈希值相同,继续比较地址值,如果地址值相同,不加入;否则加入新的元素.


字符串只要内容相同,哈希值一定相同.
字符串内容不一样,哈希值不一定不同.

自定义对象存入HashSet
  *需要重写hashCode和equals方法.
class Student{
   private String name;
   private int age ;
   
   //通过重写Object类的equals和hashCode方法,编译器可以自动生成
   //快捷键 Alt + ins
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
}

哈希表自动扩容机制:

  *实例的默认初始容量为16,加载因子为0.75(可修改)[当数据达到16*0.75=12个的时候扩容]
  *扩容机制:每次扩容为2倍,当数组 >= 长度*加载因子 ,才扩容
  *扩容后,会进行再哈希操作(哈希值%数组长度),重新排列数据位置.

LinkedHashSet集合

特点:
  *继承HashSet,基本上与HashSet一样,只是在取出数据的时候是你存入数据的顺序.
  *底层结构是哈希表+链表




集合遍历的方法:

迭代 == 遍历
为了遍历,JDK专门提供了java.util.Iterator接口.
迭代器:一个用来遍历集合的对象,该对象实现了Iterator接口
    (实现了Iterator接口的对象都是迭代器)

获得迭代器:
    通过调用集合对象的方法: Iterator<E> iterator()

常有方法:
    boolean hasNext();判断是否有下一个元素
    E next();获取下一个元素.使用指针.


//遍历
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("111");
list.add("111");

//使用迭代器
Iterator<String> it = list.iterator();
//使用while进行循环
while(it.hasNext()){
    System.out.println(it.next());
}

迭代器的优点:
 1.屏蔽了集合内部实现,对外提供统一的遍历方式.
 2. 单列集合都可以使用迭代器


增强for循环
  也称为for each循环, JDK1.5后出现
    作用:专门用来遍历数组和集合
    原理:内部为迭代器
    缺点:遍历过程中,不能对集合中的元素进行增删改查.


Map集合
 map接口是Collection接口下的集合
 存储方式: 由 组成
    *键是唯一的,值可以重复.

Map常用子类
  1. HashMap:存储数据采用哈希表结构与HashSet类似.需要保证 键是唯一的, 值可以重复
  2. LinkedHsahMap:与LindedHashSet类似,继承HashMap,能够按顺序迭代数据.


*HashMap的增\改方法都是put(K k,V v);       如果key存在于map中,则修改V的值,并返回原来V的值.

Map集合迭代的方法:
  1. 获取Map中所有的键Key,存储在Set集合中,再通过遍历Set集合把Key对应的Value取出来.
HashMap<String ,String> hashMap = new HashMap<>();
//添加数据到集合中,使用put(K k, V v); 而不是用add()方法
hashMap.put(key,value);
.
.
.
//使用getKey()把所有的key存储到集合中(返回值是Set<E>)
HashSet<String> hashSet = hashMap.keySet();
//遍历hashSet,当然你也可以使用迭代器
for(String key : hashSet){
   //通过key获取 hashMap中的对应的value值
   String value = hashMap.get(key);
}

  1. Entry把键值对封装成对象.Entry是map里面的一个接口类,我们可以使用它对Map的键值对进行封装.数据结构(哈希值,key,value,指针)

//使用Entry进行迭代
HashMap<String,String > hashMap = new HashMap<>();
hashMap.put("hello","world");
hashMap.put("hello1","world");
hashMap.put("hello2","world");
hashMap.put("hello3","world");
//使用的是Set<E>进行接收,不能使用其子类进行接收.
Set<Map.Entry<String,String>> entry = hashMap.entrySet();

for (Map.Entry<String, String> stringStringEntry : entry) {
    System.out.println(stringStringEntry.getKey()+"="+stringStringEntry.getValue());
}

JDK9.0对集合的优化:
  原本我们对集合进行添加元素的时候需要使用add()方法,当我们添加的多个数据时就会使代码重复多变.
  所以jdk9添加了几种集合工厂方法.更方便创建少量的集合(List\Set\Map)
Set<String> str1 = Set.of("a","b","c"); 
//str1.add("c");这里编译的时候不会错,但是执行的时候会报错,因为是不可变的集合 
System.out.println(str1); 
Map<String,Integer> str2 = Map.of("a",1,"b",2); 
System.out.println(str2); 
List<String> str3 = List.of("a","b"); 
System.out.println(str3);
1:of()方法只是Map,List,Set这三个接口的静态方法,其父类接口和子类实现并没有这类方法,比如
HashSet,ArrayList等等;
2:返回的集合是 不可变的;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值