Java基础(二):泛型和集合

集合和泛型

继承图

在这里插入图片描述

collection接口

方法

在这里插入图片描述

迭代器

iterator()

iterator返回一个Iterator类。拥有的方法如下图。

在这里插入图片描述

Collection<String> coll = new ArrayList<>();
coll.add("hello");
coll.add("world");
Iterator<String> itr = coll.iterator();
while(itr.hasNext()){
    //注意:最好遍历一次取一次,否则可能发生NoSuchElementException
    String next = itr.next();
    System.out.println(next);
}
hello 
world
迭代器并发修改异常

ConcurrentModificationException。在迭代的同时增删元素。

Collection的迭代器是快速失败的。在next()方法第一句会调用checkForComodification()方法。这个方法比较修改值。如果modCount和expectedModCount的值不一致,程序会抛出了ConcurrentModificationException异常。

Collection<String> coll = new ArrayList<>();
coll.add("hello");
coll.add("world");
Iterator<String> itr = coll.iterator();
while(itr.hasNext()){
    String next = itr.next();
    list.remove("hello"); 	//删除元素
    list.add("exception");	//增加元素
}

解决方法:调用iterator的remove()方法。这个方法会对expectedModCount进行重新赋值。

 1 public void remove() {
 2     if (lastRet == -1)
 3     throw new IllegalStateException();
 4        checkForComodification();
 5  
 6     try {
 7     AbstractList.this.remove(lastRet);
 8     if (lastRet < cursor)
 9         cursor--;
10     lastRet = -1;
11     expectedModCount = modCount; //重新赋值
12     } catch (IndexOutOfBoundsException e) {
13     throw new ConcurrentModificationException();
14     }
15 }
foreach循环遍历

可以实现对数组或者集合进行快速遍历。缺点是不能获取索引。数组遍历和集合遍历的原理有所不同。数组遍历采用fori循环。集合遍历则使用迭代器。

  • 数组遍历
type[] arr;
for (type var : arr) {
    body-of-loop
}
//---------------反编译如下------------------------
for (int i = 0; i < arr.length; i++) { 
    type var = arr[i];
    body-of-loop
}
  • 集合遍历
Collection<type> coll;
for (type var : coll) {
    body-of-loop
}
//---------------反编译如下------------------------
for (Iterator<type> iter = coll.iterator(); iter.hasNext(); ) {
    type var = iter.next();
    body-of-loop
}

泛型

  • 泛型类
public class Test<E>{
    public E content;
    public void show(E msg){
        System.out.println(msg);
    }
}
  • 泛型方法
//泛型方法在方法名称前面有一个<T>声明,它的作用是告诉编译器编译的时候就识别它的类型,如果传入的T是A类型,那么你就不可以将B类型传入方法中去;
public static <T> T test(T param){
	return param;
}
  • 泛型接口

继承泛型接口有两种方式,第一个是指定接口的类型,定义类是普通类。第二个不指定接口的类型,定义类也是泛型类。

public interface Dao<T>{
    public void save (T t);
    public void update (T t);
}
  • 泛型上限
//继承Number都可以使用
ArrayList<? extends Number> list;
  • 泛型下限
//Integer的超类都可以使用
ArrayList<? super Integer> list;

List

java.util.list接口集成自Collection接口,是单列集合的重要分支。其特点如下:

  • list集合占据一段连续的地址空间,以线性方式存储。
  • list集合的存放和取出是有序的。
  • list集合带有索引,可以根据索引精确地查找元素。
ArrayList

java.util.ArrayList,内部有一个数组,添加元素时如果数组大小为零会扩容为10,当size要超过数组大小时会扩容1.5倍。

因为内部是数组,所以查改快,增删时要进行数组的整体复制,造成一定的时间开销。因为其特点所以很适合查询多,增删少的场景

LinkedList

java.util.linkedList内部是一个双向链表。元素增删快,查找慢

内部维护着首尾两个指针节点。拥有大量关于首尾操作的方法。

