Set:无序(存入和取出的顺序不一定一致),不能重复,Set集合的功能和Collection是一致的
1、常见的子类:
HashSet:底层数据结构是哈希表
HashSet是通过元素的两个方法,hashCode和equals来完 成,如果元素的HashCode值相同,才会判断equals是否为 true,如果元素的hashCode值不同,不会调用equals。
注意:对于判断元素是否存在,以及删除等操作,依赖的方法 是元素的hashCode和equals
HashSet示例:
public class PersonH {
private String name;
private int age;
public PersonH(String name,int age)//设置属性值
{
this.name=name;
this.age=age;
}
public String getName()//获取name值
{
return name;
}
public int getAge()//获取age值
{
return age;
}
//复写hashCode方法,直接比较name和age的hashCode值是否相同
public int hashCode()
{
System.out.println(this.name+"---hashCode");
return name.hashCode()+age;
}
//复写Object的Equals方法
public boolean equals(Object obj)
{
if(!(obj instanceof PersonH))
return false;
PersonH ph=(PersonH)obj;//强制将obj向下转型
//验证当hashCode值相同时,是否调用了Equals方法 System.out.println(this.name+"--equals--"+ph.name);
return this.name.equals(ph.getName()) && this.age==ph.getAge();
}
}
public class HashSetTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建HashSet集合
HashSet hs=new HashSet();
hs.add(new PersonH("zhangsan",23));
hs.add(new PersonH("lisi",24));
hs.add(new PersonH("wangwu",25));
hs.add(new PersonH("lisi",24));
//判断是否包含某个对象,先判断元素的hashCode,相同再调用equals
sop(hs.contains(new PersonH("zhangsan",23)));
hs.remove(new PersonH("zhangsan",23));
Iterator it=hs.iterator();
while(it.hasNext())
{
Object obj=it.next();
PersonH ph=(PersonH)obj;
sop(ph.getName()+"--"+ph.getAge());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
TreeSet
特点:可以对set集合中元素进行排序 ,底层数据结构是二叉树,
保证元素唯一性的依据:compareTo方法return 0;
TRreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现 CompareTo接口,覆盖compareTo方法。这种方式也称为元素的自然排序,或者叫做默认顺序。
示例:
public class Student implements Comparable {
private String name;
private int age;
public Student(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public int compareTo(Object obj)
{
/*if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student sd=(Student)obj;
if(this.age>sd.age)
return 1;
if(this.age==sd.age)
{
return this.name.compareTo(sd.name);//当主要条件相同时,判断次要条件,按次要调件排序
}
return -1;*/
//return 1;//新数据比原有数据大,取出时按,存入顺序取出
//return 0;//新数据等于原有数据,保证集合中元素的唯一性
return -1;//新数据比原有数据小,取出数据时按存入的逆序取出
}
}
import java.util.Iterator;
import java.util.TreeSet;
/**
* 需求:向TreeSet集合中存入自定义对象,将学生按照年龄进行排序
* @author Administrator
*
*/
public class TreeSetTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//创建TreeSet集合对象
TreeSet ts=new TreeSet();
/*ts.add("abc");
ts.add("adc");
ts.add("bbc");
ts.add("acd");
*/
ts.add(new Student("zhangsan",23));
ts.add(new Student("lisi",22));
ts.add(new Student("wangwu",24));
ts.add(new Student("zhaoliu",22));
Iterator it=ts.iterator();
while(it.hasNext())
{
Student sd=(Student)it.next();
sop(sd.getName()+"---"+sd.getAge());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是多需要的,这时,需要让集合自身具备比较性。当两种排序都存在时,以比较器为主。
方法:在集合初始化时,就有了比较方式(参与集合的构造函数)
定义比较器:定义类,实现Comparetor接口,覆盖compare方法。
练习:按照字符串长度排序
字符串背身具备比较性,但是它的比较方式不是所需要的,这时只能使用比较器。
第一步:定义一个类,实现Comparetor接口,复写compare方法
import java.util.Comparator;
public class strLenCompare implements Comparator {
public int compare(Object obj1,Object obj2){
String s1=(String)obj1;
String s2=(String)obj2;
//比较两个字符串的长度是否相等
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)//相等,再比较两个字符串是否相同
num=s1.compareTo(s2);
return num;
}
}
第二步:定义测试类,创建TreeSet集合对象,将Comparetor接口的子类对象作为参数传递给TreeSet
public class TreeSetTest2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
TreeSet ts=new TreeSet(new strLenCompare());
ts.add("aa");
ts.add("aaa");
ts.add("aabb");
ts.add("aab");
ts.add("aabcd");
Iterator it=ts.iterator();
while(it.hasNext()){
sop(it.next());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
泛型
1、概述
泛型是JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制。
2、泛型的优点
1、将运行时期出现的问题ClassCastException,转移到了编译时期,方便于程序员解决问题,让运行时期问题减少,安全。
2、避免了强制转换的麻烦。
泛型格式:通过<>来定义要操作的引用数据类型。
使用泛型的情况:通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。泛型在比较器中也可以使用,但是在复写equals方法时,不能使用。因为equals方法是Object类中的方法。
演示程序:
public class rr {
public static void main(String agrs[]){
ArrayList<String> al=new ArrayList<String>();
al.add("abc");
al.add("abd");
al.add("abe");
Iterator<String> it=al.iterator();
while(it.hasNext()){
String s=it.next();
sop(s);
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
定义泛型类的情况:当类中要操作的引用数据类型不确定的时候,早期定义object来完成扩展,现在用泛型来完成扩展。泛型可以定义在类上,也可以定义在方法上。
泛型类定义的泛型,在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了,那么可以将泛型定义在方法上。
示例:public <T> void method(T t){}
程序演示:
public class GenericDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
GenericDemo gd=new GenericDemo();
gd.show("aaaa");
gd.print(12);
}
public <T> void show(T t){
System.out.println("show:"+t);
}
public <Q> void print(Q q){
System.out.println("print:"+q);
}
}
静态函数泛型:
静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
程序演示:
public class GenericDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public static <W> void method(W w){
}
}
泛型接口:
第一种情况:在子类实现接口时,就明确了操作数据类型。
例:
public class GenericDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
impleInter l=new impleInter();
l.show("hello");
}
}
interface inter<T>{
public void show(T t);
}
class impleInter implements inter<String>{
public void show(String s)
{
System.out.println(s);
}
}
第二种情况:在子类实现接口时,也不知道操作数据的类型
例:
public class GenericDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
impleInter<String> l=new impleInter<String>();
l.show("hello");
}
}
interface inter<T>{
public void show(T t);
}
class impleInter<T> implements inter<T>{
public void show(T t)
{
System.out.println(t);
}
}