黑马程序员——Java要点笔记——集合框架(Set)

时间:2023-02-18 17:40:55

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

day17 16-常用对象API(集合框架-HashSet集合)

1、HashSet集合在集合框架中的位置

黑马程序员——Java要点笔记——集合框架(Set)

2、Set集合中,元素不可以重复(用特定的比较方法来确定是否重复),是无序(存入和取出的顺序不一致)的。

3、HashSet集合:此类实现Set接口,由哈希表(实际上是一个HashMap实例)支持,他不保证Set的迭代顺序,特别是他不保证顺序恒久不变。此类允许使用null元素。性能稳定。注意:此类不同步。

4、代码示例——Set集合中,元素不可以重复

public class Demo28 {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add("hehe");
hs.add("heihei");
hs.add("hahah");
hs.add("xixi");
hs.add("hehe");
for(Iterator it = hs.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}

运行结果:xixi  hehe   heihei     hahah

由结果可见:无序(输入输出顺序不一致)、元素不可以重复(只有一个hehe)

day17 17-常用对象API(集合框架-哈希表1)

day17 18-常用对象API(集合框架-哈希表2)

1、比如,我要找ab。我把ab用hashCode()方法一算,算出一个5。但这不能表示5这个位置上一定是ab。因为ba也可能是5。

2、哈希表确定元素是否相同:

①先用hashCoda()方法判断两个对象的哈希值是否相同。

②如果相同,再用equals()方法判断两个对象内容是否相同。

3、HashSet集合是怎么保证元素不重复的?

    用的也是2中的方法。hashCode()看是否相同,相同再用equals()判断是否相同。

黑马程序员——Java要点笔记——集合框架(Set)

4、在Dog类中只覆盖hashCode()方法,未覆盖equals方法

publicint hashCode(){

    return (name.hashCode()+age*127);

}

运行结果:

黑马程序员——Java要点笔记——集合框架(Set)

day17 19-常用对象API(集合框架-HashSet存储自定义对象)

1、需求:往HashSet集合中存储Student对象。如果姓名和年龄相同,视为同一个人,视为相同元素。

2、代码示例——错误代码

class Student{
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 class Demo29 {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Student("lisi4",24));
hs.add(new Student("lisi7",27));
hs.add(new Student("lisi1",21));
hs.add(new Student("lisi9",29));
hs.add(new Student("lisi7",27));
for(Iterator it = hs.iterator();it.hasNext();){
Student s = (Student)it.next();
System.out.println(s.getName()+"..."+s.getAge()+"..."+s.hashCode());
}
}
}

运行结果:

lisi7...27...5383406

lisi4...24...29855319

lisi1...21...16164678

lisi9...29...23065739

lisi7...27...11533424

3、从运行结果来看,出现了两个“lisi7...27”。因为你没有在Student类中覆盖hashCode()方法和equals()方法。所以这个HashSet集合用的还是父类Object类的hashCode()和equals()在判断是否相等。地址不同,他就认为是不同的。

4、代码示例:正确代码,应该在Student类中覆盖父类Object类中的hashCode()方法和equals()方法。

class Student{
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 hashCode(){
return name.hashCode()+age;
}
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(!(obj instanceof Student)){
throw new ClassCastException("类型错误");
}
Student s = (Student)obj;
return this.name.equals(s.name)&&(this.age==s.age);
}
}
public class Demo29 {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Student("lisi4",24));
hs.add(new Student("lisi7",27));
hs.add(new Student("lisi1",21));
hs.add(new Student("lisi9",29));
hs.add(new Student("lisi7",27));
for(Iterator it = hs.iterator();it.hasNext();){
Student s = (Student)it.next();
System.out.println(s.getName()+"..."+s.getAge()+"..."+s.hashCode());
}
}
}

运行结果:

lisi4...24...102982169

lisi7...27...102982175

lisi1...21...102982163

lisi9...29...102982179

day17 20-常用对象API(集合框架-练习)

1、需求:定义功能,去除ArrayList中的重复元素。(注意,集合也是一个类或接口,也属于引用数据类型,也可以被方法返回)

2、代码示例——此代码存在问题

public class Demo30 {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add("abc1");
al.add("abc2");
al.add("abc2");
al.add("abc1");
al.add("abc3");
System.out.println(al);
System.out.println(getSingleElement(al));
}
public static ArrayList getSingleElement(ArrayList al){
//1、定义一个临时容器
ArrayList temp = new ArrayList();
//2、迭代al集合
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
//判断被迭代到的元素是否在临时容器中存在
if(!temp.contains(obj)){
temp.add(obj);
}
}
return temp;
}
}

运行结果:

[abc1, abc2, abc2, abc1,abc3]

[abc1,abc2, abc3]

3、如果我同样使用上面的getSingleElement(ArrayList al)方法,但是集合中的不是String,而是自定义对象呢?

代码示例:——有问题

