------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
Set集合特点:
set集合中数据的存储和取出是无序的。而且元素时不可以重复;
set集合Collection功能是一样的。list有操作角标的特有方法。但是set集合没有特殊的特性方法。
set集合中常见的子类:
HashSet -----底层的数据结构式哈希表。
TreeSet------底层的数据结构式二叉树。
注:Hash表的特点,先比较对象的hash值,如果hash值不同,然后就根据hash值存储在hash表中,如果hash值相同,那么就会比较对象的equal()方法。如果equal()返回的也是true,那么向hash表中存储元素就会失败。
HashSet集合是如何在保证数据的唯一性的呢?
1主要是通过比较元素本身的hashcode值,
2如果hashcode值相同,那么就在比较元素的equal方法,主要元素的hash值不同,就不会比较equal方法,
如果两个条件中只要有一个不相同,那么元素就会存储成功。
TreeSet实例
/*demo1*/
import java.util.*;
class JavaCollection1_7
{
public static void main(String[] args)
{
HashSet hs=new HashSet();
sop(hs.add("java01"));//第一次添加会添加成功
hs.add("java02");
hs.add("java03");
hs.add("java04");
sop(hs.add("java01"));//当插入重复的元素就会添加失败。
sop(hs);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
运行结果如下:
实例二:
向HashSet中存自定义的Person类,如果年龄和姓名都相同,就不存储到HashSet中
/*
*/
import java.util.*;
class JavaCollection1_8
{
public static void main(String[] args)
{
HashSet hs=new HashSet();
hs.add(new Person("java01",1));
hs.add(new Person("java02",2));
hs.add(new Person("java03",3));
hs.add(new Person("java01",1));
/*这里向hs集合中添加了重复的人。
*/
for(Iterator it=hs.iterator();it.hasNext();)
{
Person p=(Person)it.next();
sop(p.getName()+":"+p.getAge());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
//1元素存储到HashSet中,首先比较的是对象的hashCode()值,
public int hashCode()
{
return name.hashCode()+age;
}
//2如果元素的hashCode值相同,那么就会在比较对象的equsls方法。
public boolean equals(Object obj)
{
//类型安全转换
if(!(obj instanceof Person))
return false;
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
//如果人的名字和年龄相同,那么人员就重复。
}
}
运行结果如下:
而ArrayLis集合删除元素,或者是否包含元素,只依赖元素的equals()方法。
TreeSet集合的特点
可以对set中元素进行排序,而排序的依据主要是根据字符的ASCILL表。
实例一:
import java.util.*;
class JavaCollection1_9
{
public static void main(String[] args)
{
TreeSet ts=new TreeSet();
ts.add("abcde");
ts.add("bcd");
ts.add("c");
ts.add("adc");
for(Iterator it=ts.iterator();it.hasNext();)
{
System.out.println(it.next());
}
}
}
运行结果如下:
很明显,我们存储的顺序是无序的,但是输出的结果却是按照字符的ASCILL表的顺序输出的,说明TreeSet有对元素进行排序的功能。
下面我们向集合中存储自定义的对象。
注意:向TreeSet中存储的自定义对象必须具有比较性。不然程序编译就会报异常。所以自定义的对象必须实现Comparable接口,并覆盖里面的compareTo()方法。
另外在排序时,先要对主要条件进行排序,然后再对次要条件进行排序。
实例二:
需求:向TreeSet中存储多个学生,按照学生的年龄的大小排序。
/**/
import java.util.*;
class JavaCollection1_10
{
public static void main(String[] args)
{
TreeSet ts=new TreeSet();
ts.add(new Person("xt",21));
ts.add(new Person("tx",21));
ts.add(new Person("xt",22));
ts.add(new Person("xt",21));
for(Iterator it=ts.iterator();it.hasNext();)
{
Person p=(Person)it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
}
class Person implements Comparable/*存储到TreeSet中的自定义对象必须具备比较性,所以这里强制学生实Comparable接口,并实现compareTo()方法*/
{
private int age;
private String name;
public int compareTo(Object obj)
{
if(!(obj instanceof Person))
throw new ClassCastException("TreeSet中存储了非Person类型的对象");
Person p=(Person)obj;
if(this.age>p.getAge())
return 1;
if(this.age==p.getAge())//注意:这里当主条件相同时,我们还要比较次要条件,如果不比较名称,那么当年龄相同时,往TreeSet中存储时就可能存储失败。
{
//先比较年龄;再比较姓名;
return this.name.compareTo(p.getName());
}
return -1;
}
Person(String name,int age)
{
this.age=age;
this.name=name;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
运行结果如下:
实例三:
TreeSet集合底层的数据结构是二叉树,而且下来的实例将显示数据在TreeSet中的存储方式,代码如下:
总结:TreeSet实例排序的第一种方式,让元素本身具备比较性,实现Comparable接口,并重写compareTo方法。
import java.util.*;
class JavaCollection1_11
{
public static void main(String[] args)
{
TreeSet ts =new TreeSet();
ts.add(45);
ts.add(76);
ts.add(34);
ts.add(89);
ts.add(23);
ts.add(40);
ts.add(12);
ts.add(4);
for(Iterator it=ts.iterator();it.hasNext();)
{
System.out.println(it.next());
}
}
}
数据在TreeSet的存储结构就如上面的截图二叉树结构,TreeSet取出的方式是默认方式,按照从小到大的方式,
运行结果:
TreeSet的第二种排序方式:当元素本身不具备比较性,或者是元素本身的比较性不是自己所需的,那么我们就需要集合具备比较性,在集合初始化就具备比较性;这时我们就需要定义一个比较器,然后将比较器对象作为参数传递给集合的构造函数。让集合具备比较性;
实例三:
创建TreeSet集合,集合中存储Person对象,并进行排序,首先按照人名排序,如果人名相同,再按照年龄进行排序,代码如下:
import java.util.*;
class JavaCollection1_12
{
public static void main(String[] args)
{
//将比较器对象作为参数传递给集合的构造函数,让集合具备比较性。
TreeSet ts=new TreeSet(new MyComparator());
ts.add(new Person("xt",21));
ts.add(new Person("tx",22));
ts.add(new Person("aa",34));
ts.add(new Person("aa",22));
for(Iterator it=ts.iterator();it.hasNext();)
{
Person p=(Person)it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
}
//创建一个比较器:
class MyComparator implements Comparator//比较器必须要是实现Comparator接口
{
//重写Comparator接口中的compare方法。
public int compare(Object obj1,Object obj2)
{
if(obj1 instanceof Person&&obj2 instanceof Person)
{
Person p1=(Person)obj1;
Person p2=(Person)obj2;
int num=p1.getName().compareTo(p2.getName());
if(num==0)//当名字相同时就应该比较年龄。
return p1.getAge()-p2.getAge();
else
return num;
}
else
{
throw new ClassCastException("集合中存储的对象不是Person类型的");
}
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
运行结果如下:
注意事项:
当元素自身具备比较性,同时TreeSet集合也具备比较性,那么比较的依据是依赖集合的比较性。也就是比较器的比较方式。
TreeSet练习:
需求:往TreeSet中存入几个字符串,然后按照先参照字符串的长度排序,长度相同,然后在按照字符串的ASCILL码表的顺序进行排序,代码如下:
import java.util.*;
class JavaCollection1_14
{
public static void main(String[] args)
{
//使用匿名内部类来创建比较器;
TreeSet ts=new TreeSet(new Comparator(){
public int compare(Object obj1,Object obj2)
{
if(!(obj1 instanceof String )||!(obj2 instanceof String))
throw new ClassCastException("存入到TreeSet中的元素不是String类型的");
String str1=(String)obj1;
String str2=(String)obj2;
int num=str1.length()-(str2.length());
if(num==0)
return str1.compareTo(str2);
return num;
}
});
ts.add("c");
ts.add("aaa");
ts.add("b");
ts.add("bca");
System.out.println(ts);
}
}
运行结果如下: