java中List与Set的常用用法

java中的集合主要分为三种:Set(集)、List(列表)、Map(映射)

下图为List、Set和Collection的联系,我们可以看出List和Set均继承自Collection,值得注意的是List、Set和Collection都为接口,不能直接实例化对象。List的两个实现类为ArrayList和LinkedList。




1.List集合的元素是有序的(取出顺序和存储顺序一致),元素可以重复

(1)ArrayList:继承了List的特点,底层数据结构是数组,因此它的查询速度快,但是增删速度慢。他是线程不安全的,效率高。

(2)LinkedList:同样继承了List的特点,底层数据结构是链表,所以它的增删速度快,查询速度慢。线程不安全、效率高。


新建一个测试学生类,这里只说引用类型,不讨论基本类型,后面不再论述。

<span style="font-size:18px;">public class Student {
	private String name;	//学生姓名	
	private int age;		//学生姓名
	
	//构造函数
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	//重写	toString()方法
	public String toString() {
		return "姓名:" + name + "\t 年龄:" + age;
	}
	
}

</span>
鉴于篇幅原因,这里只给出ArrayList的代码,因为LinkedList和ArrayList一样的。
<span style="font-size:18px;">public static void main(String[] args) {
		//创建一个ArrayList的集合
		ArrayList<Student>  list = new ArrayList<Student>();
		Student s1 = new Student("张三", 19);		//创建学生对象
		Student s2 = new Student("李四", 17);		
		Student s3 = new Student("小明", 18);
		Student s4 = new Student("小红", 22);
		Student s5 = new Student("李四", 17);
		list.add(s1);   //增加成员
		list.add(s2); 
		list.add(s3); 
		list.add(s4); 
		list.add(s5); 
		//有三种遍历方式
		
		//1.迭代器
//		Iterator<Student> iterator = list.iterator();
//		while (iterator.hasNext()) {
//			System.out.println(iterator.next());
//		}
		
		//2.for循环遍历
//		for (int i = 0; i < list.size(); i++) {
//			System.out.println(list.get(i));
//		}
		
		//3.增强for循环
		for (Student student : list) {
			System.out.println(student);
		}
	}</span>

通过重写Collectios的sort方法可以实现自定排序,以上面为例,按年龄从小到大排序:

<span style="font-size:18px;">//重写sort方法,通过匿名内部类实现
		Collections.sort(list,new Comparator<Student>() {

			@Override
			public int compare(Student o1, Student o2) {
				if((o1.getAge()-o2.getAge())>0){
					return 1;
				}else if((o1.getAge()-o2.getAge())<0){
					return -1;
				}else
				return 0;
			}
		});</span>

还可以通过在自定义类(Student类)中实现Comparable接口,重写compareTo()方法来实现自定义排序,按年龄从大到小排序:
<span style="font-size:18px;">@Override
	public int compareTo(Student o) {
		if((this.getAge()-o.getAge())>0){
			return 1;
		}else if((this.getAge()-o.getAge())<0){
			return -1;
		}else
		return 0;
	}</span>

1.Set集合的元素是唯一的,不可重复(有两种遍历方式:1.迭代器,2.增强for.代码参照上面)

(1)HashSet:继承了Set的特点,元素唯一,但是无序。底层数据结构是哈希表,通过重写HashCode()方法和equals()方法可以保证元素的唯一性。

(2)TreeSet:继承了Set的特点,元素唯一而且有序(使用元素的自然顺序对元素进行排序,或者根据创建 set时提供的 Comparator进行排序,具体取决于使用的构造方法)。底层数据结构是二叉树,通过Compareable接口的compareTo()方法来保证元素的唯一性。

<span style="font-size:18px;">public static void main(String[] args) {
		//创建一个HashSet的集合
		HashSet<Student> hs = new HashSet<Student>();
		Student s1 = new Student("张三", 19);		//创建学生对象
		Student s2 = new Student("李四", 17);		
		Student s3 = new Student("小明", 18);
		Student s4 = new Student("小红", 22);
		Student s5 = new Student("李四", 17);
		hs.add(s1);   //增加成员
		hs.add(s2); 
		hs.add(s3); 
		hs.add(s4); 
		hs.add(s5); 
		
		for (Student student : hs) {
			System.out.println(student);
		}</span>

运行上面的程序我们发现,咦,怎么有两个 "李四",17 ,这是因为没有重写HashCode()方法和equals()方法,导致元素不是唯一的,解决方案就是在Student类中重写HashCode()方法和equals()方法即可。

自动重写HashCode()方法和equals()方法步骤:右击选择Source,找到Generate hashCode() and equals(),点击去,全选确定即可,系统会自动帮你重写。代码入下:

<span style="font-size:18px;">@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}</span>
运行后发现李四只剩一个了,这是因为重写了HashCode()方法和equals()方法,保证了元素的唯一性。
下面是TreeSet的:

<span style="font-size:18px;">public static void main(String[] args) {
		//创建一个TreeSet的集合
		TreeSet<Student> hs = new TreeSet<Student>();
		Student s1 = new Student("张三", 19);		//创建学生对象
		Student s2 = new Student("李四", 17);		
		Student s3 = new Student("小明", 18);
		Student s4 = new Student("小红", 22);
		Student s5 = new Student("李四", 17);
		hs.add(s1);   //增加成员
		hs.add(s2); 
		hs.add(s3); 
		hs.add(s4); 
		hs.add(s5); 
		
		for (Student student : hs) {
			System.out.println(student);
		}
	}</span>

运行上面的代码会发现error:Exception in thread "main" java.lang.ClassCastException.这又是怎么回事?这是因为
TreeSet通过Compareable接口的compareTo()方法来保证元素的唯一性。可以通过下面两种方式来解决:

1.自定义类(Student)继承Comparable接口重写compareTo()方法来实现

以上面Student类为例,按年龄从小到大排序

<span style="font-size:18px;">	@Override
	public int compareTo(Student o) {
		if((this.getAge()-o.getAge())>0){
			return 1;
		}else if((this.getAge()-o.getAge())<0){
			return -1;
		}else
		return 0;
	}</span>

对于这种方式,TreeSet采用的构造器应当是无参的,也就是使用元素的自然顺序对元素进行排序。

2.创建set集合的时候,传入Comparator进行排序,进行排序,也叫作比较器排序

public static void main(String[] args) {
		//创建一个TreeSet的集合
		TreeSet<Student> hs = new TreeSet<Student>(new Comparator<Student>() {

			@Override
			public int compare(Student o1, Student o2) {
				int num1 = o1.getAge() - o2.getAge();
				int num2 = num1==0?o1.getName().compareTo(o2.getName()):num1;
				return num2;
			}
		});
		Student s1 = new Student("张三", 19);		//创建学生对象
		Student s2 = new Student("李四", 17);		
		Student s3 = new Student("小明", 18);
		Student s4 = new Student("小红", 22);
		Student s5 = new Student("李四", 17);
		hs.add(s1);   //增加成员
		hs.add(s2); 
		hs.add(s3); 
		hs.add(s4); 
		hs.add(s5); 
		
		for (Student student : hs) {
			System.out.println(student);
		}
	}
这里使用了内部类,也达到了同样的目的。





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值