Linux软件安装 测试用例 跨域 mysql overflow winforms process playframework ios7 nosql vue配置 后台界面模板 websocket库 android自定义控件 python for循环 python打开文件 python正则表达 python程序代码 java9 java简介 java变量类型 java中的对象 linux中sudo 嵌入式linux驱动程序设计从入门到精通 两表关联查询 计算机网络自顶向下 渐变事件 pr缩放 程序员面试宝典 魔兽七个人 assist是什么意思 程序卸载 司司网吧 vscode全局搜索 斑驳纹理 xmind画流程图 hdcp是什么 微信问卷调查怎么做 捷速pdf编辑器 python字符串
当前位置: 首页 > 学习教程  > 编程语言

java学习笔记day17集合概述、List、Set

2021/1/22 23:09:18 文章标签:

1. Collection 1.1 概述 通过继承体系发现,集合中两大分类List和Set, 并且 两个都继承了Collection,那也就意味着Collection中的方法是List和Set都有的。 Collection 集合只能保存引用数据类型,不能保存基本数据类型 因为 底层就是 Object[] 数组,既然是Object 所…

1. Collection
1.1 概述

  • 通过继承体系发现,集合中两大分类List和Set, 并且 两个都继承了Collection,那也就意味着Collection中的方法是List和Set都有的。

  • Collection 集合只能保存引用数据类型,不能保存基本数据类型

  • 因为 底层就是 Object[] 数组,既然是Object 所以 即可以说只能保存Object单一元素,也可以说可以保存任何元素,因为Object是祖类,所有类型都会发生向上转型(多态)

  • 基本类型真的不能存吗? 真的,因为基本类型和Object没有关系,但是 可以把基本类型转换为对应的包装类类型,而 包装类 是Object的子类,这样就能间接存储基本类型了

  • 常用方法 :

  •  	boolean add() : 添加元素
    
  •  	void clear() : 清空集合
    
  •  	boolean remove() 删除某个元素
    
  •  	boolean isEmpty() 判断集合中是否为空
    
  •  	boolean contains() : 是否包含某个元素
    
  •  	int  size() 返回集合中 元素个数
    

下面是关于上述方法的一些代码测试:

public static void main(String[] args) {
         //接口不能创建对象,我们以ArrayList为例,由于发生多态,丢失了ArrayList的特有方法
		//所以我们现在能够调用的方法都是Collection中的
		Collection c1=new ArrayList();
		//判断集合中是否为空
		System.out.println(c1.isEmpty());
		
		//添加元素
		c1.add("as");
		//12为int类型的,会先自动装箱为Integer类型的,然后再向上转型为Object类型的
		c1.add(12);
		
		Object o1=new Object();
		c1.add(o1);
		// size不是数组的长度,而是数组中已经添加的元素个数
		System.out.println(c1.size());
		//转数组
		Object[] arr=c1.toArray();
		for (Object object : arr) {
			System.out.println(object);
		}
       
		//删除,12为int类型的,自动装箱成Integer类型的,然后向上转型成Object类的
		c1.remove(12);
		//重新获取数组
		arr=c1.toArray();
		for (Object object : arr) {
			System.out.println(object);
		}
		// 清空数组中元素
		c1.clear();
		//输出现有数组中元素的个数
		System.out.println(c1.size());
	}

来深入理解一下

  • 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) {
          //创建集合
		Collection c=new ArrayList();
		Integer i1=new Integer(1);
		Integer i2=new Integer(2);
		//包装类是Object类的子类
		c.add(i1);
		c.add(i2);
		Integer i4=new Integer(2);
		//false 因为==比较引用类型比较的是地址,new了两次
		System.out.println(i4==i2);
		//true,因为调用的是Integer类的equals方法,重写了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;
	}

}

2.Iterator
Iterator是迭代器,迭代器是一种模式,它可以使序列类型的数据结构的遍历行为和被遍历的对象分离
我们无需关心该序列底层数据结构是什么,只要拿到这个对象,使用迭代器就可以遍历这个对象的内部数据

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

Iterator的方法
1 boolean hasNext(): 判断光标下一位是否还有元素,有就返回true,没有就返回false,
 生成迭代器的时候,光标不是指向第一个元素的,而是在最顶端,没有指向任何元素,
 光标不会自动复位,使用完之后,必须重新生成
 2 E next():把光标向下移动一位,并返回该位上的数据
 3 remove():删除当前光标指向的元素
 方法使用的顺序是1,2,3

迭代器相当于一个索引器
迭代器一旦创建,如果集合中添加或者删除元素,那么迭代器必须重新生成,因为个数变了
否则调用next()方法会报错,但是更改数据不用重新生成
增强for循环,foreach就是为了让用iterator循环访问的形式变简单,写起来方便,但是需要有删除操作的话还是需要用原来的iterator形式
forEach也是迭代器,使用forEach和使用iterator一样,不能添加或删除集合数据,但是更改可以
而普通for和while这种遍历,都是和数据结构存储有关系的,比如数组需要使用arr[index]去访问,可以进行添加和删除操作
使用迭代器进行遍历时,如果需要删除元素,只能使用迭代器的remove()方法,不能使用集合的remove方法