public void addFirst(E e) :将指定元素插⼊入此列列表的开头。
public void addLast(E e) :将指定元素添加到此列列表的结尾。
public E getFirst() :返回此列列表的第⼀一个元素。
public E getLast() :返回此列列表的最后⼀一个元素。
public E removeFirst() :移除并返回此列列表的第⼀一个元素。
public E removeLast() :移除并返回此列列表的最后⼀一个元素

Set

java.util.Set接口也继承Collection接口,基本上只重写了Collection中的方法。特点如下

  • 元素无序,没有索引,并且不可重复。
HashSet

java.util.HashSet是一个存储无重复数据的集合,Set接口的实现类。内部是一个数组加链表形成的哈希表。元素存取的顺序是不一致的,通常由元素的hashcode和数组的大小决定其顺序。

java.util.HashSet内部有一个HashMap,对元素的增删改查通过调用HashMap方法来完成。

HashSet的存取逻辑如下:

1.通过元素的hashCode方法计算数组索引。

2.如果索引位置没有元素,则直接放置。否则调用元素的equals方法和遍历链表进行内容比较。

3.如果内容相同,则返回旧值;否则,将元素插在链表的尾部。

4.如果链表大小超过8, 则将链表转化成为红黑树(JDK1.8)

5.计算元素的数量是否超过阀值,如果超过则扩容两倍。

在这里插入图片描述

LinkedHashSet

java.util.LinkedHashSet继承HashSet。内部是由一个哈希表和一个双向链表组成,能够实现存取顺序的一致性。

Collections工具类

常用方法

java.utils.Collections 是集合工具类,用来对集合进行操作。常用方法如下:

public static <T> boolean addAll(Collection<T> c, T... elements) :往集合中添加一些元素。
public static void shuffle(List<?> list) 打乱顺序 :打乱集合顺序。
public static <T> void sort(List<T> list) :将集合中元素按照默认规则排序。
public static <T> void sort(List<T> list,Comparator<? super T> c) :使⽤自定义比较器对集合中元素进⾏行行排序。
代码演示
public class CollectionsDemo {
	public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        //原来写法
        //list.add(12);
        //list.add(14);
        //list.add(15);
        //list.add(1000);
        //采⽤用⼯工具类 完成 往集合中添加元素
        Collections.addAll(list, 5, 222, 12);
        System.out.println(list);
        
        // 对集合元素乱序
        Collections.shuffle(list);
        System.out.println(list);
        //排序⽅方法:升序
        Collections.sort(list);
        System.out.println(list);
        // 使⽤用自定义比较器排序:降序
        Collections.sort(list,new MyComparator());
        System.out.println(list);
    }
}

/*
* 自定义比较器
*/
class MyComparator implements Comparator<Integer>{
	public int compare(Integer o1,Integer o2) {
	return o2 - o1;
	}
}

结果:
[5, 222, 1, 2]
[1, 2, 5, 222]

Map接口

1541071414605

常用方法

public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中。
public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
public Set<K> keySet() : 获取Map集合中所有的键,存储到Set集合中。
public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)

Map的遍历

键找值方式

    Map<String,String> map = new HashMap<>();
    map.put("邓超", "孙俪");
    map.put("李晨", "范冰冰");
    map.put("刘德华", "柳岩");
    map.put("黄晓明", "Baby");
    map.put("谢霆锋", "张柏芝");
    Set<String> keys = map.keySet();
    for (String key : keys) {
        System.out.println(key);
        String value = map.get(key);
        System.out.println(value);
    }

键值对方式(获取Entry对象): 直接获取键值对对象,不用每次都遍历,效率较高。

    Map<String,String> map = new HashMap<>();
    map.put("邓超", "孙俪");
    map.put("李晨", "范冰冰");
    map.put("刘德华", "柳岩");
    map.put("黄晓明", "Baby");
    map.put("谢霆锋", "张柏芝");
    Set<Map.Entry<String, String>> entries = map.entrySet();
    for (Map.Entry<String, String> entry : entries) {
        System.out.println("key: " + entry.getKey());
        System.out.println("value: " + entry.getValue());
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值