zoukankan      html  css  js  c++  java
  • 集合类——Collection、List、Set接口

    集合类

    Java类集

    我们知道数组最大的缺陷就是:长度固定。从jdk1.2开始为了解决数组长度固定的问题,就提供了动态对象数组实现框架——Java类集框架。Java集合类框架其实就是Java针对于数据结构的一种实现。

    Java类集的本质就是动态对象数组。

    Java类集中提供有两个最为核心的接口:Collection和Map接口。

    1、Collection接口

    1)定义:

    public interface Collection<E> extends Iterable<E>

    Collection是单个集合保存的最大接口。

    Collection与写过的链表类似,每一次进行数据操作的时候只能对单个对象进行处理。且从jdk1.5开始追加泛型应用,这样可以避免ClassCastException异常的出现,里面的所有保存数据类型应该相同。

    (2)常用方法

    向集合中添加元素:boolean add(E e)

    向集合中添加一组元素:boolean addAll(Collection<? extends E> c)

    清空集合数据: void clear()

    查找数据是否存在:boolean contains(Object o)

    删除数据:boolean remove(Object o)

    取得集合长度:int size()

    将结合变为对象数组:Object[] toArray()

    取得Iterator接口对象,用于集合输出:Iterator<E> iterator()

    实则Collection接口只是一个存储数据的标准,并不能用来区分存储类型。如:需要区分可存储数据的重复与否。所以我们一般用来使用的是Collection的两个子接口:ListSet

                  

    2、List接口

    public interface List<E> extends Collection<E>

    新增方法:

    根据索引取得保存数据: E get(int index)

    修改数据: E set(int index, E element)

    List接口与Collection接口相比,比其增加了一个get()set()方法,可以通过指定的索引值取得修改、内容。要想取得接口的实例化对象则其必须有子类,在List接口下有三个常用子类:ArrayListVectorLinkedList.

                   

    (1)ArrayList

    public class ArrayList<E> extends AbstractList<E>

    ArrayList是针对于List的数组实现。

    1. package mycollection;
    2. import java.util.*;
    3. public class Test {
    4. public static void main(String[] args) {
    5. //这时候集合中只能存String类型的数据
    6. List<String> list = new ArrayList<>();
    7. list.add("hello");
    8. list.add("world");
    9. //添加重复元素
    10. list.add("hello");
    11. list.add("陕科大");
    12. System.out.println(list);
    13. //返回集合中元素的个数
    14. System.out.println("新增元素后集合长度:"+list.size());
    15. //判断集合是否为空
    16. System.out.println("集合是否为空:"+list.isEmpty());
    17. //判断集合是否包含指定元素(元素存在)
    18. System.out.println("集合中是否包含元素“hello”:"+list.contains("hello"));
    19. //判断集合是否包含指定元素(元素不存在)
    20. System.out.println("集合中是否包含元素“haha”:"+list.contains("haha"));
    21. //取得集合指定位置的元素
    22. System.out.println("下标为2的元素:"+list.get(2));
    23. //修改指定位置的元素
    24. System.out.println("修改下标为3的元素:");
    25. list.set(3, "lemon");
    26. System.out.println("修改元素后将集合中元素转化为数组并打印"+list.toArray());
    27. for (String string : list) {
    28. System.out.print(" "+string);
    29. }
    30. System.out.println();
    31. //清空集合中元素
    32. System.out.println("清空集合:");
    33. list.clear();
    34. System.out.println("清空后集合是否为空:"+list.isEmpty());
    35. }
    36. }

                        

    由上述运行结果我们可以发现List可以存储重复元素。

    get()方法是List子接口提供的,根据指定下标返回元素。若我们要对Collection接口实现此操作,则引用该将其转换为对象数组再进行操作。

    1. //利用Collection实现get()方法
    2. public class Test {
    3. public static void main(String[] args) {
    4. //这时候集合中只能存String类型的数据
    5. Collection<String> list = new ArrayList<>();
    6. list.add("hello");
    7. list.add("world");
    8. //添加重复元素
    9. list.add("hello");
    10. list.add("陕科大");
    11. //操作以Object为主,可能需要向下转型,就会出现ClassCastException异常
    12. Object[] object = list.toArray();
    13. System.out.println(Arrays.toString(object));
    14. System.out.println("下标为2的元素:"+object[2]);
    15. }
    16. }

                              

    (1)Vector

    Vectorjdk1.0提出的,而ArrayListjdk1.2提出的,Vector相对使用较少。

    Vector的使用与ArrayList的使用类似

    1. public class Test {
    2. public static void main(String[] args) {
    3. //这时候集合中只能存String类型的数据
    4. List<String> list = new Vector<>();
    5. list.add("hello");
    6. list.add("world");
    7. //添加重复元素
    8. list.add("hello");
    9. System.out.println(list);
    10. //返回集合中元素的个数
    11. System.out.println("新增元素后集合长度:"+list.size());
    12. //判断集合是否为空
    13. System.out.println("集合是否为空:"+list.isEmpty());
    14. //判断集合是否包含指定元素(元素存在)
    15. System.out.println("集合中是否包含元素“hello”:"+list.contains("hello"));
    16. //判断集合是否包含指定元素(元素不存在)
    17. System.out.println("集合中是否包含元素“haha”:"+list.contains("haha"));
    18. //取得集合指定位置的元素
    19. System.out.println("下标为2的元素:"+list.get(2));
    20. //修改指定位置的元素
    21. System.out.println("修改下标为3的元素:");
    22. list.set(1, "lemon");
    23. System.out.println("修改元素后将集合中元素转化为数组并打印"+list.toArray());
    24. for (String string : list) {
    25. System.out.print(" "+string);
    26. }
    27. System.out.println();
    28. //清空集合中元素
    29. System.out.println("清空集合:");
    30. list.clear();
    31. System.out.println("清空后集合是否为空:"+list.isEmpty());
    32. }
    33. }

    ArrayListVector的区别:

    A. 时间上:Vectorjdk1.0提供的;而ArrayListjdk1.5提供的。

    B. 处理形式:Vector是同步处理,性能较低;而ArrayList是异步处理,性能相对高。

    C. 数据安全:Vector是线程安全的;而ArrayList是非线程安全的。

    D. 输出形式:Vector支持Iterator、ListIterator、 foreach、Enumeration输出;而ArrayList支持Iterator、ListIterator、foreach输出。

    (2)LinkedList

    若还是利用子类向父类转型来使用的话,LinkedList的使用和前面两者也没什么区别。

    ArrayListLinkedList的区别:

    观察ArrayList的源码,可以发现ArrayList里面存放的是一个数组,如果实例化此对象时传入了数组的大小,则里面保存的数组就会开辟一个定长的数组,但是后续中再进行数据保存,若该长度不够使用则会对数组进行动态扩充。所以我们在使用ArrayList时最好对其设置初始化大小。

    LinkedList就是一个纯粹的链表实现,除性能高外与我们编写的链表没有什么区别。

    ArrayList封装的是数组,而LinkedList封装的是链表。进行查找时ArrayList的时间复杂度为1,而LinkedList的时间复杂度为n

    3、Set接口

    List接口相比SetSet中的内容是不允许重复的,且没有对Collection接口再进行方法的扩充。所以Set中没有get()方法。

    Set接口中提供与两个常用子类:HashSet(无需存储)和TreeSet(有序存储)。

                          

    1. public class Test{
    2. public static void main(String[] args) {
    3. //Set<Integer> set = new HashSet<>();
    4. Set<Integer> set = new TreeSet<>();
    5. set.add(20);
    6. set.add(6);
    7. set.add(15);
    8. set.add(-3);
    9. set.add(20);
    10. //添加重复元素
    11. System.out.println(set);
    12. }
    13. }

    HashSet运行后结果                TreeSet运行后结果

                                          

    由此我们可以看出HashSet是对集合进行无需存储,而TreeSet则对集合进行有序存储(采用升序模式进行排列)。

    (1)TreeSet中排序的分析

    因此我们对TreeSet的排序来进行分析:

        由于TreeSet可以进行排序操作,所以我们可以来实现数据的排序处理。此时进行的排序实际是针对对象数组进行的排序处理,而如果要对对象数组进行排序,则对象所在的类要实现Comparable接口并且要覆写compareTo()方法(要利用Comparable接口进行大小关系比较时必须要对所有的属性进行比较操作)


    1. //自定义类
    2. class Person implements Comparable<Person>{
    3. private String name;
    4. private Integer age;
    5. @Override
    6. public String toString() {
    7. return "Person [name=" + name + ", age=" + age + "]";
    8. }
    9. Person(String name, Integer age) {
    10. super();
    11. this.name = name;
    12. this.age = age;
    13. }
    14. public String getName() {
    15. return name;
    16. }
    17. public void setName(String name) {
    18. this.name = name;
    19. }
    20. public Integer getAge() {
    21. return age;
    22. }
    23. public void setAge(Integer age) {
    24. this.age = age;
    25. }
    26. @Override
    27. public int compareTo(Person o) {
    28. if(this.age > o.age) {
    29. return 1;
    30. }else if(this.age < o.age) {
    31. return -1;
    32. }else {
    33. return this.name.compareTo(o.name);
    34. }
    35. }
    36. }
    37. public class Test{
    38. public static void main(String[] args) {
    39. Set<Person> set = new TreeSet<>();
    40. set.add(new Person("lemon",20));
    41. set.add(new Person("demon", 20));
    42. set.add(new Person("lemon",20));
    43. System.out.println(set);
    44. }
    45. }

    这样一个一个属性进行比较的操作过于麻烦,所以一般情况下我们都使用HashSet

    (2)重复元素的判断在使用TreeSet子类进行数据保存时。重复元素的判断依靠Comparable接口来实现。但是这并不是全部Set接口判断元素重复的方式,因为如果使用的是HashSet子类,因为其和Comparable没有任何关系,所以它判断重复要依靠Object类的两个方法:

    hash码: public native int hashCode();

    对象比较:public boolean equals(Object obj);

    Java中进行对象比较的操作有两个步骤:第一步要通过一个对象的唯一编码找到一个对象的信息,当编码匹配之后再进行下一步操作利用equals()方法进行内容比较。

    1. /*
    2. * 标识对象的唯一性
    3. * */
    4. //自定义类
    5. class Person implements Comparable<Person>{
    6. private String name;
    7. private Integer age;
    8. @Override
    9. public String toString() {
    10. return "Person [name=" + name + ", age=" + age + "]";
    11. }
    12. Person(String name, Integer age) {
    13. super();
    14. this.name = name;
    15. this.age = age;
    16. }
    17. public String getName() {
    18. return name;
    19. }
    20. public void setName(String name) {
    21. this.name = name;
    22. }
    23. public Integer getAge() {
    24. return age;
    25. }
    26. public void setAge(Integer age) {
    27. this.age = age;
    28. }
    29. public int compareTo(Person o) {
    30. if(this.age > o.age) {
    31. return 1;
    32. }else if(this.age < o.age) {
    33. return -1;
    34. }else {
    35. return this.name.compareTo(o.name);
    36. }
    37. }
    38. @Override
    39. public int hashCode() {
    40. return Objects.hash(name,age);
    41. }
    42. @Override
    43. public boolean equals(Object obj) {
    44. if(this == obj) {
    45. return true;
    46. }
    47. if(obj == null|| getClass()!=obj.getClass()) {
    48. return false;
    49. }
    50. Person person = (Person) obj;
    51. return Objects.equals(name,person.name)
    52. && Objects.equals(age,person.age);
    53. }
    54. }
    55. public class Test{
    56. public static void main(String[] args) {
    57. Set<Person> set = new HashSet<>();
    58. set.add(new Person("lemon",20));
    59. set.add(new Person("lemon",20));
    60. set.add(new Person("demon", 18));
    61. System.out.println(set);
    62. }
    63. }

    不覆写hashCode()equals()方法或只覆写一个运行结果:


    两个方法覆写后运行结果:

    所以想要标识出对象的唯一性,则必须覆写hashCode()equals()两个方法。

    如果两个对象的hashCode()相同,equals()不同;或两个对象的equals()相同,而hashCode()不同时,这两个对象都是不能消除。而只有当两个对象的hashCode()equals()都相同时,这两个对象才能判定为同一对象,即相同。

    所以在保存自定义类信息时,建议使用List接口。而保存系统类信息时,建议使用Set接口。



  • 相关阅读:
    Android周学习Step By Step(6)Android的数据库SQLite
    Android周学习Step By Step(2)HelloWorld
    解决方案(.sln)文件
    浅谈测试(1)单元测试
    批量上传功能的实现
    分页控件AspNetPager的用法
    .net下验证码的简单实现
    window.alert重写实现友好的对话框(支持IE)
    网页上自定义运行和测试HTML脚本
    数据库行转列的sql语句(zt)
  • 原文地址:https://www.cnblogs.com/edda/p/12600249.html
Copyright © 2011-2022 走看看