zoukankan      html  css  js  c++  java
  • Java核心技术及面试指南 线性表方面的面试题总结以及答案

    3.2.7.1 请用ArrayList实现Stack以及Queue的功能。

     
    public class ArrayListStack extends ArrayList implements Stack {
        ArrayList arrayList =new ArrayList<>() ;
        public void push(T obj) {
           arrayList.add(obj);
        }
        public T pop() {
            return arrayList.remove(arrayList.size()-1);
        }

        public int size(){

            return arrayList.size(); 

        }
    }

    3.2.7.2 如果让你实现Java的ArrayList,你需要考虑哪些要素?

        ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。 

        ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。

       每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。 
       注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步。

         ArrayList提供了三种方式的构造器,可以构造一个默认初始容量为10的空列表、构造一个指定初始容量的空列表以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。

        ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection<? extends E> c)、addAll(int index, Collection<? extends E> c)这些添加元素的方法。

        每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,如果超出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。在实际添加大量元素前,我也可以使用ensureCapacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。

        数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。 

        Fail-Fast机制: 
    ArrayList也采用了快速失败的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

    3.2.7.3 请通过Iterator对象访问LinkedList对象,并说明这种访问方式的好处。

      LinkedList  list =  new LinkedList();

      //省略赋值
      ListIterator it = list.listIterator();
      while(it.hasNext()) { 
       System.out.println(it.next().toString()); //使用  
      }

      好处是,能用统一的方式来访问集合对象,这也是迭代器模式的好处。

    3.2.7.4 你有没有读过ArrayList部分的底层实现源代码?如果有,请说明下其中的add方法是如何实现的?尤其请考虑动态扩展的情况。

    如下是扩容的底层方法

    /**
    * 增加ArrayList容量。
    *
    * @param minCapacity 想要的最小容量
    */
    public void ensureCapacity(int minCapacity) {
        // 如果elementData等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,最小扩容量为DEFAULT_CAPACITY,否则为0
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)? 0: DEFAULT_CAPACITY;
        //如果想要的最小容量大于最小扩容量,则使用想要的最小容量。
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
    /**
    * 数组容量检查,不够时则进行扩容,只供类内部使用。
    *
    * @param minCapacity 想要的最小容量
    */
    private void ensureCapacityInternal(int minCapacity) {
        // 若elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则取minCapacity为DEFAULT_CAPACITY和参数minCapacity    之间的最大值
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }
    /**
    * 数组容量检查,不够时则进行扩容,只供类内部使用
    *
    * @param minCapacity 想要的最小容量
    */
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // 确保指定的最小容量 > 数组缓冲区当前的长度
        if (minCapacity - elementData.length > 0)
        //扩容
        grow(minCapacity);
    }

    /**
    * 分派给arrays的最大容量
    * 为什么要减去8呢?
    * 因为某些VM会在数组中保留一些头字,尝试分配这个最大存储容量,可能会导致array容量大于VM的limit,最终导致OutOfMemoryError。
    */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
    * 扩容,保证ArrayList至少能存储minCapacity个元素
    * 第一次扩容,逻辑为newCapacity = oldCapacity + (oldCapacity >> 1);即在原有的容量基础上增加一半。第一次扩容后,如果容量还是小于minCapacity,就将容量扩充为minCapacity。
    *
    * @param minCapacity 想要的最小容量
    */
    private void grow(int minCapacity) {
        // 获取当前数组的容量
        int oldCapacity = elementData.length;
        // 扩容。新的容量=当前容量+当前容量/2.即将当前容量增加一半。
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果扩容后的容量还是小于想要的最小容量
        if (newCapacity - minCapacity < 0)
            //将扩容后的容量再次扩容为想要的最小容量
            newCapacity = minCapacity;
        //如果扩容后的容量大于临界值,则进行大容量分配
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
         // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData,newCapacity);
    }
    /**
    * 进行大容量分配
    */
    private static int hugeCapacity(int minCapacity) {
        //如果minCapacity<0,抛出异常
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        //如果想要的容量大于MAX_ARRAY_SIZE,则分配Integer.MAX_VALUE,否则分配MAX_ARRAY_SIZE
        return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
    }

    3.2.7.5 请说下Collection和Collections的差别以及各自的用途。

        Collections 是一个集合的一个类,其中包含有一些和集合操作相关的静态多态方法。Jave集合里则有另外一个和它非常相似的接口    

        Collection(不带s),它是线性表类集合的父接口,List和Set等接口都是通过实现这个接口来实现的。

    3.2.7.6 我们知道Set对象里不能有重复的元素,请说下是用什么方法来判断是否重复?是通过equals方法吗?

        请参与本书3.2.3 Set集合是如何判断重复,里面有详细的描述

  • 相关阅读:
    【k8s】deploy-progressDeadlineSeconds
    【k8s】deploy-paused
    【k8s】deploy-rollback
    【k8s】deploy-rollout
    【k8s】deploy-pod-template-hash
    【k8s】deploy-rs
    【k8s】deploy-metadata
    垂直居中总结
    linux操作系统的知识点复盘
    JMETER接口测试学习知识点复盘
  • 原文地址:https://www.cnblogs.com/JavaArchitect/p/8495834.html
Copyright © 2011-2022 走看看