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接口。



  • 相关阅读:
    【转载】SAP_ECC6.0_EHP4或SAP_ECC6.0_EHP5_基于Windows_Server_2008R2_和SQL_server_2008下的安装
    使用delphi 开发多层应用(二十四)KbmMW 的消息方式和创建WIB节点
    使用delphi 开发多层应用(二十三)KbmMW 的WIB
    实现KbmMw web server 支持https
    KbmMW 服务器架构简介
    Devexpress VCL Build v2014 vol 14.1.1 beta发布
    使用delphi 开发多层应用(二十二)使用kbmMW 的认证管理器
    KbmMW 4.50.00 测试版发布
    Basic4android v3.80 beta 发布
    KbmMW 认证管理器说明(转载)
  • 原文地址:https://www.cnblogs.com/edda/p/12600249.html
Copyright © 2011-2022 走看看