java教程

Java面试题相关---集合

位置:首页 > java教程 > java技巧,2017-10-07 01:35
Collection |--List |--ArrayList |--Vector
Collection  
        |--List
            |--ArrayList
            |--Vector
            |--LinkedList
        |--Set
            |--HashSet
            |--TreeSet

集合和数组的区别

A:长度区别

  • 数组的长度固定
  • 集合长度可变

B:内容不同

  • 数组存储的是同一种类型的元素
  • 而集合可以存储不同类型的元素

C:元素的数据类型问题

  • 数组可以存储基本数据类型,也可以存储引用数据类型
  • 集合只能存储引用类型

数组有没有length()方法,字符串有没有length()方法。集合有没有length()方法;

没有,有,没有

迭代器集合的专门遍历方式

Iterator iterator():迭代器,集合的专用遍历方式

while (it.hasNext()) {
         System.out.println(it.next());
    }

用for循环改写效率高,因为用Iterator之后就是垃圾了。
for(Iterator it;it.hasNext();){
System.out.println(it.next());
}

迭代器为什么是接口,而不是一个类。

假设迭代器定义的是一个类,这样我们就可以创建该类的对象,调用该类的方法来实现集合的遍历。

由于Java提供了很多的集合类,而这些集合类的数据结构是不同的。所以,存储的方式和遍历的方式应该是不同的。进而遍历方式也应该不一样,最终没有定义迭代器类的。

而无论你是哪种集合,你都应该具备获取元素的操作,并且,最好在辅助于判断功能,这样,在获取前,先判断,这样就更不容易出错,也就是说,判断功能和获取功能应该是一个集合遍历所具备的,而每种集合的方式又不太一样,所以我们把这两个功能给提取出来,并不提供具体实现,这种方式就是接口。

那么,真正的具体的实现类在哪里呢?
在真正的具体的子类中,以内部类的方式体现的。
(增强for就是用来替代迭代器的)

List集合

  • 有序:进去的时候是什么顺序出去也是什么顺序(并不是排序)
  • 允许重复的元素;

list集合的特有遍历功能

size()方法和get()方法结合使用用for循环

list集合的特有迭代器列表迭代器listIterator

listIterator继承于Iterator接口

  • 特有功能1 previous().往回走。获取前一个元素
    1. hasPrevious(),判断是否有元素
  • 3.add()将指定元素添加。如果我们用Iterator去添加元素会出现并发修改异常。

数组

存储同一种类型的多个元素的容器,有索引,方便我们获取。
查询快,增删慢

链表

由一个链子把多个结点连起组成的数据
结点:有数据和地址组成(数据域和指针域组成)
查询慢,增删快

List子类的特点

  • ArrayList:
    底层数据结构是数组,查询快,增删慢。
    线程不安全,效率高
  • Vector:
    底层数据结构是数组,查询快,增删慢。
    线程安全,效率低
  • LinkedList:
    底层数据结构是链表,查询慢,增删快。
    线程不安全,效率高

Vector的特有功能

因为Vector是1.0出现,在1.2版本才加入到list集合中,所以它有自己的特有功能。
addElement---add
elementAt----get
elements----iterator
JDK升级的原因:A,安全。B.效率。C.简化书写

LinkedList的特有功能

A:addFirst()/addLast()
B:getFirst()/getLast()
C:removeFirst()/removeLast()

contains()

contains()方法的底层是依赖equals()方法。当我们比较一个集合是否包含另一个集合的时候如果存储的对象没有重写equals方法时,它就默认用的Object类中的方法,比较的是地址值。

asList(T...a)把数组转换成集合

其本质还是数组,所以长度不能改变。集合的增加,删除就会报错。修改则可以。

Set

无序:存储顺序和取出顺序不一致,(虽然)

唯一

HashSet

它不保证set的迭代顺序,特别是不保证该顺序恒久不变。

底层是HashMap保证hashset唯一,因为调用add就是hashmap的put()方法
通过add方法的源码我们可以知道底层依赖的判断两个方法就是:hashCode()和equals()

  • 步骤:
    • 首先比较哈希值:如果相同继续走,比较地址值或者走equals()
    • 如果不同:就直接添加到集合中

      如果类中没有重写这两个方法,默认使用的是Object(),一般来说不同
      而String类重写了这两个方法,所以内容相同就添加不进去。只添加一个

哈希表

是一个元素为链表的数组。综合了数组和链表的好处。(好比如新华字典)

LinkedHahSet

底层数据结构由哈希表和链表组成。哈希表保证元素唯一性,链表保证元素有序(存储和取出一致)
具有可预知的迭代顺序

TreeSet

能够对元素按照某种规则进行排序(自然排序,比较器排序)
特点:排序和唯一

  • 唯一性:根据比较的返回是否是0来决定
  • 排序:

    • 自然排序(元素具备比较性):让元素所属的类实现自然排序的接口Comparable
    • 比较器排序(集合具备比较性):让集合的构造方法比较器接口的子类对象Comparator
      底层数据结构是红黑树(红黑树是一种自平衡的二叉树)保证元素的排序和唯一性。

      自然排序

      如果一个类的元素要想能够进行自然排序,就必须实现自然排序接口Comparable<Student>,重写方法

      //按照姓名的长度排序
      @Override
      public int compareTo(Student s) {

      // 主要条件 姓名的长度
      int num = this.name.length() - s.name.length();
      // 姓名的长度相同,不代表姓名的内容相同
      int num2 = num == 0 ? this.name.compareTo(s.name) : num;
      // 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄
      int num3 = num2 == 0 ? this.age - s.age : num2;
      return num3;

      }

比较器排序

第二个构造器需要我们传入一个参数就是比较器对象,自定义一个类重写方法:

new Comparator<Student>() {
        @Override
        public int compare(Student s1, Student s2) {
            // 姓名长度
            int num = s1.getName().length() - s2.getName().length();
            // 姓名内容
            int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
                    : num;
            // 年龄
            int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
            return num3;
        }
    }

Map

将键映射到值得对象,一个映射不能包含重复的键,每个键最多只能映射到一个值。

  • Map集合的数据结构值针对键有效,跟值无关
  • Collection集合的数据结构是针对元素有效

    map集合的遍历

  • 根据丈夫找妻子

    • 获取所有的键
    • 遍历键的集合,获取每一键
    • 根据去找值

      // 获取所有的键
          Set<String> set = map.keySet();
          // 遍历键的集合,获取得到每一个键
             for (String key : set) {
               // 根据键去找值
               String value = map.get(key);
               System.out.println(key + "---" + value);
           }
  • 根据结婚证找丈夫和妻子

    • 获取所有键值对对象的集合
    • 遍历键值对对象的集合得到每一个键值对对象
    • 根据键值对对象获取键和值
// 获取所有键值对对象的集合
        Set<Map.Entry<String, String>> set = map.entrySet();
        // 遍历键值对对象的集合,得到每一个键值对对象
        for (Map.Entry<String, String> me : set) {
        // 根据键值对对象获取键和值
        String key = me.getKey();
        String value = me.getValue();
        System.out.println(key + "---" + value);
          }

HashMap

键是哈希表结构,可以保证键的唯一性(hashCode()和equals()

LinkedHashMap

Map接口的哈希表和链表列表实现,具有可预知的迭代顺序

  • 哈希表保证唯一性
  • 链表保证有序(存储和取出顺序一致)

TreeMap

  • 键是红黑树结构,可以保证键的排序(默认自然排序)和唯一性.
  • 排序的话如果是自定义对象也得重写Comparable接口,否则会报错

    HashMap和Hashtable(这里的't'是小写)的区别

    Hashtable:线程安全,效率低。不允许null建和null值
    HashMap:线程不安全,效率高,允许null建和null值

Collections接口

是针对集合进行操作的工具类

Collection和Collections的区别

  • :Collection 是单列集合的顶层接口,有两个子接口List和Set
  • :Collections 是针对集合进行操作的工具类,可以对集合进行排序和查找等

总结

  • :集合

    Collection(单列集合)
      List(有序,可重复)
          ArrayList
              底层数据结构是数组,查询快,增删慢
              线程不安全,效率高
          Vector
              底层数据结构是数组,查询快,增删慢
              线程安全,效率低
          LinkedList
              底层数据结构是链表,查询慢,增删快
              线程不安全,效率高
      Set(无序,唯一)
          HashSet
              底层数据结构是哈希表。
              哈希表依赖两个方法:hashCode()和equals()
              执行顺序:
                  首先判断hashCode()值是否相同
                      是:继续执行equals(),看其返回值
                          是true:说明元素重复,不添加
                          是false:就直接添加到集合
                      否:就直接添加到集合
              最终:
                  自动生成hashCode()和equals()即可
    
              LinkedHashSet
                  底层数据结构由链表和哈希表组成。
                  由链表保证元素有序。
                  由哈希表保证元素唯一。
          TreeSet
              底层数据结构是红黑树。(是一种自平衡的二叉树)
              如何保证元素唯一性呢?
                  根据比较的返回值是否是0来决定
              如何保证元素的排序呢?
                  两种方式
                      自然排序(元素具备比较性)
                          让元素所属的类实现Comparable接口
                      比较器排序(集合具备比较性)
                          让集合接收一个Comparator的实现类对象
      Map(双列集合)
      A:Map集合的数据结构仅仅针对键有效,与值无关。
      B:存储的是键值对形式的元素,键唯一,值可重复。
    
      HashMap
          底层数据结构是哈希表。线程不安全,效率高
              哈希表依赖两个方法:hashCode()和equals()
              执行顺序:
                  首先判断hashCode()值是否相同
                      是:继续执行equals(),看其返回值
                          是true:说明元素重复,不添加
                          是false:就直接添加到集合
                      否:就直接添加到集合
              最终:
                  自动生成hashCode()和equals()即可
          LinkedHashMap
              底层数据结构由链表和哈希表组成。
                  由链表保证元素有序。
                  由哈希表保证元素唯一。
      Hashtable
          底层数据结构是哈希表。线程安全,效率低
              哈希表依赖两个方法:hashCode()和equals()
              执行顺序:
                  首先判断hashCode()值是否相同
                      是:继续执行equals(),看其返回值
                          是true:说明元素重复,不添加
                          是false:就直接添加到集合
                      否:就直接添加到集合
              最终:
                  自动生成hashCode()和equals()即可
      TreeMap
          底层数据结构是红黑树。(是一种自平衡的二叉树)
              如何保证元素唯一性呢?
                  根据比较的返回值是否是0来决定
              如何保证元素的排序呢?
                  两种方式
                      自然排序(元素具备比较性)
                          让元素所属的类实现Comparable接口
                      比较器排序(集合具备比较性)
                          让集合接收一个Comparator的实现类对象
  • 到底使用那种集合

是否是键值对象形式:
       是:Map
        键是否需要排序:
            是:TreeMap
            否:HashMap
        不知道,就使用HashMap。

      否:Collection
        元素是否唯一:
            是:Set
                元素是否需要排序:
                    是:TreeSet
                    否:HashSet
                不知道,就使用HashSet

            否:List
                要安全吗:
                    是:Vector(其实我们也不用它,后面我们讲解了多线程以后,我在给你回顾用谁)
                    否:ArrayList或者LinkedList
                        增删多:LinkedList
                        查询多:ArrayList
                    不知道,就使用ArrayList
        不知道,就使用ArrayList
  • 集合的常见方法及遍历方式

    Collection:
      add()
      remove()
      contains()
      iterator()
      size()
    
      遍历:
          增强for
          迭代器
    
      |--List
          get()
    
          遍历:
              普通for
      |--Set
    
      Map:
      put()
      remove()
      containskey(),containsValue()
      keySet()
      get()
      value()
      entrySet()
      size()
    
      遍历:
          根据键找值
          根据键值对对象分别找键和值

TAGS:Java面试题

猜你喜欢

NewHot