Java进阶——集合

  • 数组的长度是固定的,当需要处理长度未知或不固定的数据时,就需要用到集合

遵循Collection接口

遵循List子接口

  • list集合中的数据都是单一的
  • 按照插入顺序保存数据,数据是可以重复的
  • 具体的实现类有ArrayList和LinkedList

ArrayList类

  • 底层用顺序表实现
  • 创建ArrayList对象时不需要传构造参数,直接new就行,此时底层数组为空数组
  • 可以给构造参数传递一个int值,用于设定底层数组的长度
  • ArrayList有自动扩容功能,如果存储数据超出当前数组的长度,会自动创建一个更长的新数组,把之前的数据拷过来,和越界的数据连接成新数组,不会出现索引越界,并抛弃掉旧数组
  • ArrayList提供了add方法用于增加数据,有一个参数的add方法(参数为插入的数据,默认插在尾部),也有两个参数的add方法(参数为索引和插入的数据,可以在指定位置插入数据)
  • addAll方法用于将另一个ArrayList对象整体插入到尾部
  • remove方法用于删除指定位置的数据,传一个参数(索引),并返回删除的值
  • clear方法用于清空集合中的所有数据
  • removeAll方法用于清空指定集合的数据
  • set方法用于修改指定位置的数据,传两个参数(索引,修改后的值),并返回修改前的值
  • size方法用于获取存储数据的个数
  • get方法用于获取指定位置的数据,传一个参数(索引从0开始)
  • isEmpty方法用于判断集合是否为空
  • contains方法用于判断集合中是否存在某个数据
  • indexOf方法用于获取某个数据在集合中的索引,如果数据不存在返回-1,如果存在两个一样的数据返回第一个位置
  • lastIndexOf方法用于获取某个数据在集合中最后一次出现的索引
  1. 其它
  • toArray方法将集合转换成数组类型
  • clone方法克隆一个新的集合对象
  • sort方法实现了排序
ArrayList l = new ArrayList(); // 创建ArrayList实例

// 增
l.add("you"); // 用一个参数的add方法在尾部插入数据
l.add(1, "I"); // 用两个参数的add方法在索引处插入数据,插入方法与顺序表一致
ArrayList l1 = new ArrayList(); // 创建ArrayList实例
l.addAll(l1); // addAll方法将l1集合完整插入到尾部

// 删
removeValue = l.remove(0); // remove方法用于删除指定位置的数据,并返回删除的值,此时removeValue为"me"
l.removeAll(l1); // 清空l1集合的数据
l.clear(); // 清空所有数据

// 改
oldValue = l.set(0, "me"); // set方法用于修改指定位置的数据,并返回修改前的值,此时oldValue为"you"

// 查
l.size(); // size方法获取存储的数据个数
l.get(0); // get方法获取指定位置的数据
// 如果关心数据位置,可以取到数据个数,用for循环使用get方法
// 如果不关心数据位置,可以用下面特殊的遍历方式
for(Object obj : l){
    
    
	System.out.println(obj);
}
l.isEmpty(); // 判断集合是否为空
l.contains("me"); // 判断集合中是否有元素“me”
l.indexOf("me"); // 返回元素“me”在集合中的第一个位置
l.lastIndexOf("me"); // 返回元素“me”在集合中的最后一个位置

// 其它
Object[] obj = l.toArray(); // 将集合转化成数组
Object[] obj1 = l.clone(); // 克隆一份集合
ArrayList l2 = (ArrayList )obj1;

LinkedList类

  • 底层用循环双链表实现
  • add方法可以增加数据,也可以在指定索引处增加一个数据,此处的索引并不是数组中真正的索引,而是链表元素中增加的表示元素顺序的名义上的索引
LinkedList l = new LinkedList();

// 增
l.add("1"); // 默认在尾部增加数据
l.push("aaa"); // 默认在头部增加数据
l.addFirst("2"); // 头插
l.addLast("3"); // 尾插
l.add(1, "4"); // 在索引1处插入元素4,此时结果为2 4 1 3
LinkedList l1 = new LinkedList();
l.addAll(l1); // 尾插整个链表

// 删
l.pop(); // 删除第一个数据
l.remove(o: "2"); // 删除某个元素
l.remove(index: 0); // 删除指定位置元素
l.removeFirst(); // 删除第一个元素
l.removeLast(); // 删除最后一个元素

// 改
l.set(0, "5"); // 修改指定位置的数据

// 查
l.getFirst(); // 获取第一个数据
l.getLast(); // 获取最后一个数据
for (Object o : l){
    
     // 遍历l
	打印o;
}
l.size();
l.isEmpty();
l.contains("1");
l.element(); // 获取第一个数据
l.indexOf("1");
l.LastIndexOf("1");
l.clear();

ArrayList类与LinkedList类的比较

  • 增加第一条数据,LinkedList更快
  • 增加第二条数据,ArrayList更快
  • 超过底层数组容量再增加数据,LinkedList更快
  • 插入数据,LinkedList更快

遵循Set子接口

  • 集,无序保存数据,数据是不可以重复的
  • 具体的实现类有HashSet

HashSet类

  • HashSet底层为顺序表+单链表,解决冲突的方式为链地址法
  • HashSet会自动抛弃一模一样的数据,即自动去重
  • HashSet数据是无序的
  • HashSet没有修改的方法,只能先删除后增加
  • HashSet没有直接查询的方法,只能遍历查询
  • HashSet提供addAll方法,可以把ArrayList对象完整增加,且自动去重