class People{
String name;
int age;
public People(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name+"..."+age;
}
}
public class Demo31 {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(new People("lisi1",21));
al.add(new People("lisi1",21));
al.add(new People("lisi2",22));
al.add(new People("lisi3",23));
System.out.println(al);
System.out.println(getSingleList(al));
}
public static ArrayList getSingleList(ArrayList al){
ArrayList temp = new ArrayList();
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
if(!temp.contains(obj)){
temp.add(obj);
}
}
return temp;
}
}

运行结果:

[lisi1...21, lisi1...21,lisi2...22, lisi3...23]

[lisi1...21,lisi1...21, lisi2...22, lisi3...23]

4、没有去掉相同的,这是怎么回事?

    查看API文档,发现contains(Object o)方法内部用的是equals方法来确定是否包含。因此,应该在People类中覆盖equals方法。

5、正确代码示例

class People{
String name;
int age;
public People(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name+"..."+age;
}
public boolean equals(Object obj){
if(this==obj){
return true;
}
if(!(obj instanceof People)){
throw new ClassCastException("类型错误");
}
People p = (People)obj;
return this.name.equals(p.name)&&this.age==age;
}
}
public class Demo31 {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(new People("lisi1",21));
al.add(new People("lisi1",21));
al.add(new People("lisi2",22));
al.add(new People("lisi3",23));
System.out.println(al);
System.out.println(getSingleList(al));
}
public static ArrayList getSingleList(ArrayList al){
ArrayList temp = new ArrayList();
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
if(!temp.contains(obj)){
temp.add(obj);
}
}
return temp;
}
}

运行结果:

[lisi1...21, lisi1...21,lisi2...22, lisi3...23]

[lisi1...21,lisi2...22, lisi3...23]

day17 21-常用对象API(集合框架-LinkedHashSet集合)

1、类LinkedHashSet<E>  extends HashSet<E>  implements  Set<E>

2、LinkedHashSet集合,在保证唯一性的情况下,还可以有序。

3、代码示例:

public class Demo32 {
public static void main(String[] args) {
LinkedHashSet lhs = new LinkedHashSet();
lhs.add("abc1");
lhs.add("abc2");
lhs.add("abc1");
lhs.add("abc3");
System.out.println(lhs);
}
}

运行结果:

[abc1,abc2, abc3]

4、类HashSet和LinkedHashSet都是接口Set的实现,两者都不能保存重复的数据。主要区别是HashSet不保证集合中元素的顺序,即不能保证迭代的顺序和插入的顺序一致。而LinkedHashSet按照元素插入的顺序进行迭代,即迭代输出的顺序与插入的顺序保持一致。

day17 22-常用对象API(集合框架-TreeSet集合)

1、TreeSet集合特点:

    TreeSet集合不仅保证元素的唯一性,还会比较元素的大小。TreeSet是不同步的。TreeSet判断元素唯一性的方法:就是根据比较方法的返回结果是否是0。是0就认为是相同元素,不存。

2、TreeSet集合实现元素比较有两种方式。

    ①、应用传入类本身实现的Comparable接口及覆盖的int  compareTo(T  o)方法。即利用类的自然排序方法。

    ②、在new一个TreeSet集合时,往构造方法中传入一个比较器对象。它实现了Compartor接口并覆盖了int compare(T  o1,T  o2)方法。

    注意,当既有自然排序又有比较器时,以比较器优先。

3、接口Comparable。此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。类的compareTo方法被称为他的自然比较方法。这相当于这个类他自己本身就有的排序规则。

4、需求:按照Student的年龄来进行排序(年龄从小到大)。并使用自然排序方式。

5、代码示例

class Student1 implements Comparable{
private String name;
private int age;
public Student1(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 Student1)){
throw new ClassCastException("类型错误");
}
Student1 s = (Student1)obj;
return this.age - s.age;
}
public String toString(){
return name+"..."+age;
}
}
public class Demo33 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add(new Student1("张三",3));
ts.add(new Student1("李四",4));
ts.add(new Student1("宋三",3));
ts.add(new Student1("王五",5));
ts.add(new Student1("赵六",6));
System.out.println(ts);
}
}

运行结果:

    [张三...3, 李四...4, 王五...5, 赵六...6]

6、由以上结果可以看出,int compareTo(Object  obj)方法返回的为0的(即年龄一样的对象),TreeSet都认为是重复对象,都没有保存。而且输出结果显示,是按照年龄从小到大排序的。

day17 23-常用对象API(集合框架-TreeSet集合-Comparator)

1、如果不按照对象中具备的自然排序进行排序;或是对象中不具备自然排序,怎么办?

    使用TreeSet的第二种排序方式:在new一个TreeSet集合时,往构造方法中传入一个比较器对象。它实现了Compartor接口并覆盖了int compare(T  o1,T  o2)方法。即你把元素扔给我(TreeSet),我来帮你排(通过Comparator)。

2、TreeSet构造方法

TreeSet(Comparator<?super E>)

    构造一个新的空TreeSet,它根据指定比较器进行排序。

3、接口Comparator<T>

    int compare(T o1,T o2)

       用来比较排序的两个参数。根据第一个参数小于、等于或大于第二个参数,分别返回负、0、正。

    boolean equals(Object obj)

       指示某个其他对象是否“等于”此Compartor。

4、相对来说,比较器更常用。当既有比较器又有元素自然排序时,以比较器优先。

5、何时需要比较器?

    ①当一个类中不具备自然排序。

    ②当一个类中具备自然排序,但这个规则不是我所需要的时候。

6、需求:创建一个先根据name排序,再根据age进行排序的比较器。

class Student1 implements Comparable{
private String name;
private int age;
public Student1(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 Student1)){
throw new ClassCastException("类型错误");
}
Student1 s = (Student1)obj;
return this.age - s.age;
}
public String toString(){
return name+"..."+age;
}
}
class MyComparator implements Comparator{
public int compare(Object o1,Object o2){
Student1 s1 = (Student1)o1;
Student1 s2 = (Student1)o2;
int temp = s1.getName().compareTo(s2.getName());
return temp==0?s1.getAge()-s2.getAge():temp;
}
}
public class Demo33 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyComparator());
ts.add(new Student1("zs",3));
ts.add(new Student1("ls",4));
ts.add(new Student1("zs",5));
ts.add(new Student1("ww",5));
ts.add(new Student1("zl",6));
System.out.println(ts);
}
}

运行结果:

    [ls...4, ww...5, zl...6, zs...3, zs...5]

day17 24-常用对象API(集合框架-TreeSet集合-二叉树)

1、TreeSet怎么确定元素位置的?

    此处以年龄从小到大排序

    ts.add(new Person(“zhangsan”,28));

    ts.add(new Person(“lisi”,21));

    ts.add(new Person(“zhouqi”,29));

    ts.add(new Person(“zhaoliu”,25));

    ts.add(new Person(“wangwu”,24));

    ts.add(new Person(“sunba”,19));

    ts.add(new Person(“baijiu”,30));

    ts.add(new Person(“wangcai”,27));

黑马程序员——Java要点笔记——集合框架(Set)

2、技巧,那我现在要怎么存进去的怎么取出来,该怎么做?

    原理,在使用二叉树排的时候,如下图。

   黑马程序员——Java要点笔记——集合框架(Set)

    很简单,二叉树不管你这那,就看正、负、零。“后来的”减去“先来的”,负就把后来的放到左边,正就把后来的放到右边,零就认为重复。

    所以,代码如下:

class Student{
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 String toString(){
return name+"..."+age;
}
}
class MyComparator implements Comparator{
public int compare(Object obj1,Object obj2){
return 1;
}
}
public class Demo41 {
public static void main(String[] args) {
TreeSet ts= new TreeSet(new MyComparator());
ts.add(new Student("zhangsan",28));
ts.add(new Student("lisi",21));
ts.add(new Student("zhouqi",29));
ts.add(new Student("zhaoliu",25));
ts.add(new Student("wangwu",24));
ts.add(new Student("sunba",19));
ts.add(new Student("baijiu",30));
ts.add(new Student("wangcai",27));
System.out.println(ts);
}
}

运行结果:[zhangsan...28, lisi...21, zhouqi...29,zhaoliu...25, wangwu...24, sunba...19, baijiu...30, wangcai...27]

    不管传进什么,我只要返回正数,证明“后来的”都在右边,比上一个大。相反的,逆向输出,你return -1即可。

day17 25-常用对象API(集合框架-TreeSet集合练习-字符串长度排序)

1、需求:利用字符串的长度排序

2、众所周知,String类实现了Comparable接口,内部覆盖了compareTo(XXX)方法,根据字母顺序进行排序。

3、代码示例——有问题

public class Demo42 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add("aaaaa");
ts.add("zz");
ts.add("nbaq");
ts.add("cba");
ts.add("abc");
System.out.println(ts);
}
}

运行结果:[aaaaa, abc, cba, nbaq, zz]

4、从运行结果可以看出,ts使用了String类的自然排序方法,即按照字母顺序进行排序的。

5、代码示例——实现按照字符串长度排序

class ComparatorByLength implements Comparator{
public int compare(Object obj1,Object obj2){
String s1 = (String)obj1;
String s2 = (String)obj2;
return s1.length() - s2.length();
}
}
public class Demo42 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new ComparatorByLength());
ts.add("aaaaa");
ts.add("zz");
ts.add("nbaq");
ts.add("cba");
ts.add("abc");
System.out.println(ts);
}
}

运行结果:[zz, cba, nbaq, aaaaa]

6、但按照上例,"cba"和"abc"长度相同,只存了一个。我们按照先长度,再字母的方式排序。

7、代码示例——按照先长度,再字母的方式排序

class ComparatorByLength implements Comparator{
public int compare(Object obj1,Object obj2){
String s1 = (String)obj1;
String s2 = (String)obj2;
int temp = s1.length() - s2.length();
return temp==0?s1.compareTo(s2):temp;
}
}
public class Demo42 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new ComparatorByLength());
ts.add("aaaaa");
ts.add("zz");
ts.add("nbaq");
ts.add("cba");
ts.add("abc");
System.out.println(ts);
}
}

运行结果:[zz, abc, cba, nbaq, aaaaa]哦了