单列集合的特点与使用

 

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

                                                  单列集合
一.集合的分类
Collection     一次存一个对象, 单列集合
  List     可重复, 有索引,有序
   ArrayList  数组实现, 查找快, 线程不安全
   LinkedList  链表实现, 增删快, 线程不安全

Vector   数组实现, 线程安全
  Set      不可重复, 没索引,无序
   HashSet   使用哈希算法去重复, 效率高, 但元素无序
   TreeSet   TreeSet是用排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列
   LinkedHashSet HashSet的子类, 原理相同, 除了去重复之外还能保留存储顺序
   
List迭代(遍历)
  a.普通for循环, 使用get()逐个获取
  b.调用iterator()方法得到Iterator, 使用hasNext()和next()方法
  c.增强for循环, 只要可以使用Iterator的类都可以用
  d.Vector集合可以使用Enumeration的hasMoreElements()和nextElement()方法

二.HashSet(LinkedHashSet)

1.HashSet原理


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

实例:


  HashSet实例,  在一个集合中定义很多个重复元素,要求定义一个方法将重复元素去掉
  分析:在一个集合中有重复元素,先定义一个新的HashSet集合,然后把List集合中的元素存入Set集合,
   然后在清空原集合,把Set集合中的元素存入原集合就可以了.

package cn.itcast.test;

import java.util.ArrayList;
import java.util.LinkedHashSet;

public class Test1 {

	/**
	 * @param args
	 * 在一个集合中定义很多个重复元素,要求定义一个方法将重复元素去掉
	 */
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("a");
		list.add("a");
		list.add("a");
		list.add("b");
		list.add("b");
		list.add("b");
		list.add("c");
		list.add("c");
		list.add("c");
		list.add("c");
		
		System.out.println(list);
		getSingle(list);
		System.out.println(list);
	}

	private static void getSingle(ArrayList<String> list) {
		LinkedHashSet<String> lhs = new LinkedHashSet<>();
		lhs.addAll(list);				//将list集合中所有的元素添加到LinkedHashSet中,重复自动去掉
		list.clear();					//将原集合清空
		list.addAll(lhs);				//将去除重复的结果添加回原集合
	}

}


2.将自定义类的对象存入HashSet去重复
  类中必须重写hashCode()和equals()方法
  hashCode(): 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率)
  equals(): 属性相同返回true, 属性不同返回false,返回false的时候存储
  
   实例:自定义一个Person类,重写HashCode方法和equals方法.

 

package cn.itcast.bean;

public class Person implements Comparable<Person>{
	private String name;
	private int age;
	public Person() {
		super();
		
	}
	public Person(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
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	@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
	//eclipse重写的equals方法
	public boolean equals(Object obj) {
		//当调用的对象和传入的对象是同一个对象时
		if (this == obj)						
			return true;						
			//返回true
		//如果传入的对象为null,调用对象不为null
		if (obj == null)						
			return false;						//返回false
		//如果调用的字节码对象和传入的字节码对象不是同一个对象
		if (getClass() != obj.getClass())		
			return false;						//返回false
		//将obj强转为Person
		Person other = (Person) obj;			
		//如果调用的年龄不等于传入的年龄
		if (age != other.age)					
			return false;						//返回false
		//如果调用对象的name为null
		if (name == null) {						
			//如果传入的对象的name不为null
			if (other.name != null)				
				return false;					//返回false
		//如果调用对象的name不等于传入对象的name
		} else if (!name.equals(other.name))	
			return false;						//返回false
		//说明name和age一样返回true
		return true;							
	}
	public int compareTo(Person p) {
		int num = this.name.compareTo(p.name);
		return num == 0 ? this.age - p.age : num;
	}	
}


 


3.Set
  a.调用iterator()方法得到Iterator, 使用hasNext()和next()方法
  b.增强for循环, 只要可以使用Iterator的类都可以使用增强for循环

package cn.itcast.set;

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

public class Demo3_Iterator {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		HashSet<String> hs = new HashSet<>();
		hs.add("a");
		hs.add("b");
		hs.add("c");
		hs.add("d");
		
		Iterator<String> it = hs.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		
		for(String obj : hs) {
			System.out.println(obj);
		}
	}

}


三.TreeSet

 


1.特点

 


  TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列


2.使用方式


  a.自然顺序(Comparable)
   TreeSet类的add()方法中会把存入的对象提升为Comparable类型
   如果是自定义对象,必须实现 implements Comparable 接口.
   (增加哪个元素,哪个元素调用compareTo方法)
   调用对象的compareTo()方法和集合中的对象比较
   根据compareTo()方法返回的结果进行存储
  自然顺序比较的实例:在一个集合中存储了无序并且重复的字符串,定义一个方法,
     让其有序(字典顺序),而且还不能去除重复

package cn.itcast.test;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.TreeSet;

public class Test3 {

	/**
	 * @param args
	 * 
	 */
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("b");
		list.add("b");
		list.add("b");
		list.add("a");
		list.add("a");
		list.add("a");
		list.add("c");
		list.add("c");
		list.add("c");
		sort(list);
		System.out.println(list);
	}
	
	public static void sort(ArrayList<String> list) {//给TreeSet集合的构造函数传入比较器,比较器就是Comparator的子类对象	
		TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {	
			@Override
			//重写Comparator中的compare方法
			public int compare(String s1, String s2) {					
				//主要条件按照字典顺序比较
				//如果两个比较的字符串一样,就会返回0,返回0就不会存储在TreeSet集合中
				int num = s1.compareTo(s2);								
			//所以如果比较的结果是0就返回一个非0的数字就可以将重复的保留
				return num == 0 ? 1 : num;								
			}															
		});
		
		//将list集合中的所有元素添加到ts中,排序保留重复
		ts.addAll(list);						
		//将list清空
		list.clear();							
		//将ts中排序后的结果存储在list集合中
		list.addAll(ts);						
	}

