Java基础(21)——集合ArrayList、LinkedList、Set、HashSet、TreeSet详解


版权声明

  • 本文原创作者:清风不渡
  • 博客地址:https://blog.csdn.net/WXKKang

一、List实现类

1、ArrayList

  在实际的开发中,ArrayList是使用频率最高的一个集合实现类

(1)原理

  ArrayList底层维护了一个Object[]用于存储对象,默认数组的长度是10。当默认的或者指定的容量不够存储对象的时候,容量自动增长为原来的容量的1.5倍。
  由于底层使用数组实现,在增加和删除的时候会牵扯到数组增容和拷贝元素,所以效率比较慢。但是数组可以直接按索引查找元素,所以查找时较快。
  例如,假设向数组的0下标位置添加元素,那么原来的下标位置的元素需要整体往后移,并且数组可能还要增容。一旦增容, 就需要要将老数组的内容拷贝到新数组中。所以数组的增删的效率是很低的。

(2)例子

  要求:去除ArrayList集合中的重复元素。
  思路:循环遍历该集合,每取出一个放置在新的集合中,但是在放置之前,需要先判断新的集合是否以包含了新的元素。这里使用contains 方法,需要对象实现equals方法。
  代码实现:

package cn.com;

import java.util.ArrayList;

public class Demo {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<String>();
		// add方法将元素加入最后
		list.add("Jack");
		list.add("Lucy");
		list.add("Lucy");
		list.add("Bruce");
		
		ArrayList<String> list2 = new ArrayList<String>();
		for(int i=0;i<list.size();i++) {
			String str = list.get(i);
			if (!(list2.contains(str))) {
				list2.add(str);
			}
		}
		System.out.println(list2);
	}
}

2、LinkedList

(1)原理

  由于LinkedList在底层使用链表实现存储结构,需要让上一个元素记住下一个元素,所以每个元素中保存的有下一个元素的位置。虽然LinkedList中也有下标,但是查找的时候需要从头往下找,显然是没有数组查找快。但是,链表在插入新元素的时候,只需要让前一个元素记住新元素,让新元素记住下一个元素就可以了,所以插入很快。

(2)特有方法

在这里插入图片描述
  示例如下:

package cn.com;

import java.util.Iterator;
import java.util.LinkedList;

public class Demo {

	public static void main(String[] args) {
		LinkedList<String> list = new LinkedList<>();
		list.add("北京");
		list.add("上海");
		list.add("成都");
		
		list.addFirst("甘肃");
		String first = list.getFirst();
		System.out.println("第一个元素:"+first);
		list.addLast(null);
		String last = list.getLast();
		System.out.println("最后一个元素:"+last);
		
		System.out.println("删除第一个元素!"+list.removeFirst());
		System.out.println("删除最后一个元素!"+list.removeLast());
		
		//逆序迭代
		Iterator<String> descendingIterator = list.descendingIterator();
		while(descendingIterator.hasNext()) {
			System.out.print(descendingIterator.next()+"\t");
		}
	}		
}

  运行结果:
在这里插入图片描述

二、Set

1、Set

  Set中元素是无序存放的,即元素存入和取出的顺序不一定相同,并且集合中元素不能重复。其中,HashSet 是一种常用的Set

(1)存储原理

  和List不同的是,Set中的对象不是按元素加入到集合中的先后顺序依次摆放,因此,Set中是没有索引的,也不能按索引访问集合中的对象。
  在Set内部的存储结构使用了散列算法(HASH 算法),按对象的散列值决定存放位置,也按照散列值检索对象。由于散列值的无序特点,因此Set的行为表现为一个无序的集合,图示如下:
在这里插入图片描述
  例如:现在有两个创建好的对象要加入到Set中:

Student s1 = new Student("Tom", "男", 12);
Student s2 = new Student("Lucy", "女", 12);

  现在分析Set中存放对象的内部行为:
  1、最开始是一个空的集合,如下:

Set<Student> set = new HashSet<Student>();

在这里插入图片描述
  2、现在加入s1,如下:

set.add(s1);

在这里插入图片描述
  3、现在加入s2,如下:

set.add(s2);

在这里插入图片描述
  小结:
  1、HashSet调用对象的hashCode()方法得到对象的hashCode值,并依据hashCode值决定该对象在HashSet中存放的位置
  2、Hashset判断两个对象是否相等的依据:两个对象通过equals()方法比较后结果为相等,并且两个对象的hashCode()方法得到对象的hashCode值也相等
  3、规则:如果两个对象通过equals()方法比较后结果为相等,那么两个对象的hashCode()方法得到对象的hashCode值也应该是相等的
  4、建议:利用IDE重写hashCode( )和equals( )方法

(2)重复元素

  在Java中,重复元素使用Object类中的hashCode和equals判断。在类中重写了hashCode和equals,当两个的hashCode方法返回相同值并且两个对象的equals返回true时,两个对象是相同的。
  有一些常见的重复元素情形:
  1、所有null常量都是重复元素
  2、相同对象的不同引用变量是重复元素
  3、String 对象已重写hashCode和equals;即只要两个String 对象的个通过equals( )方法比较后结果为相等,那么这两个String对象的hashCode()方法得到对象的hashCode值也是相等的。简单地说:两个String对象的值相同时,就认为这两个String对象是重复的。
  例子如下:

package cn.com;

import java.util.HashSet;
import java.util.Set;

public class Demo {

	public static void main(String[] args) {
		//添加null值
		Set<String> set1 = new HashSet<String>();
		set1.add(null);
		//输出set大小
		System.out.println("set1的长度:"+set1.size());
		//null对象不能重复加入,这是替换
		set1.add(null);
		//输出长度和上面的相等
		System.out.println("set1的长度:"+set1.size());
		
		//同一对象引用多个变量
		Set<Student> set2 = new HashSet<Student>();
		Student student1 = new Student("Tom", "man", 12);
		Student student2 = student1;
		//student1成功加入
		set2.add(student1);
		System.out.println("set2的长度:"+set2.size());
		//第二次替换第一次
		set2.add(student2);
		System.out.println("set2的长度:"+set2.size());
		 
		//添加相同值的String对象
		Set<String> set3 = new HashSet<String>();
		String str1 = "Hello";
		String str2 = new String("Hello");
		//通过双等号证明str1和str2不是一个对象
		System.out.println("str1和str2的地址比较:"+(str1==str2));
		//通过equals方法证明str1和str2内容
		System.out.println("str1和str2的内容比较:"+str1.equals(str2));
		//str1成功添加
		set3.add(str1);
		System.out.println("set3的长度:"+set3.size());
		//str2没有增加到集合里
		set3.add(str2);
		System.out.println("set3的长度:"+set3.size());
		
	}		
}

2、HashSet

  使用Set集合都是需要去掉重复元素的。如果在存储的时候逐个equals()比较,效率较低,哈希算法提高了去重复的效率,降低了使用equals()方法的次数。当HashSet调用add()方法存储对象的时候,先调用对象的hashCode()方法得到一个哈希值,然后在集合中查找是否有哈希值相同的对象,如果没有哈希值相同的对象就直接存入集合,如果有哈希值相同的对象,就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入,true 则不存入。
  HashSet的常见操作如下:

package cn.com;

import java.util.HashSet;
import java.util.Iterator;

public class Demo {

	public static void main(String[] args) {
		//创建一个空的集合
		HashSet<Student> set = new HashSet<Student>();
		//创建Student对象
		Student s1 = new Student("Lucy", "女", 17);
		Student s2 = new Student("Tom", "男", 18);
		//将对象添加至set集合中
		set.add(s1);
		set.add(s2);
		//输出集合大小(即长度)
		System.out.println(set.size());
		//删除集合中的s2元素
		set.remove(s2);
		//使用迭代器遍历集合
		Iterator<Student> iterator = set.iterator();
		while(iterator.hasNext()) {
			Student student = iterator.next();
			System.out.println(student.getName());
		}
	}		
}

3、TreeSet

  TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。.

(1)引入

  设计一个数据结构用于保存数据,要求不能重复存储元素,并且对数据支持排序
  已有数据结构分析:
  ArrayList、LinkedList 不能去除重复数据。
  HashSet可以去除重复,但是不支持排序。
  这里引入一个新的数据结构::TreeSet。

(2)排序接口Comparable

  在Java中提供了一个对象比较接口Comparable,它只有一个方法:
在这里插入图片描述
  所有加入TreeSet的元素必须实现Comparable接口,否则会抛出异常,在TreeSet内部使用Comparable接口对元素排序。和HashSet相比,它的效率较低。

(3)示例

  实现对学生排序,如果年龄相同就再比较姓名
  学生类代码:

package cn.com;

public class Student implements Comparable<Student>{
	
	private String name;
	private String gender;
	private Integer age;

	public Student() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Student(String name, String gender, Integer age) {
		super();
		this.name = name;
		this.gender = gender;
		this.age = age;
	}


	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", gender=" + gender + ", age=" + age + "]";
	}
	
	//实现Comparable中的compareTo方法
	@Override
	public int compareTo(Student o) {
		int age1 = this.age;
		int age2 = o.getAge();
		if(age1>age2) {
			return 1;
		}
		if (age1<age2) {
			return -1;
		}
		return this.name.compareTo(o.getName());
	}
}

  测试类代码:

package cn.com;

import java.util.Iterator;
import java.util.TreeSet;

public class Demo {

	public static void main(String[] args) {
		//创建一个空的集合
		TreeSet<Student> set = new TreeSet<Student>();
		//创建Student对象
		Student s1 = new Student("Lucy", "女", 17);
		Student s2 = new Student("Tom", "男", 18);
		Student s3 = new Student("Jack", "man", 17);
		//将对象添加至set集合中
		set.add(s1);
		set.add(s2);
		set.add(s3);
		//使用迭代器遍历集合
		Iterator<Student> iterator = set.iterator();
		while(iterator.hasNext()) {
			System.out.println(iterator.next());
		}
	}		
}

  运行结果:
在这里插入图片描述
  由运行结果我们可以看到,Jack是后添加的但是它是在Tom前面,并且在与Lucy年龄相同的情况下依照姓名进行了排序

4、LinkedHashSet

  LinkedHashSet是具有可预知迭代顺序的Set接口的哈希表和链接列表实现。此实现与HashSet的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可为插入顺序或是访问顺序,例如:

package cn.com;

import java.util.LinkedHashSet;

public class Demo {

	public static void main(String[] args) {
		//创建一个空的集合
		LinkedHashSet<String> set = new LinkedHashSet<String>();
		//添加元素
		set.add("a");
		set.add("a");
		set.add("a");
		set.add("a");
		set.add("b");
		set.add("c");
		set.add("d");
		//打印集合
		System.out.println(set);
	}		
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值