您的位置:首页 > 职场人生

黑马程序员----十七-Set集合

2016-01-15 19:29 459 查看
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
1.今天开始学Set集合,Set集合和Collection集合的方法都是一样的,所以Set里面没有什么特有的方法,主要就是学Set集合的子类如何保证元素不重复.

子类:HashSet

HashSet不保证Set的迭代顺序,由哈希表支持.此类允许使用null元素.

如果用boolean类型表示存储的结果,比如

boolean b1=hs.add("a");

boolean b2=hs.add("a");

那么b1就是true,b2就是false.

Set集合,无索引,不重复,无序(存取不一致).

用for(:)循环可以直接遍历,前面就是定义类型,后面是要遍历的数组或者集合.只要能用迭代器迭代的,就可以使用这个增强for循环来遍历.

2.用资源菜单里的各个快捷键可以快速创建各个代码

C--创建无参数的构造函数

O--创建指定参数的构造函数

R--创建getter和setter

S--创建toString方法

如果是new出来的相同条件的对象,是不重复的,因为每个对象都有自己的地址值,如果现在设定同一姓名同一年龄就是同一个人,该怎么办呢?

那就试试重写equals方法.

首先向下转型

Person p=(Person)obj;

所以

return this.name.equals(p.name)&&this.age==p.age;

重写equals之后依然重复出现,为什么呢?

因为equals方法根本没有执行.

再试试重写hashCode()方法,

return 10;

这时发现equals执行了,而且对象也唯一了.

为什么呢?

3.画图解释一下HashSet如何保证自定义对象唯一

首先添加第一个元素,("a",1),这个对象要进内存,就会调用他的hashCode方法来算出一个值,然后确定这个对象的位置.

第二个元素("a",1)进来之后,也有一个哈希值.所以这两个元素的值确定的位置就是不同的,根本不用调用equals方法,只有他们在同一个位置时才需要用equals来比较.

现在想要让元素不重复,那么就需要让他们作比较,所以之前重写了hashCode方法,返回随便一个值比如10,那么所有元素的哈希值都是这个10,所以他们的位置都是相同的,这时候就需要用equals来比较了.

所以这时候进来一个("a",1)和("b",2),他们位置相同,调用equals方法返回的是false,那么第二个就挂在第一个后面.

现在由于哈希值都是10,所以每次进来一个元素,都要调用equals方法,但其实两个元素根本不一样,所以hashCode值不能像现在这样给固定的值.

如果返回的是age呢?

现在有1和2,那么就有了2个位置,但效率还不够.

可以试试把name也加进来.

return name.hashCode()+age;

这样条件更多,位置更多.但效率还不够.

可以final int NUM=38;

return name.hashCode()*38+age;

这样又降低了重复的几率.

有没有更好的办法?

资源列表里快捷键H,就可以快速创建hashCode()和equals()方法.

4.HashSet保证元素唯一的原理

为什么自动生成的hashCode方法里面的final int prime=31,为什么这个数是31呢?

因为一.31是一个素数(质数)

二.31不大也不小,太大的话后续的算法操作可能会超过int的取值范围,太小的话效率不高.

三.31这个数好算,因为是2的五次方减一,2向左移动5位减一.

为什么自动生成的equals代码这么长?

因为有许多的健壮性判断.

1.if(this==obj)

调用的对象和传入的对象是同一个对象,直接返回true.

2.if(obj==null)

传入的对象为null,直接返回false

3.if(getClass()!=obj.getClass())

调用的字节码对象和传入的字节码对象不一致,直接返回false.

Person other =(Person)obj; //向下转型

4.if(age!=other.age)

调用对象的age不等于传入对象的age,返回false

5.if(name==null){

 if(other.name!=null)

 return false;

}

调用对象的姓名为null,传入对象的姓名不为null,返回false

6.else if(!name.equals(other.name))

调用对象的姓名不等于传入对象的姓名,返回false

HashSet原理

调用add()方法存储时,先用hashCode方法,如果相同,再调用equals方法.

将自定义类的对象存入HashSet去重复

类中必须重写hashCode()和equals()方法

五.LinkedHashSet

底层是链表.可以保证怎么存就怎么取.HashSet就保证唯一性.

是Set集合中唯一一个有序的集合对象.

六.练习.产生10个1-20之间的随机数(不重复)

分析:

1.要有Random类创建随机数对象

2.需要存储10个随机数,而且不重复,所以我们用HashSet集合

3.如果HashSet的size是小于10就可以不断的存储,如果大于等于10,就停止存储.

4.通过Random类中的nextInt(n)方法来获取1到20之间的随机数,并将随机数存储在HashSet集合中.

5.遍历HashSet.

r.nextInt(n)就是0到n-1之间的数

Random r=new Random();

HashSet<Integer> hs=new HashSet<>();

while(hs.size()<10){

 hs.add(r.nextInt(20)+1);

}

for(int i:hs){ sysout(i);}

七.练习.使用Scanner从键盘读取一行,去掉其中重复字符,打印出不同的那些字符.

Scanner sc=new Scanner(System.in);

String line=sc.nextLine();

char[] arr=line.toCharArray();

HashSet<Character> hs=new HashSet<>();

for(char c:arr){

 hs.add(c);

}

for(char c:hs){

 sysout(c);

}

八.练习.将集合中的重复元素去掉

一样的道理

九.TreeSet

先存储一些Integer类型的元素并遍历来观察一下.

TreeSet也可以保证元素唯一性并且是按自然顺序排序的.

十.存储自定义对象

存储自定义对象时必须指定排序的方法.

Comparable接口里有一个compareTo方法.

想要有自己的排序方法,只要实现comparable接口并且重写compareTo方法就可以了.

先让Person implements Comparable<Person>,再重写compareTo(Person p)方法.

compareTo方法里有默认的一个return 0;这会出现什么情况呢,运行后发现不报错了,但是只剩下一个元素了,为什么呢?

如果把0改成1,就发现这些元素按存的顺序排列,如果把0改成-1,就发现这些元素按存的反方向排列.也就是说返回正数,那么就排在之前元素的后面,如果返回负数,就排在之前元素的前面.

十一.TreeSet原理和图解

二叉树:小的存储在左边(负数),大的存储在右边(正数),相等就不存(0).

compareTo方法,在TreeSet集合如何存储元素取决于compareTo方法的返回值.

如果是this.age-o.age

先进来一个,不用比较,后进来的调用compareTo,所以是(后.age-先.age),如果为正,那么说明后来的大,就排在右边,如果为负,说明后来的小,就排在左边,所以这样是从小到大排序.

如果是o.age-this.age

同理,所以是从大到小排序.

如果出现了有两个人,姓名不同,但age不同,后进来的这个人就不见了,因为age相减为0,所以相当于是一样的,怎么办呢?

这样要多考虑一层因素,

int num=this.age-o.age;

return num==0?this.name.compareTo(o.name);

十二.练习.按姓名排序

跟年龄是一样的道理.

十三.练习.按姓名长度排序

num=this.name.l-o.name.l;

也是一样的道理

十四.TreeSet比较器排序的原理及代码实现

需求:将字符串按照长度排序

如果直接将字符串存储到TreeSet中,会按他们的编码顺序排列,怎么办呢?

TreeSet构造函数有TreeSe(Comparator),就是按比较器进行排序.

Comparator是一个接口,那么就要给他一个子类对象,他有一个compare方法,有一个equals方法.

单独写一个类

class CompareByLen implements Comparator<String>{

 public int compare(String s1,String s2){

 int num=s1.l-s2.l;

 return ;

 }

}

长度为主要条件,内容为次要条件.

TreeSet ts =new TreeSet(new comparator());

十五.TreeSet原理

两种排序方法

1.自然顺序(实现Comparable)

* add方法会把存入的对象提升为Comparable类型

* 调用对象的compareTo进行比较

* 根据compareTo方法返回的结果存储

2.比较器顺序(Comparator)

* 制定一个Comparator

* add方法内部会调用compare方法排序

十六.练习.对无序的字符串进行排序,而且不能去除重复

关键在于num==0的时候,就不要返回0,一旦返回0,就会去掉这个重复元素
4000
.

十七.练习.对字符串中的所有字符进行排序

十八.练习.把所有的输入的整数排序打印

十九.练习.录入5个学生信息,按总分高低排序

二十.总结

1.List四种取出

a.普通for循环

b.Iterator迭代器,hasNext和next方法

c.增强for循环

d.Vector集合可以用hasMoreElements和nextElement方法

2.Set两种取出

a.Iterator迭代

b.增强for循环

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: