Java基础-容器、迭代器

容器

Collection接口

数据结构是复杂的,难以被初中级程序员用好,这与Java的设计理念相违背...

Java作为一门高大上的语言,怎么会让我们失望呢~~

(Java设计理念:Java语言是一门面向应用的,而不是面向研究的语言--来自Java编程规范JavaSE8版)

于是,Java砖家们就针对数据结构进行了开发来让数据结构变得简单易用,然后Collection接口诞生了

我们可以用Collection接口存放 可重复、没有顺序 的数据对象

同时,因为我们知道Collection接口本身无法存放数据

所以我们通过它下面的子类或者说实现类来存放数据,如HashSet、ArrayList等类

可是我们想要存储有序或者重复的数据啊~

Set接口和List接口这对兄弟接口于是被Java砖家搞出来了~

用Set接口存放不可重复、没有顺序的数据对象

用List接口存档重复、顺序的数据对象

哎呦呦,Set和List的特性完全相反啊~好记~真好记~

砖家满足了我们的要求~

我们来看看这两个接口的子类吧~

毕竟用来直接存储数据的是它们的子类啊~

Set接口有2个常用的子类(实现类)HashSet和TreeSet

HashSet 不可重复 无序

TreeSet 不可重复 有序 (和Set不一样,因为采用了二叉树结构存储数据)

List接口有2个常用的子类(实现类)ArrayList和LinkedList

ArrayList 可重复 有序

LinkedList 可重复 有序

这2个子类和List接口的特性一模一样,

List接口的特性又与Set接口完全相反

哈哈,好记,真好记~

请消化一下~

请不要死记硬背,理解记忆效果最好~

(只有TreeSet特殊,其它的太好记了~)

细心的你肯定发现了,Collection接口号称是存储可重复、没有顺序的数据对象,

可是其下却没有实现了可重复、没有顺序的实现类~ 不信你回头看看~

我们想要存储可重复、没有顺序的数据对象是,Collection接口无能为力了~

于是,砖家又出现了~

Map接口因此出现了~(映射)

我们由此知道:Map接口是不在Collection接口下的~~~

Map接口存放的是也是对象,这个对象由键值对组成~

键(key)是对象,值(value)也是对象,因为所有的容器存放的都是对象...

key的底层用Set存储,value的底层使用Collection存储~ 此句只可意会~~不可言传~~~ 

key类似我们的身份证编号,是唯一的;value类似我们的姓名,可以是重复的

即:在Map里存放的所有键值对中,键是不可以重复的,值是可以重复的~~

我们通过键,就可以查找到值;相反,通过值,不能确认唯一的键~~

Map接口有两个子类(实现类)HashMap和TreeMap

用HashMap存储可重复、没有顺序的值

用TreeMap 存储可重复、有顺序的值(原因是TreeSet一样~~)

请注意:

可重复和有或没有顺序,指的是值对象,而不是键对象,更不可能是键值对对象~请认真体会~

下面介绍各种容器的用法和理念

----------------------------------------------Collection接口-----------------------------------------

1、Collection接口存放可重复、没有顺序的数据对象

2、Collection接口是接口,所以本身不能存放对象,必须依赖子类

3、它有两个常用的子接口Set和List接口

用法比较简单,直接上代码段

  //报错,因为Collection是个接口,接口不能直接被实例化
  Collection<T> c=new Collection<T>();
  //使用Collection接口创建一个具有泛型参数的HashSet(哈希集合)对象
  Collection<T> c1=new HashSet<T>();
  //使用Collection接口创建了一个只能存放String类型的TreeSet(树型集合)对象
  Collection<String> c2=new TreeSet<String>();
  //使用Collection接口,是为了程序的多态

----------------------------------Set(集合)接口----------------------------------

1、Set接口存放不可重复、没有顺序的数据对象

2、Set接口是接口,所以...和它爸爸一样~

3、它有两个子类(实现类)HashSet(无序的哈希集合)和TreeSet(有序的树型集合)

当我们向HashSet添加重复元素(对象)时,它会采用屏蔽技术进行屏蔽;

(简单理解:非专业人士看不懂HashSet底层的哈希排序,所以我们认为HashSet是无序的~)

当我们向TreeSet 添加重复元素时,它也会用屏蔽技术进行屏蔽,而且还会采用排序技术对元素进行排序。

屏蔽技术

Java如何判断两个对象是否相同?

Java通过调用对象的equals方法来判断,本质是查看两个对象在内存中的引用(在堆里的地址)是否相同。

因为所有对象都继承了Object对象的方法,所以在对象没有重写Object对象的equals方法时,

使用的是Object的equals方法来比较两个对象。

HashSet如何判断两个对象是否相同?

HashSet首先调用将要放进HashSet中的对象的hashCode方法查看两个对象的哈希码是否相同,

若该对象没有重写Object类的hashCode方法,则使用Object类里的hashCode方法~

再调用将要放进HashSet中的对象的equals方法判断两个对象是否相同。

若该对象没有重写Object类的equals方法,则使用Object类里的equals方法~

扩展:相同的对象有相同的哈希码

TreeSet如何判断两个对象是够相同?

TreeSet调用将要放进TreeSet中的对象的equals方法判断两个对象是够相同。

若该对象没有重写Object类的equals方法,则使用Object类里的equals方法~

总结:

1、凡是自定义类的对象要判断相等,则必须重写 equals()方法,为其提供判断的条件。

2、当容器由HashSet来构建,且用来存放自定义类的对象时,则要求该类必须重写hashCode()和equals()两个方法。

源码示例1:向HashSet中放入相同学生信息,操作失败,放入不同的学生信息,操作成功

package com.collection.demo;

import java.util.*;

class Student {
    //属性
    String name;
    boolean sex;
    int score;

    //构造器
    public Student() {
    }

    public Student(String name, boolean sex, int score) {
        this.name = name;
        this.sex = sex;
        this.score = score;
    }

    //设定器
    public void setName(String name) {
        this.name = name;
    }

    public void setSex(boolean sex) {
        this.sex = sex;
    }

    public void setScore(int score) {
        this.score = score;
    }

    //访问器
    public String getName() {
        return name;
    }

    public boolean isSex() {
        return sex;
    }

    public int getScore() {
        return score;
    }

    //功能方法
    @Override
    public int hashCode() {//重写了hashCode生成方式
        return (name + "").hashCode() + (sex + "").hashCode() + score;
    }

    @Override
    public boolean equals(Object obj) {//重写了要放入HashSet中的对象的equals方法
        Student student = (Student) obj;
        if (this.name.equals(student.name) && this.sex == student.sex && this.score == student.score)
            return true;
        return false;
    }

    @Override
    public String toString() {//重写了打印对象的方法
        return "姓名:" + name + "	性别:" + (sex ? "男" : "女") + "	分数:" + score;
    }
}

public class HashSetTest {
    public static void main(String[] args) {
        Collection<Student> set = new HashSet<Student>();
        Student student01 = new Student("张三", true, 80);
        Student student02 = new Student("张三", true, 80);
        Student student03 = new Student("张三", true, 85);
        Student student04 = new Student("李四", true, 90);
        Student student05 = new Student("李四", false, 90);
        Student student06 = new Student("王五", false, 95);
        set.add(student01);
        set.add(student02);
        set.add(student03);
        set.add(student04);
        set.add(student05);
        set.add(student06);
        for (Student student : set) {
            System.out.println(student);//显示所有在HashSet里的学生的信息
        }
        System.out.println(set.size());//5个
    }
}

排序技术

TreeSet如何实现两个对象的排序?

TreeSet对添加进来的元素自动排序。这句话有2个前提,

第1:元素能够添加进来    第2:元素能够被排序

第1点可以使用屏蔽技术

第2点则要求对于我们自定义的对象,对象必须实现java.lang.Comparable接口,从而能够被排序

既然实现了接口,那么接口中的抽象方法compareTo(),肯定要被即将放进TreeSet中的对象重写

判断元素相等依赖: compareTo()方法

因此,在重写compareTo()方法时,要求必须将对象的所有属性一一比较大小。

排序总结:

凡是对象比较大小就用 compareTo()方法,若对象是自定义类的对象,则该类必须实现Comparable接口,重写compareTo()方法。

源码示例2:向TreeSet中放入学生信息,并根据分数进行排序

package com.collection.demo;

import java.util.*;

class Student implements Comparable<Student> {
    //属性
    String name;
    boolean sex;
    int score;

    //构造器
    public Student() {
    }

    public Student(String name, boolean sex, int score) {
        this.name = name;
        this.sex = sex;
        this.score = score;
    }

    //设定器
    public void setName(String name) {
        this.name = name;
    }

    public void setSex(boolean sex) {
        this.sex = sex;
    }

    public void setScore(int score) {
        this.score = score;
    }

    //访问器
    public String getName() {
        return name;
    }

    public boolean isSex() {
        return sex;
    }

    public int getScore() {
        return score;
    }

    //功能方法

    @Override
    public boolean equals(Object obj) {//重写了要放入TreeSet中的对象的equals方法
        Student student = (Student) obj;
        if (this.name.equals(student.name) && this.sex == student.sex && this.score == student.score)
            return true;
        return false;
    }

    @Override
    public String toString() {//重写了打印对象的方法
        return "姓名:" + name + "	性别:" + (sex ? "男" : "女") + "	分数:" + score;
    }

    @Override
    public int compareTo(Student student) {
        if (this.score - student.score != 0) {//优先按分数排序
            return this.score - student.score;
        } else if ((this.sex + "").compareTo(student.sex + "") != 0) {//分数相同,按性别排序
            return (this.sex + "").compareTo(student.sex + "");
        } else {//性别相同,按姓名排序
            return this.name.compareTo(student.name);
        }
    }
}

public class TreeSetTest {
    public static void main(String[] args) {
        //由于此容器会将元素按大小自动排序。因此,放进去的元素必须实现了 Comparable接口。否则,异常。
        Collection<Student> set = new TreeSet<Student>();
        Student student01 = new Student("张三", true, 80);
        Student student02 = new Student("张三", true, 80);//放不进Set
        Student student03 = new Student("张三", true, 85);
        Student student04 = new Student("李四", true, 90);
        Student student05 = new Student("李四", false, 90);
        Student student06 = new Student("王五", false, 95);
        set.add(student01);
        set.add(student02);
        set.add(student03);
        set.add(student04);
        set.add(student05);
        set.add(student06);
        for (Student student : set) {
            System.out.println(student);//显示所有在TreeSet里的学生的信息,自动按分数排序
        }
        System.out.println(set.size());//5个
    }
}

 注意(再次小结):

1、

凡是自定义类的对象要判断相等,则必须重写 equals()方法,为其提供判断的条件。

此条适用范围不仅仅是HashSet啊,而是所有容器哈~

2、

使用HashSet(HashMap)接口来构建容器时,只有在存放我们自定义类的对象(学生)时,才要求重写equals()和hashCode()两个方法。

若里面存放的是String类、包装类等已经写好的类对象室,不用重写equals()和hashCode(),砖家替我们写好了

直接拿来使用就好,这也是Java的设计思想:简单 易用 实用,这也是Java体系发展迅速的原因~

好了,Set接口告一段落~

List接口,好简单的~

简单提一下:

ArrayList 有序 可重复 采用数组结构 长度需要变化时 每次增加50% 存储空间连续 查询和修改快 增加和删除慢

LinkedList 有序 可重复 采用双向链表结构 长度...不固定好吧~  存款空间不连续 查询慢 增加、删除快(呵呵,其实你感觉不到~)

再说说它们的区别:

ArrayList和LinkedList在作为List接口使用的时候,主要区别就是随机访问(按照index进行查找删除等等操作)效率,

ArrayList的随机访问效率当然会高;如果你的程序很少应用随机访问,那使用LinkedList不会是比ArrayList更差的选择。

ArrayList最没有效率的地方就是频繁的添加操作,这个操作可能会引起ArrayList的扩容,

扩容的时候会copy数组浪费点时间,而LinkedList没有扩容时的问题。

还有就是LinkedList实现了Deque接口,如果我们需要队列操作,那声明LinkedList的实现为Deque类型是非常方便的,

然后ArrayList没有实现这个接口。


好了,然后是Map接口了~

----------------------------------Map接口----------------------------------

直接上代码了~ 很多东西和Set相似~

import java.util.Map;
import java.util.HashMap;

//Map 使用覆盖技术,Set使用屏蔽技术
//HashMap 先判断hashCode是否相同,再根据equals()判断键对象是否相同,
//相同则覆盖已经存在的该键对应的值,不相同就在HashMap里新建一对键值
//判断元素相等实质上只判断元素的键是否相等,当键相等时,则元素相等
public class hashMapTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Map<Student, String> map = new HashMap<Student, String>();
        map.put(new Student("张三", 9527), "男");
        map.put(new Student("李四", 9528), "男");
        map.put(new Student("王五", 9529), "男");
        System.out.println(map);
        map.put(new Student("张三", 9527), "男");
        System.out.println();
        System.out.println(map);
        map.put(new Student("张三", 9527), "女");
        System.out.println();
        System.out.println(map);
        map.put(new Student("张三", 9530), "女");
        System.out.println();
        System.out.println(map);// 体会每次打印结果,多做练习(覆盖技术)
    }

}

class Student {
    private String name;
    private int id;

    public Student() {
        // TODO Auto-generated constructor stub
    }

    public Student(String name, int id) {
        super();
        this.name = name;
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        // 此处的代码请参考Set案例里的
        return super.equals(obj);
    }

    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        // 此处的代码请参考Set案例里的
        return super.hashCode();
    }

    @Override
    public String toString() {
        // TODO Auto-generated method stub
        // 此处的代码请参考Set案例里的
        return super.toString();
    }
}

----------------------------------Iterator迭代器---------------------------------- 

import java.util.*;

//Iterator的使用方法
class Students2 implements Comparable<Students2> {
    //个性
    private String name;
    private int id;

    //构造器
    public Students2(String name, int id) {
        super();
        this.name = name;
        this.id = id;
    }

    //设定器、访问器
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    //功能代码
    @Override
    public int compareTo(Students2 o) {
        if (this.id > o.id) {
            return 1;
        } else if (this.id < o.id) {
            return -1;
        } else {
            return 0;
        }
    }

}

public class MyIterator {
    public static void main(String[] args) {
        Set<Students2> set = new TreeSet<Students2>();
        set.add(new Students2("刘德华", 9528));
        set.add(new Students2("李连杰", 9527));
        set.add(new Students2("加菲猫", 9529));
        set.add(new Students2("加菲猫", 9529));
        Iterator<Students2> iterator = set.iterator();//迭代器的使用
        while (iterator.hasNext()) {//迭代器的使用
            Students2 students = (Students2) iterator.next();//迭代器的使用
            System.out.println("姓名" + students.getName() + "	编号:" + students.getId());

        }
    }
}

 补充:

===========================

使用Comparator<T>实现排序
第一步:有不可更改的实体类
public class Goods {
   private  String  gid;
   private  String  gname;
   private  float  gprice;

   public String getGid() {
      return gid;
    }
    
    public void setGid(String gid) {
        this.gid = gid;
    }
    
    public String getGname() {
        return gname;
    }
    
    public void setGname(String gname) {
        this.gname = gname;
    }
    
    public float getGprice() {
        return gprice;
    }
    
    public void setGprice(float gprice) {
        this.gprice = gprice;
    }


   public Goods(String gid, String gname, float gprice) {
    this.gid = gid;
    this.gname = gname;
    this.gprice = gprice;
  }
  
}

第二步:自定义类实现Comparator<T>接口
public class MyGoods  implements Comparator<Goods>{

    @Override
    public int compare(Goods o1, Goods o2) {
        // TODO Auto-generated method stub
        float f=o1.getGprice()-o2.getGprice();
        if(f>0)
        {
            return 1;
        }
        if(f<0)
        {
            return -1;
        }
        return 0;
    }

}
第三步:
    public static void main(String[] args) 
    {
                 //生成自定义的MyGoods对象
         MyGoods  myGoods=new MyGoods();
                 //使用重载的构造方法TreeSet(Comparator<? super E> comparator) 
                 Set<Goods>   set = new TreeSet<Goods>(myGoods);
                 set.add(new Goods("g001","book001",212));
                 set.add(new Goods("g002","book002",100));
                 set.add(new Goods("g003","book003",913));
                 for(Goods g:set)
                 {
                 System.out.println(g.getGprice());
                 }
    }
原文地址:https://www.cnblogs.com/qixiawentang/p/5466582.html