2021-01-22

学习目标:

小白起飞17天

学习内容:

Collection
1.1 概述
通过继承体系发现,集合中两大分类,List和Set 并且 两个都继承了Collection,所以Collection中的方法是List和Set都有的

  • Collection 集合 只能存储单个元素,并且只能保存引用数据类型,不能保存基本数据类型
  • 因为 底层就是 Object[] 数组,既然是Object 所以 即可以说 只能保存Object单一元素,也可以说
  • 可以保存任何元素,因为Object是祖类,所有类型都会发生向上转型(多态),上述不能存基本数据类型,但是可以存包装类型
    常用方法 :
    boolean add() : 添加元素
    void clear() : 清空集合
    boolean remove() 删除某个元素
    boolean isEmpty() 判断集合中是否为空
    boolean contains() : 是否包含某个元素
    int size() 返回集合中 元素个数

下面我们列举出最常用的几个子接口和实现类:
Collection ——> List ——> ArrayList类
Collection ——> List ——> LinkedList类
Collection ——> Set ——> HashSet类
Collection ——> Set ——> SortedSet接口 ——> TreeSet类
Map ——> HashMap类
Map ——> SortedMap ——> TreeMap类
1.3 Collection和Iterator
1.3.1 Collection概述
Collection接口是List接口和Set接口的父接口,它定义的方法可以用于操作List集合和Set集合。
Collection接口定义的方法

public static void main(String[] args) {
// 接口不能创建对象,但是可以由于多态,还是可以访问对象的,只是丢失子类特有的方法
// 所以我们现在能够调用的方法都是Collection中的
Collection c1 = new ArrayList();
// 判断是否为空 true
System.out.println(c1.isEmpty());

	// 添加元素
	c1.add("asd");
	// 123为int,会先自动装箱为 Integer,然后再向上转型为Object
	c1.add(123);
	c1.add(256);
	Object  o1=new Object();
	c1.add(o1);
	// 添加元素后,判断元素是否为空
	System.out.println(c1.isEmpty());
	// size不是数组的长度,而是数组中已经添加的元素个数,添加了四个元素,输出4
	System.out.println(c1.size());
	
	// 转数组
	Object[] arr = c1.toArray();
	for (Object object:arr) {
		System.out.println(object);
	}
	System.out.println("---------");
	// 删除
	c1.remove(123);
	// 重新获取数组
	arr = c1.toArray();
	for (Object object : arr) {
		System.out.println(object);
	}
	// 清空数组中元素
	c1.clear();
	System.out.println(c1.size());
	System.out.println(c1.isEmpty());
}