HashSet set = new HashSet();
set.add("you");
set.add("you"); // 只保存一个you
set.remove("you"); // 删除you

ArrayList l = new ArrayList();
set.addAll(l); // 把整个集合增加到set里
Object[] o = set.toArray(); // 把set变成数组
set.isEmpty();
set.size();
Object obj = set.clone();
set.contains("you");
set.clear();

遵循Queue子接口

  • 队列,先进先出
  • 具体的实现类有ArrayBlockingQueue

ArrayBlockingQueue类

  • 底层是有限制的循环队列,满了之后不允许入队
  • 创建ArrayBlockingQueue对象时必须说明队列长度n,长度超出n时发生阻塞
ArrayBlockingQueue queue = new ArrayBlockingQueue(2);

// 第一种添加数据的方法,添加到第三个时会报错
queue.add("a");
queue.add("b");
queue.add("c");

// 第二种添加数据的方法,添加到第三个时会阻塞,程序一直运行
queue.put("a");
queue.put("b");
queue.put("c");

// 第三种添加数据的方法,程序不会报错也不会报异常,添加到第三个时添加失败,c为false
boolean a = queue.offer("a");
boolean b = queue.offer("b");
boolean c = queue.offer("c");

// 从队列中取数据,按照顺序先进先出
queue.poll(); // 返回取出的数据,队空时再取会返回null
queue.take(); // 返回取出的数据,队空时再取会阻塞,程序一直运行

// 其它方法
queue.size();
queue.isEmpty();
queue.contains("a");
queue.clear();

遵循Map接口

  • map集合中的数据是成对的
  • 具体的实现类有HashMap和HashTable

HashMap类

  • 底层也是数组+单链表
  • 底层数组长度默认为16
  • 保存的不是单个数据,而是key value键值对
  • 也是无序存储,不能放重复数据
  • 根据key来判断是否为重复数据,只要key一样,就判断为重复数据,用新数据把旧数据覆盖掉
  • put方法既可以用来添加数据,也可以用来修改数据,当该地址已经存在与新数据的key一样的旧数据时,put方法会用新数据把旧数据覆盖掉,并把旧数据的value返回
  • putIfAbsent方法也可以用来添加数据,当该地址已经存在与新数据的key一样的旧数据时,putIfAbsent方法不会添加新数据
  • replace方法真正用于修改数据,当key不存在时,put方法会添加数据,而replace方法只会修改key存在的数据的value值,并把旧数据的value返回
  • HashMap用Iterator迭代器代替for循环,避免了因数据未实时更新而报的错
  • 进阶:单链表太长会影响查询速度,红黑二叉树可以解决这个问题
HashMap map = new HashMap();

map.put("a", "0"); // 此时相当于添加
map.put("a", "1"); // 此时相当于修改,put方法会用 a 1 覆盖掉 a 0 ,返回被改掉的”0“
map.put("b", "2");
map.putIfAbsent("b", "3"); // putIfAbsent方法不会添加 b 3
map.replace("b", "4"); // replace方法会直接把b的value改成4,并返回旧value

map.get("a"); // 查询,传入key,返回value
map.remove("a"); // 删除,传入key,删掉整个键值对
map.remove("a", "0"); // 删除,传入整个键值对,都匹配才删掉整个键值对

Set keys = map.keySet(); // 获取map中所有的key
map.containsKey("a"); // 判断map中有没有某个key
Collection values = map.values(); // 获取map中所有的value
map.containsValue("0"); // 判断map中有没有某个value
Set sntries = map.entrySet(); // 获取map中所有的键值对

// Iterator迭代器
Set keys = map.keySet(); // 获取map中所有的key
Iterator it = keys.iterator(); // 创建Iterator对象
while(iterator.hasNext()){
    
     // hasNext方法用于判断是否存在下一条数据
	String key = it.next();
	if("a".equals(key)){
    
    
		it.remove(); // 只能删除当前迭代到的数据
	}
}

Hashtable类

  • 底层也是数组,长度与HashMap不一样,为11
  • HashMap的key和value都可以是null,Hashtable不可以
  • 底层用的计算地址的算法不同,HashMap更复杂一些
  • 多线程访问时,HashMap性能较高,但安全性较差,操作二者基本一样

Arrays工具类

  • 有很多实用的静态方法,不需要创建对象就可以直接使用
  • toString方法可以将展示出来不好理解的int数组转换成好理解的字符串形式
  • sort方法可以实现排序
  • binarySearch方法可以用二分查找法在有序数组中找某个元素
  • equals方法可以比较两个数组的任意一段数据的内容,当该段数据位置与值完全相同且对应时,返回true
int[] i1 = {
    
    3,2,1,4,5} // 直接打印数组为hashcode地址
int[] i2 = {
    
    2,2,3,4,4} 
Arrays.toString(i1) //  打印出来就是[3,2,1,4,5]
Arrays.sort(i1); // 默认对i1进行升序排序,此时i1为[1,2,3,4,5]
Arrays.binarySearch(i1, 2); // 用二分查找法找元素2
Arrays.equals(i1, i2); // false
Arrays.equals(i1, 1, 4, i2, 1, 4); // true,只比较两个数组索引为1,2,3的元素,都为2 3 4

猜你喜欢

转载自blog.csdn.net/weixin_46838605/article/details/129883695