public static void main(String[] args) {
          //创建集合
		Collection c=new ArrayList();
		//向集合里添加元素
		//int 自动装箱成Integer类型,然后Integer类型在向上转型成Object类型
		c.add(12);
		c.add("as");
		//double自动装箱成Double类型,然后Double类型在向上转型成Object类型
		c.add(2.4);
		c.add(false);
		c.add(null);
		//创建迭代器
		Iterator it=c.iterator();
		//判断光标的下一位还有没有元素,没有就终止,.hasNext()返回布尔类型的值
		while(it.hasNext()){
			//把光标向下移动一位,并返回该位上的值
			Object o=it.next();
			System.out.println(o);
		}
		//光标已经落在了最后一位,下一位没有元素了
		// false
		System.out.println(it.hasNext());
	    // 如果此时 添加或者删除元素
		c.add(1);
		
		// 只要迭代器生成,集合添加或者删除,再使用这个迭代器就会报错
		//  java.util.ConcurrentModificationException
		// 如果要使用迭代器,需要重新生成
		it=c.iterator();
		while(it.hasNext()){
			// 能进来说明有
			//把光标向下移动一位,并将该位上的数据给到o
			Object o = it.next();
			// 生成迭代器不能使用集合的remove,除非重新生成,否则报错
           //c.remove(1);
			// 但是可以使用迭代器的remove进行删除元素的操作,删除当前光标指向的元素
			it.remove();
			System.out.println(o);
		}
		// 循环删除完了
		//输出集合中的元素个数
		System.out.println(c.size());
	}

3.List

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

  • 存入顺序和取出顺序是一致的,并且有指定的下标可以表示数据的唯一性,所以可以存在重复数据

  • 底层实现

  •  	ArrayList : 底层是数组,查询效率较高,添加和删除效率较低
    
  •  	LinkedList : 底层是双向链表,查询效率较低,添加和删除效率较高
    

Vector 已经过时了,ArrayList是Vector的升级版,而Vector属于线程安全,ArrayList属于非线程安全,所以ArrayList效率较高

ArrayList

public class Collection05 {
     /*ArrayList : 底层索引数组,下标0开始 初始化容量为 10 ,扩大容量为 原始容量的1.5倍.非线程安全,效率高
 * 
 * Vector : 初始化容量为10 , 扩大容量为 原始容量的 2 倍,线程安全,效率低
 * 
 * 所以 Vector已经废弃
 * 
 * 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 static void main(String[] args)  {
		List li = new ArrayList();
		// 数组中 : 数组只能保存同一数据类型
		// 集合中 : 可以存储任意类型
		// 而ArrayList底层又是数组,很简单,因为ArrayList底层是Object[] 数组,  
		// 同理 我们单独声明Object[]数组的话,也可以说可以存储任意数据
		// 因为任何数据 都可以转型为Object类型,包括基本(自动装箱再向上转型)
		
		// 把数据添加到尾部
		li.add(1);
		// 把指定元素,插入到指定位置,该位置上的元素统一向后移动
		li.add(0, 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));
		}
	}

}

LinkedList

public class Collection06 {
//	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 static void main(String[] args) {
		//底层是双向链表
		LinkedList linkedList = new LinkedList();
		//添加到尾部
		linkedList.add(1);
		//添加到头部
		linkedList.addFirst(2);
		//添加到尾部
		linkedList.addLast(3);
		//添加到头部
		linkedList.push(4);
		//添加到头部,成功返回true
		linkedList.offerFirst(5);
		//添加到尾部,成功返回true
		linkedList.offerLast(6);
		//foreach 遍历
		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));
		
	}

}

4、Set
Set元素特点 : 无序不可重复

  • TreeSet : 底层红黑树
  • HashSet : 底层散列表
public class Collection07 {
//Set元素特定:无序,不可重复
	public static void main(String[] args) {
		Set s = new TreeSet();
		//添加到尾部
		s.add(1);
		s.add(3);
		//输出集合中元素个数
		System.out.println(s.size());
		//Set覆写了toString方法
		System.out.println(s);
		//遍历
		for (Object object : s) {
			System.out.println(object);
		}
	}

}

TreeSet

  • 元素必须有序,添加的元素会按照某种规则自动排序,所以添加元素时需要比较元素,那么注意添加不同类型时会报错

  • 想要使用TreeSet,元素必须要排序
    数字 : 默认从小到大
    字符串 : 默认比较每位ASCII码
    日期 : 默认比较自然日期 昨天-今天-明天

    下面是代码

public static void main(String[] args) {
		//创建TreeSet类的对象treeSet
		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);
		}
	}
public class Collection09 {
//	比较器有两种 : 1 元素自身比较器, 2 比较器类
//	   
//	  为什么字符串,Integer,Date可以排序?
//	   		因为都实现了 implements Comparable 
//	   
//	   因为使用treeSet在进行数据添加的时候,会自动调用该对象的compareTo()方法和集合内元素进行比较
//	   
//	   如果我们想要存储自定义类型怎么办?
//	   		需要实现comparable接口才行
	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);
		//添加元素时自动调用User类的compareTo()方法和集合内元素进行比较
		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 + "]";
	}
   
	//实现Comparable接口覆写compareTo方法
	@Override
	public int compareTo(Object o) {
		// this 是当前对象
		// o 是集合内对象
		// 并且 返回值为0 表示 相等,则不添加,set不允许有重复元素
		// 返回大于0 的 表示 要添加的元素大,则放到后面
		// 返回小于0 的 表示 要添加的元素小,则放到前面

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


本文链接: http://www.dtmao.cc/news_show_630873.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?