b.比较器顺序(Comparator)
   创建TreeSet的时候可以制定 一个Comparator
   一般用匿名内部类:
    new Comparator(){
     public void compare(T s1, T s2){
      int num = s1.compareTo(s2)
     }
    }
   如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序
   add()方法内部会自动调用Comparator接口中compare()方法排序
   使用比较器的实例:
     * 请输入学生考试成绩:
     * 张三,80,80,80
     * 李四,70,75,65
     * 王五,90,95,80
     * 赵六,60,60,60
     * quit
     *
     * 排序后的学生信息:
     * 王五,90,95,80,265
     * 张三,80,80,80,240
     * 李四,70,75,65,210
     * 赵六,60,60,60,180
   分析:先定义一个Student类,使用匿名内部类,把比较器传入TreeSet的构造函数.


package cn.itcast.test;

import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;

public class Compare { 
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入学生成绩,格式是 姓名,数学成绩,语文成绩,英语成绩");
		TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				int num = s2.getSum() - s1.getSum();
				return num == 0 ? 1 : num;
			}
		});
		
		while(true) {
			String line = sc.nextLine();
			if("quit".equals(line))
				break;
			String[] arr = line.split(",");
			int math = Integer.parseInt(arr[1]);
			int chinese = Integer.parseInt(arr[2]);
			int english = Integer.parseInt(arr[3]);
			ts.add(new Student(arr[0], math, chinese, english));
		}
		
		System.out.println("排序后的学生信息:");
		
		for (Student student : ts) {
			System.out.println(student);
		}
	}

}


c.两种方式的区别
   TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
   TreeSet如果传入Comparator, 就优先按照Comparator的顺序进行比较.

 

 

 

 

 

 

### Set 集合特点 Set 是 Java 集合框架中的一种单列集合,其主要特点是: 1. **无序性**:Set 集合中的元素是无序的,这意味着存储顺序取出顺序不一致。例如,`HashSet` 使用哈希表来实现这种无序特性[^2]。 2. **唯一性**:Set 集合不允许重复元素存在。具体来说: - `HashSet` 通过 `hashCode()` `equals()` 方法确保元素的唯一性。 - `TreeSet` 则基于红黑树结构,不仅保证元素唯一,还提供排序功能。 - `LinkedHashSet` 结合了哈希表链表结构,既保证元素唯一,又保持插入顺序的一致性[^2]。 3. **允许 null 值(部分实现)**:`HashSet` `LinkedHashSet` 允许插入一个 `null` 元素,而 `TreeSet` 不允许插入 `null` 值,因为其排序机制依赖于比较操作,无法处理 `null` 值[^2]。 ### Set 集合的实现类及其特点 #### 1. `HashSet` - 基于哈希表实现,查询效率高。 - 元素存取顺序不一致。 - 允许插入一个 `null` 值。 - 线程不安全,多个线程同时修改时需要同步控制[^1]。 #### 2. `LinkedHashSet` - 继承自 `HashSet`,内部使用双向链表维护元素的插入顺序。 - 保证元素的存取顺序一致。 - 查询性能略低于 `HashSet`,但提供了有序性保障。 - 同样允许插入一个 `null` 值。 #### 3. `TreeSet` - 基于红黑树实现,支持自然排序或自定义排序。 - 元素按升序排列(默认),可以通过 `Comparator` 自定义排序规则。 - 不允许插入 `null` 值。 - 查询、插入删除的时间复杂度为 O(log n)[^2]。 ### Set 集合使用方法 #### 创建 Set 集合 ```java Set<String> hashSet = new HashSet<>(); Set<String> linkedHashSet = new LinkedHashSet<>(); Set<String> treeSet = new TreeSet<>(); ``` #### 添加元素 ```java hashSet.add("Apple"); hashSet.add("Banana"); hashSet.add("Orange"); ``` #### 删除元素 ```java hashSet.remove("Banana"); ``` #### 遍历 Set 集合 可以使用增强型 for 循环或迭代器进行遍历: ```java for (String fruit : hashSet) { System.out.println(fruit); } ``` #### 线程安全的 Set 集合 为了在多线程环境下使用 Set 集合,可以通过 `Collections.synchronizedSet()` 方法将其包装为线程安全的集合: ```java Set<String> synchronizedSet = Collections.synchronizedSet(new HashSet<>()); ``` ### 应用场景 1. **去重操作**:当需要从 List 中去除重复元素时,可以将数据放入 `HashSet` 中自动去重。如果需要保留顺序,则使用 `LinkedHashSet`[^2]。 2. **快速查找**:由于 `HashSet` 提供常数时间复杂度的查找操作,适合用于频繁查询的场景。 3. **排序需求**:当需要对元素进行排序时,选择 `TreeSet` 可以直接获取有序的结果集。 4. **唯一性校验**:在业务逻辑中需要确保某个字段或对象的唯一性时,Set 集合天然支持这一特性。 ### 示例代码 以下是一个简单的示例,展示如何使用 `HashSet` 进行去重操作: ```java import java.util.*; public class Main { public static void main(String[] args) { List<Integer> list = Arrays.asList(1, 2, 3, 2, 4, 5, 6, 7, 8, 9, 10, 5); Set<Integer> set = new HashSet<>(list); System.out.println(set); // 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值