21.Collections工具类与Set集合

1.Collections工具类
主要是为List集合服务,进行相关的List功能处理

注意: Collection与Collections要区分开

扩展了解复合泛型
<T extends Comparable<T>>: 所使用的T类型必须要实现Comparable
<T extends Comparable<? super T>>:所使用的T类型或T的父亲实现Comparable接口

//例如:此处List存Integer类型,定义复合类型说明Integer或父亲必须实现Comparable

class Student{
	int age;
	public Student(int age) {
		this.age=age;
	}
	
}
public class Test1 {
	public static void main(String[] args) {
		List<Integer> list = new ArrayList<>();
		list.add(3);
		list.add(1);
		list.add(2);
		list.add(4);
		Collections.reverse(list);  //集合的反转
		Collections.shuffle(list);  //随机重置集合
		System.out.println(list);
		Collections.sort(list);     //排序
		System.out.println(list);
		
		
		//------扩展思考:List存自定义对象,并进行排序------
		List<Student> list2 = new ArrayList<Student>();
		list2.add(new Student(30));
		list2.add(new Student(25));
		//Collections.sort(list2);  //有约束,Student类必须实现Comparable接口才行
	}
}

2.Set实现类HashSet

2.1. HashSet存储原理
HashSet实现类: 是Set接口的实现类
特点:无序,无下标,元素唯一
使用方式:

分析HashSet存储原理:通过hash算法进行存储

public class Test1 {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(11);
        set.add(33);
        set.add(22);
        set.add(33);  //唯一的
        System.out.println(set);
        
        
        //因为无下标,所以不能使用基本for遍历
        for(int i=0;i<set.size();i++) {}
        
        for(Integer o:set) {
            System.out.println(o);
        }
    }
}

HashSet存储原理:Hash算法

存储对象时,每个对象都能得到hash值,该值再hash表中,通过运算,得到下标位置,如果该位置值为空,则直接存储;否则,与该位置的链表元素一一比较,确定唯一性

//HashSet源码分析:
//1、调用add方法--内部通过HashMap的put方法实现
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
//初始hash表是空,创建hash表空间,长度为16
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
//对象得到的hash值在hash表中可以算出下标位置,如果该位置为null,则直接存储;如果不为null则循环与链表元素比较
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
//需要比较hashCode与equals确定其唯一性
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

2.2 hashSet验证原理

//验证存储原理:
//HashSet存储自定义对象student,所有对象如何确定唯一性
//例如:      学生对象zs    ls     zs  
//目标: 2个        实际:3

//思考:假设两个属性的自定义对象存储;

===================存储单个属性的对象===================

class Student{
	String name;
	public Student(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		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 (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
	
}
public class Test2 {
	public static void main(String[] args) {
		Set<Student> set = new HashSet<Student>();
		set.add(new Student("zs"));
		set.add(new Student("ls"));
		set.add(new Student("zs"));
		System.out.println(set);  
		
		//为什么下面的new String,它会根据属性的一致确定唯一性?
		//根据存储原理分析结论得出:
		//只要源码中的hashCode和equals一致,则确定唯一性,可以得出String类型肯定重写过
		//如果存储自定义对象,要想根据属性确定唯一性,需要重写hashCode与equals
		
		Set<String> set2 = new HashSet<String>();
		set2.add(new String("zs"));
		set2.add(new String("ls"));
		set2.add(new String("zs"));
		System.out.println(set2);
	}
}

4. Set实现类TreeSet(重点)

4.1 TreeSet的使用特点
TreeSet:是Set接口的实现类
TreeSet存储特点:可排序,唯一,无下标

TreeSet的存储原理:通过二叉树进行存储
 

public class Test1 {
	public static void main(String[] args) {
		Set<Integer> set = new TreeSet<Integer>();
		set.add(11);
		set.add(33);
		set.add(22);
		set.add(11);
		System.out.println(set);
		
		//基本for:  不能
		for(int i=0;i<set.size();i++) {}
		
		//增强for
		for(Integer o:set) {
			System.out.println(o);
		}
		
		
	}
}

4.2存储原理分析

TreeSet存储原理:二叉树算法

存储第一个数,将该数作为根,再次存储,与根比较,如果没有,则直接存储;否则继续比较;如果比根大,查看根的右边是否有节点,如果没有则直接存储,否则继续比较,依次类推

            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;

 实现排序的方式
  1.自然排序法------存储对象的类实现Comparable接口
  2.比较器法  ------带参构造方法传入比较器对象(Comparator)

验证原理-存储单个属性的对象

  class Person implements Comparable<Person>{
    String name;
    public Person(String name) {
        this.name=name;
    }
    
    @Override
    public String toString() {
        return "Person [name=" + name + "]";
    }

    @Override
    public int compareTo(Person o) {
        //按自己方式比较,认为姓名相同则确定唯一
        //compareTo方法与二叉树原理匹配的>0  ==0  <0--->升序排列
        //return this.name.compareTo(o.name);
        
        return o.name.compareTo(this.name);  //倒叙排列
        
        //return 0;  //如果返回0,只返回一个对象
    }
    
    
}
public class Test1 {
    public static void main(String[] args) {
        Set<Person> set = new TreeSet<Person>();
        set.add(new Person("zs")); //ClassCastException: Person cannot be cast to Comparable
        set.add(new Person("ls"));
        set.add(new Person("zs"));
        set.add(new Person("ww"));
        System.out.println(set);
    }
}

 验证原理-存储多个属性的对象
TreeSet存储对象为两个属性:
分析:需要判断两个属性都一致则认为是同一个对象

自然排序法---存储类型实现Comparable接口

class Student implements Comparable<Student>{
    String name;
    int    age;
    
    public Student(String name, int age) {
        this.name=name;
        this.age = age;
    }
    
    

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }

    @Override
    public int compareTo(Student o) {
        //排序规则:按年龄比较升序,如果年龄相同,则按姓名的降序
        /*if(this.age==o.age) { //年龄相同
            return o.name.compareTo(this.name); //姓名降序
        }else {
            return this.age-o.age; //年龄升序
        }*/
        
        //排序规则2:先按姓名的升序排,如果姓名相同,则按年龄的降序
        if(this.name.equals(o.name)) {
            return o.age-this.age;  //年龄的降序
        }else {
            return this.name.compareTo(o.name);
        }
        
    }
    
}

public class Test2 {
    public static void main(String[] args) {
        Set<Student> set = new TreeSet<>();
        set.add(new Student("zs",20));
        set.add(new Student("ls",20));
        set.add(new Student("zs",18));
        set.add(new Student("ls",20));
        System.out.println(set);
    }
}

 比较器法
案例:TreeSet存储两个属性的对象,使用比较器方式

class Teacher{
    String name;
    int    age;
    public Teacher(String name,int age) {
        this.name = name;
        this.age  = age;
    }
    @Override
    public String toString() {
        return "Teacher [name=" + name + ", age=" + age + "]";
    }
    
    
}
public class Test3 {
    public static void main(String[] args) {
        Set<Teacher> set = new TreeSet<Teacher>(new Comparator<Teacher>() {

            @Override
            public int compare(Teacher o1, Teacher o2) {
                //规则: 先按姓名降序排列,如果姓名相同,在按年龄升序排列
                if(o1.name.equals(o2.name)) {
                    return o1.age-o2.age;
                }else {
                    return o2.name.compareTo(o1.name);
                }
                
            }
        });
        
        set.add(new Teacher("zs", 13));
        set.add(new Teacher("ls", 13));
        set.add(new Teacher("zs", 13));
        set.add(new Teacher("ls", 15));
        
        System.out.println(set);
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值