1.3.3 Iterator概述

  • Iterator是迭代器

  • 迭代器是一种模式,它可以使序列类型的数据结构的遍历行为和被遍历的对象分离,只要拿到这个对象,使用迭代器就可以遍历这个对象的内部数据

  • 创建迭代器对象

  •  Iterator it = 集合对象.iterator();
    
  •  	调用集合对象自己的iterator方法就可以创建属于自己的迭代器
    
  • Iterator方法

  •  1 boolean hasNext() : 判断光标下一位 是否还有元素,有就返回true,没有就返回false,
    
  •  		生成迭代器的时候,光标不是指向第一个元素的,而是在最顶端,没有指向任何元素
    
  •  		光标不会自动复位,使用完之后,必须重新生成
    
  •  2 E next() : 把光标向下移动一位,并返回该位上的数据
    
  •  3 remove() : 删除当前光标指向的元素
    
  •  三个方法的使用顺序,就是 1,2,3 
    
  • 迭代器 一旦创建,如果集合中添加或者删除元素,那么迭代器必须重新生成, 否则调用next()方法会报错

  • 但是 更改数据 不用重新生成,用iterator让循环访问的形式变的更简单,写起来更方便,不过功能不太全,没有办法删除

  • 所以需要有删除操作的话,还是要用原来的iterator形式

  • 所以 forEach也是迭代器,使用forEach和使用iterator一样,不能添加或删除集合数据,但是更改可以

  • 而 普通for和while这种遍历,都是和数据结构存储有关系的,比如数组 需要使用 arr[index]去访问

  • 并且可以进行添加和删除操作

  • 注意 使用迭代器进行遍历操作时 如果需要删除元素,只能使用 迭代器的remove方法,不能使用集合的remove方法
    */
    public class _Collection02 {
    public static void main(String[] args) {

     // 1 创建集合
     	Collection c = new ArrayList();
     	
     	// 2 添加元素
     	c.add(123);
     	c.add("asd");
     	c.add(2.3);
     	c.add(false);
     	c.add(null);
     	
     	// 创建迭代器
     	Iterator it = c.iterator();
     	// 判断还有没有元素,没有就终止
     	while(it.hasNext()){
     		// 能进来说明有,并且输出的是有几个元素就输出几个
     		Object o = it.next();
     		System.out.println(o);
     	}
     	System.out.println("===========");
     	
     	// 到这里输出false,因为光标已经移动到了最后一位,下面没有元素了
     	System.out.println(it.hasNext());
     	System.out.println("===========");
     	// 使用for完成
     	// 不会执行 因为 上面循环中 已经把光标移动到最后了
     	// 当这里再判断 hasNext()的时候,就已经是false了
     	for(;it.hasNext();){
     		// 能进来说明有,上边已经没有元素了
     		Object o = it.next();
     		System.out.println(o);
     		System.out.println("===========");
     	}
     	
     	// 如果此时 添加或者删除元素
     	c.add(1);
     	
     	// 只要迭代器生成,集合添加或者删除,再使用这个迭代器 就会报错
     	//  java.util.ConcurrentModificationException
     	// 如果要使用,需要重新生成
     	it=c.iterator();
     	while(it.hasNext()){
     		// 能进来说明有
     		Object o = it.next();
     		// 一旦生成迭代器 不能使用 集合的remove,除非重新生成,否则报错
    

// c.remove(1);
// 但是可以使用迭代器的remove进行删除操作
it.remove();
System.out.println(o);
}
// 0 循环删除完了
System.out.println(c.size());
}

1.3.5 注意 : Contains和remove
boolean contains(Object o)

  •  判断集合中是否包含某个元素
    
  • boolean remove(Object o)

  •  在集合中删除指定元素
    
  • 这两个方法,底层都会去调用equals方法进行比较

  •  比如 c.contains("asd") , 会用 asd 调用String的equals方法 挨个和集合中元素进行比较
    
  •  同理 remove也是一样
    
  •  判断谁,就用谁调用equals方法,和集合中元素进行比较
    
  • 所以如果是存储的自定义类型(类对象),就需要根据需求覆写equals方法
    */
    public class _Collection03 {
    public static void main(String[] args) {
    // 1 创建集合
    Collection c = new ArrayList();
    Integer i1 = new Integer(1);
    Integer i2 = new Integer(2);
    Integer i3 = new Integer(3);
    c.add(i1);
    c.add(i2);
    c.add(i3);

     Integer i4 = new Integer(2);
     // false 因为new
     System.out.println(i4 == i2);
     // true 因为  Integer 重写了equals方法,比较的是值
     System.out.println(i4.equals(i2));
     // true,因为contains会自动调用 i4的equals方法和集合元素进行比较
     // 由于 i4是Integer类型,因为Integer覆写了equals方法,所以比较的是值
     System.out.println(c.contains(i4));
     
     Manager m1 = new Manager(2, "张三");
     Manager m2 = new Manager(2, "张三");
     c.add(m1);
     // true , 因为添加了m1,肯定是true
     System.out.println(c.contains(m1));
     // false,尽管m1和m2中数据一样,但是会调用equals方法,而Manager中没有覆写equals方法,
     // Object中的equals方法默认比较内存地址,m2和m1的内存地址不同,所以不存在
     System.out.println(c.contains(m2));
     
     // 需求 : 如果编号和姓名一致 就认为是同一个对象
     // 在Manager中覆写了equals方法之后,再比较 就是true了
     System.out.println(c.contains(m2));
    

    }
    }

class Manager {
private int no;
private String name;

@Override
public String toString() {
	return "Manager [no=" + no + ", name=" + name + "]";
}

@Override
public boolean equals(Object obj) {
	System.out.println("=========");
	if (this == obj) {
		return true;
	}
	if (obj instanceof Manager) {
		Manager m2 = (Manager) obj;
		if (this.name.equals(m2.name) && this.no == m2.no) {
			return true;
		}
	}
	return false;
}
public int getNo() {
	return no;
}

public void setNo(int no) {
	this.no = no;
}

public String getName() {
	return name;
}

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

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

1.4 List
List元素的特性 : 有序可重复

  •  存入顺序和取出顺序是一致的,并且有指定的下标可以表示数据的唯一性,所以可以存在重复数据
    
  • 底层实现
  •  	ArrayList : 底层是数组,查询效率较高,添加和删除效率较低
    
  •  	LinkedList : 底层是双向链表,查询效率较低,添加和删除效率较高
    

*/
public class _Collection04 {
public static void main(String[] args) {
List list = new ArrayList();
list.add(2);
list.add(3);
// 输出 [2,3] ,因为输出引用的时候,会自动调用该对象的toString,而ArrayList覆写了
System.out.println(list);

}

1.4.1 ArrayList
ArrayList : 底层索引数组,下标从0开始 初始化容量为 10 ,如果数组被占满,需要增加数据时,

  • 扩大容量为原始容量的1.5倍.非线程安全,效率高

  • List遍历方式

  •  while , for, foreach , iterator 
    
  • add(E e) : 将指定元素添加到尾部

  • add(int index,E e) : 将指定元素添加到指定位置,原位置内容统一向后移动

  • set(int index,E e) : 更改指定位置上的元素值

  • get(int index) : 获取指定索引上的元素

  • remove(int index) : 删除指定索引上的元素

  • remove(Object o) : 删除指定元素
    */
    public class _Collection05 {
    public static void main(String[] args) {
    List li = new ArrayList();
    // 数组中 : 数组只能保存同一数据类型
    // 集合中 : 可以存储任意类型
    // 而ArrayList底层是数组,因为ArrayList底层是Object[] 数组
    // 同理 我们单独声明Object[]数组的话,也可以说可以存储任意数据
    // 因为任何数据 都可以转型为Object类型,包括基本(自动装箱再向上转型)

     // 把数据添加到尾部
     li.add(1);
     //在这里1已经被添加在之前的数组最后一位了,后边的8也是添加在最后一位
     li.add(8);
     // 把指定元素,插入到指定位置,该位置上的元素统一向后移动
     li.add(0, 2);
     //此时添加数组,之前有三个元素,最后一个元素下标是2,这次只能比下标多一位添加,否则报错
     li.add(3, 2);
     System.out.println(li);
     // 更改指定位置上的元素
     li.set(0, 3);
     System.out.println(li);
     
     // 获取指定下标对应的数据
     Object o = li.get(1);
     System.out.println(o);
     
     // 删除 ,方法重载,如果 是 int 说明是要删除元素的下标是什么, Object 才是被删除的对象
     // 删除下标为3的元素
     // li.remove(3);
     // 删除元素值 为 Integer并且值为3的元素
     li.remove(new Integer(3));
     System.out.println(li);
     
     li.add("aa");
     li.add("aa2");
     li.add("aa3");
     for (Object object : li) {
     	System.out.println(object);
     }
     System.out.println("----");
     for (int i = 0; i < li.size(); i++) {
     	System.out.println(li.get(i));
    

1.4.2 LinkedList

1.4.2.1 基本使用
LinkedList : 底层是双向链表

  •  链表 : 链表中保存的是节点,每个节点中有三个元素
    
  •  	1 自身对象(添加的元素) , 2 上一个节点的地址 , 3 下一个节点的地址
    
  • 链表是没有下标的,内存空间也不是连续的,所以查询比较慢(和数组比较)

  •  由于内存空间不是连续的,只是保存上下节点的引用,随意添加删除比较快(和数组比较)
    
  • add(E e) : 添加到尾部

  • push(E e) : 添加到头部

  • addFirst(E e) : 添加到头部

  • addLast(E e) : 添加到尾部

  • offerFirst(E e) 添加到头部,成功返回true

  • offerLast(E e) : 添加到尾部,成功返回true

  • get(int index) : 返回指定下标对应的数据(链表没有下标,只是模拟下标,方便我们查询使用)

  • 本质 就调用了两个方法 : linkLast 和 linkFirst 所以没任何区别
    */
    public class _Collection06 {
    public static void main(String[] args) {
    LinkedList linkedList = new LinkedList();
    linkedList.add(1);
    linkedList.addFirst(2);
    linkedList.addLast(3);
    linkedList.push(4);
    linkedList.push(8);
    linkedList.offerFirst(5);
    linkedList.offerLast(6);
    // 遍历
    for (Object object : linkedList) {
    System.out.println(object);
    }
    System.out.println("----");
    for (int i = 0; i < linkedList.size(); i++) {
    System.out.println(linkedList.get(i));
    }

     // -------- 
     System.out.println("===");
     LinkedList linked = new LinkedList();
     linked.add("a");
     linked.add("b");
     linked.add("c");
     System.out.println(linked.size());
     System.out.println(linked.get(2));
    

    }

1.4.2.2.4 获取-get

校验下标

获取数据

Get只是模拟下标获取的方式而已,其实本质就是遍历,从头挨个找
只不过做了一定的判断,判断是找前半截还是后半截,来决定 是正序遍历还是倒叙遍历
本质就是循环通过next一个一个的节点去找,所以这个get和ArrayList中的get完全不是一回事,ArrayList中就是封装了下标访问方式而已,下面是ArrayList的get方法实现

LinkedList : 底层是双向链表

  •  链表 : 链表中保存的是节点,每个节点中有三个元素
    
  •  	1 自身对象(添加的元素) , 2 上一个节点的地址 , 3 下一个节点的地址
    
  • 链表是没有下标的,内存空间也不是连续的,所以查询比较慢(和数组比较)

  •  由于内存空间不是连续的,只是保存上下节点的引用,随意添加删除比较快(和数组比较)
    
  • add(E e) : 添加到尾部

  • push(E e) : 添加到头部

  • addFirst(E e) : 添加到头部

  • addLast(E e) : 添加到尾部

  • offerFirst(E e) 添加到头部,成功返回true

  • offerLast(E e) : 添加到尾部,成功返回true

  • get(int index) : 返回指定下标对应的数据(链表没有下标,只是模拟下标,方便我们查询使用)

  • 本质 就调用了两个方法 : linkLast 和 linkFirst 所以没任何区别
    */
    public class _Collection06 {
    public static void main(String[] args) {
    LinkedList linkedList = new LinkedList();
    linkedList.add(1);
    linkedList.addFirst(2);
    linkedList.addLast(3);
    linkedList.push(4);
    linkedList.push(8);
    linkedList.offerFirst(5);
    linkedList.offerLast(6);
    // 遍历
    for (Object object : linkedList) {
    System.out.println(object);
    }
    System.out.println("----");
    for (int i = 0; i < linkedList.size(); i++) {
    System.out.println(linkedList.get(i));
    }

     // -------- 
     System.out.println("===");
     LinkedList linked = new LinkedList();
     linked.add("a");
     linked.add("b");
     linked.add("c");
     System.out.println(linked.size());
     System.out.println(linked.get(2));
    

    }

  • TreeSet : 元素必须有序,添加的元素会按照某种规则自动排序

  • 想要使用TreeSet,元素必须要排序

  •  数字 : 默认从小到大
    
  •  字符串 : 默认比较每位ASCII码
    
  •  日期 : 默认比较自然日期 昨天-今天-明天
    

*/
public class _Collection08 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet();
treeSet.add(1);
treeSet.add(3);
treeSet.add(2);
treeSet.add(7);
// 上面是数字,下面如果是字符串就会导致 报错,因为添加的时候需要比较元素大小,而不同类型 是没有可比性的
// treeSet.add(“a”);
for (Object object : treeSet) {
System.out.println(object);
}
System.out.println("----");
TreeSet treeSet2 = new TreeSet();
treeSet2.add(“a”);
treeSet2.add(“1”);
// 如果有多个字符,先比较第一位,如果第一位不同,则第一位小的在上面
// 如果第一位相同,再比较第二位,以此类推
treeSet2.add(“11”);
treeSet2.add(“101”);
treeSet2.add(“b”);
treeSet2.add(“n”);
for (Object object : treeSet2) {
System.out.println(object);
}
}

  • 比较器有两种 : 1 元素自身比较器, 2 比较器类

  • 字符串,Integer,Date可以排序,因为都实现了 implements Comparable

  • 因为使用treeSet在进行数据添加的时候,会自动调用该对象的compareTo()方法和集合内元素进行比较

  • 想要存储自定义类型需要实现该接口
    */
    public class _Collection09 {
    public static void main(String[] args) {
    TreeSet treeSet = new TreeSet();
    User user1 = new User(11);
    User user2 = new User(13);
    User user3 = new User(6);
    treeSet.add(user1);
    treeSet.add(user2);
    treeSet.add(user3);
    System.out.println(treeSet.size());

     for (Object object : treeSet) {
     	System.out.println(object);
     }
    

    }
    }

class User implements Comparable{
private int age;

public int getAge() {
	return age;
}

public void setAge(int age) {
	this.age = age;
}

public User(int age) {
	super();
	this.age = age;
}

@Override
public String toString() {
	return "User [age=" + age + "]";
}

@Override
public int compareTo(Object o) {
	// this 是当前对象
	// o 是集合内对象
	// 并且 返回值为0 表示 相等,则不添加
	// 返回大于0 的 表示 要添加的元素大,则放到后面
	// 返回小于0 的 表示 要添加的元素小,则放到前面

	User user = (User) o;
	// 升序
	return this.age - user.age;
	// 降序
	// return this.age - user.age;
}

学习时间:

学习产出:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值