java知识点(3)

10.HashMap的实现原理?

    HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。”HashMap是在bucket中储存键对象和值对象,作为Map.Entry。这一点有助于理解获取对象的逻辑。如果你没有意识到这一点,或者错误的认为仅仅只在bucket中存储值的话,你将不会回答如何从HashMap中获取对象的逻辑。

    HashMap其实是一个线性的数组实现的,可以理解为其存储的容器就是一个线性数组。HashMap里面实现一个静态内部类Entry,其重要的属性有key,value,next,Entry就是HashMap键值对实现的一个基础bean,Map里面的内容都保存在Entry[]里面。

    10.1HashMap同步语句:Map m = Collections.synchronizeMap(hashMap);

    10.2什么是HashSet?

    HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。

    10.3.为什么HashMap是线程不安全的,实际会如何体现?   

    第一,如果多个线程同时使用put方法添加元素,假设正好存在两个put的key发生了碰撞(hash值一样),那么根据HashMap的实现,这两个key会添加到数组的同一个位置,这样最终就会发生其中一个线程的put的数据被覆盖。

    第二,如果多个线程同时检测到元素个数超过数组大小*loadFactor,这样会发生多个线程同时对hash数组进行扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给table,也就是说其他线程的都会丢失,并且各自线程put的数据也丢失。且会引起死循环的错误。

    10.4如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?

    默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。

    10.5 ConcurrentHashMap通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。

 

11.海量数据,如何找到第K小的数?

    k数比较小时    构造一个大堆,也就是堆节点最大值在根节点。查找到第k小的元素,k的值是确定的,可以构造一个含有k个元素的大堆,当有新的元素过来时,从大堆的根节点获得最大值,如果新来元素的值比根节点小,那么我们将根节点从堆中去掉,将新节点插入到堆中,如果新来的元素大于根节点,那么就直接忽略掉新元素,于是我们就可以始终保持所遇到的所有元素中排序在前k位的值,最后所有元素的访问走完后,从堆的根节点处就可以得到海量数据元素中第k小的值了。 整个算法的时间复杂度是O(n*lg(k))。

    100w个数中找出最大的100个数

    思路1:最小堆,找最大100个数

    思路2:快速排序,每次分割之后只考虑比轴大的一部分,直到比轴大的一部分比100多时,采用传统排序,取前100个

    思路3:选取前100个元素,排序,然后扫描剩余的元素,与排好序的元素中最小的相比,如果比它大,替换,重排前面,跟堆排序思路一样。

    Hash法。 如果大量数据中有很多重复的数,先通过hash法,把数据去重,这样会减少很大的内存用量,然后通过分治法或最小堆法查找最大的k个数。

    分治法。 将1亿个数据分成100份,每份100万个数据,找到每份中最大的K个,最后把剩下的100*K个数据里面找出最大的K个。100*K个数据中找最大的K个数据方法如下:用快速排序的方法,将数据分为2堆,如果大的那堆个数N大于K个,继续对大堆快速排序一次分为2堆,直到大堆个数N小于K,就在小的那堆里面快速排序一次,找第K-n大的数字,递归以上过程,就可以找到第K大的数。

12.分布式处理

Hadoop

MapReduce

HDFS

13.在定义Java类时,如果没有定义父类,默认都会去继承Object类

在Object类中,常用的方法,如getClass(),toString()和equals()方法,

(1)对于getClass()来说,它可以在运行时获得类。

(2)equals()通常用来进行比较,在Object类中,它进行了引用的比较,只有引用相同时会返回true。

字符串的比较,进行几次判断:1.首先判断引用相同,如果相同则返回true;2.判断传入的对象是否为String,如果不是String,则直接返回false;3.比较字符串的长度,如果两个字符串的长度不一样,也就不用比较了;4.上面的都相同时,则进行逐字符的比较。

(3)toSting()默认在Object类中输出当前运行时类和一个HashCode.

(4)clone方法实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。

(5)finalize方法用于释放资源。

(6)hascode方法,该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。

(7)wait方法是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。

调用该方法后当前线程进入睡眠状态,直到以下事件发生。

(1)其他线程调用了该对象的notify方法。(2)其他线程调用了该对象的notifyAll方法。

(3)其他线程调用了interrupt中断该线程。(4)时间间隔到了。

此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
(8)notify方法用于唤醒在该对象上等待的某个线程。

(9)notifyAll方法用于huan唤醒在该对象上等待的所有线程。

Object的直接子类:Boolean,Character,Character.Subset,Class,ClassLoader,Compiler,Enum,Math,Number,Package,Permission,Process,PfocessBuilder,Runtime,SecurityManager,StackTraceElement,StrictMath,String

StringBuffer,StringBuilder,System,Thread,ThreadGroup,ThreadLocal,Throwable,Void

14.Java常见异常种类

14.1 error

14.2 Runtime Exception运行时异常

14.3 Exception

14.4 throw用户自定义异常

 异常类分两个类型:Error类代表编译和系统的错误,不允许捕获;Exception类代表标准Java类方法所激发的异常。Exception类还包括运行异常类Runtime_Exception和非运行异常类Non_Runtime_Exception这两个直接子类。

  运行异常对应于编译错误,它指Java程序在运行时产生的由解析器引发的各种异常。运行异常可能会出现在任何地方,且出现频率很高,为避免巨大的系统资源开销,编译器不对异常进行检查。java语言中的运行异常不一定被捕获。出现运行错误往往表示代码有错误。

  非运行时异常是Non_Runtime_Exception类及其子类的实例,称为可检测异常。Java编译器利用分析方法或构造方法中可能产生的结果来检测Java程序中是否含有检测异常的处理程序,对于每个可能的可检测异常,方法或构造方法的throws子句必须列出该异常对应的类。在Java的标准包java.lang java.util和java.net中定义的异常都是非运行时异常。

发布了36 篇原创文章 · 获赞 19 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_27182767/article/details/79705272